diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a937f5e..79381d14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ Planned: April 2025 ### Features +* Event handling: replace `select` with `poll` + * See [Support more than 100 devices](https://github.com/clicon/clixon-controller/issues/174) * Added new `ca_userdef` callback * New `clixon-restconf@2025-02-01.yang` revision * Added timeout parameter diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c index f3a2dafb..f2af11a6 100644 --- a/apps/backend/backend_client.c +++ b/apps/backend/backend_client.c @@ -1631,7 +1631,7 @@ from_client_process_control(clixon_handle h, * @retval -1 Error */ static int -from_client_hello(clixon_handle h, +from_client_hello(clixon_handle h, cxobj *x, struct client_entry *ce, cbuf *cbret) diff --git a/configure b/configure index 171b8afd..9110ed39 100755 --- a/configure +++ b/configure @@ -777,7 +777,6 @@ with_yang_standard_dir with_clicon_user with_clicon_group enable_nls -enable_event_poll ' ac_precious_vars='build_alias host_alias @@ -1424,7 +1423,6 @@ Optional Features: http/1 only --enable-netsnmp Enable net-snmp Clixon YANG mapping - --enable-event-poll Enable event polling feature Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] @@ -6249,18 +6247,6 @@ fi test "x$prefix" = xNONE && prefix=$ac_default_prefix -# Check whether --enable-event-poll was given. -if test ${enable_event_poll+y} -then : - enableval=$enable_event_poll; if test "$enable_event_poll" = "yes"; then - -printf "%s\n" "#define CLIXON_EVENT_POLL 1" >>confdefs.h - - fi - -fi - - ac_config_files="$ac_config_files Makefile lib/Makefile lib/src/Makefile lib/clixon/Makefile apps/Makefile apps/cli/Makefile apps/backend/Makefile apps/netconf/Makefile apps/restconf/Makefile apps/snmp/Makefile include/Makefile etc/Makefile etc/clixonrc example/Makefile example/main/Makefile example/main/example.xml docker/Makefile docker/clixon-dev/Makefile docker/example/Makefile docker/test/Makefile yang/Makefile yang/clixon/Makefile yang/mandatory/Makefile doc/Makefile test/Makefile test/config.sh test/cicd/Makefile test/vagrant/Makefile" cat >confcache <<\_ACEOF diff --git a/configure.ac b/configure.ac index 2a8edbc4..bc2108e8 100644 --- a/configure.ac +++ b/configure.ac @@ -463,21 +463,6 @@ AH_BOTTOM([#include ]) test "x$prefix" = xNONE && prefix=$ac_default_prefix -AC_ARG_ENABLE([event-poll], - AS_HELP_STRING([--enable-event-poll], [Enable event polling feature]), - [if test "$enable_event_poll" = "yes"; then - AC_DEFINE([CLIXON_EVENT_POLL], 1, [Enable event polling feature]) - fi] -) - -AC_ARG_WITH([max-events], - AS_HELP_STRING([--with-max-events=VALUE], [Set the maximum number of events (default: 1024)]), - [MAX_EVENTS=$withval], - [MAX_EVENTS=1024] # Значение по умолчанию, если не указано -) - -AC_DEFINE_UNQUOTED([MAX_EVENTS], [$MAX_EVENTS], [Maximum number of events]) - AC_CONFIG_FILES([Makefile lib/Makefile lib/src/Makefile diff --git a/include/clixon_config.h.in b/include/clixon_config.h.in index 27750f3f..86d16877 100644 --- a/include/clixon_config.h.in +++ b/include/clixon_config.h.in @@ -75,9 +75,6 @@ /* Define to 1 if you have the `fcgi' library (-lfcgi). */ #undef HAVE_LIBFCGI -/* Define to 1 if you have the `m' library (-lm). */ -#undef HAVE_LIBM - /* Define to 1 if you have the `netsnmp' library (-lnetsnmp). */ #undef HAVE_LIBNETSNMP diff --git a/lib/src/clixon_event.c b/lib/src/clixon_event.c index e029a481..1f408de7 100644 --- a/lib/src/clixon_event.c +++ b/lib/src/clixon_event.c @@ -1,7 +1,7 @@ /* * ***** BEGIN LICENSE BLOCK ***** - + Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren Copyright (C) 2017-2019 Olof Hagsand Copyright (C) 2020-2022 Olof Hagsand and Rubicon Communications, LLC(Netgat)e @@ -25,7 +25,7 @@ in which case the provisions of the GPL are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the GPL, and not to allow others to - use your version of this file under the terms of Apache License version 2, + use your version of this file under the terms of Apache License version 2, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the GPL. If you do not delete the provisions above, a recipient may use your version of this file under @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -69,10 +70,6 @@ #include "clixon_options.h" #include "clixon_event.h" -#ifdef CLIXON_EVENT_POLL -#include -#endif - /* * Constants */ @@ -86,20 +83,30 @@ struct event_data{ int (*e_fn)(int, void*); /* Callback function */ enum {EVENT_FD, EVENT_TIME} e_type; /* Type of event */ int e_fd; /* File descriptor */ - int e_prio; /* 1: high-prio FD:s only*/ struct timeval e_time; /* Timeout */ void *e_arg; /* Function argument */ - char e_string[EVENT_STRLEN]; /* String for debugging */ + char e_descr[EVENT_STRLEN]; /* String for debugging */ + struct pollfd *e_pollfd; /* Pointer to pull struct */ }; /* * Internal variables - * XXX consider use handle variables instead of global + * Consider use handle variables instead of global, but needs API changes */ -static struct event_data *ee = NULL; -static struct event_data *ee_timers = NULL; +/* File event handlers */ +static struct event_data *_ee = NULL; +static int _ee_nr = 0; -/* Set if element in ee is deleted (clixon_event_unreg_fd). Check in ee loops */ +/* Prioritized File event handlers */ +static struct event_data *_ee_prio = NULL; +static int _ee_prio_nr = 0; + +/* Timer event handlers */ +static struct event_data *_ee_timers = NULL; + +/* Set if element in _ee is deleted (clixon_event_unreg_fd). Check in _ee loops + * XXX: algorithm has flaw: which _ee is unregged? + */ static int _ee_unreg = 0; /* If set (eg by signal handler) exit select loop on next run and return 0 */ @@ -113,8 +120,8 @@ static int _clicon_sig_ignore = 0; /*! For signal handlers: instead of doing exit, set a global variable to exit * - * - zero means dont exit, - * - one means exit, + * - zero means dont exit, + * - one means exit, * - more than one means decrement and make another event loop * Status is checked in event_loop and decremented by one. * When it reaches one the exit is made. @@ -136,7 +143,7 @@ clixon_exit_get(void) return _clicon_exit; } -/*! If > 1 decrement exit counter +/*! If > 1 decrement exit counter */ static int clixon_exit_decr(void) @@ -174,17 +181,22 @@ clicon_sig_ignore_get(void) /*! Register a callback function to be called on input on a file descriptor. * + * Prio is primitive, non-preemptive as follows: + * If several file events are active, then the prioritized are served first. + * If a non-prioritized is running, and a prioritized becomes active, then the + * running un-prioritized handler will run to completion (not pre-empted) and then + * the priorizited events will run. + * A timeout will always run. * @param[in] fd File descriptor * @param[in] fn Function to call when input available on fd * @param[in] arg Argument to function fn * @param[in] str Describing string for logging * @param[in] prio Priority (0 or 1) * @code - * int fn(int fd, void *arg){ - * } - * clixon_event_reg_fd(fd, fn, (void*)42, "call fn on input on fd"); - * @endcode - * @see clixon_event_unreg_fd + * static int fn(int fd, void *arg){} + * clixon_event_reg_fd(fd, fn, (void*)42, "call fn on input on fd", 0); + * @endcode + * @see clixon_event_loop */ int clixon_event_reg_fd_prio(int fd, @@ -200,18 +212,29 @@ clixon_event_reg_fd_prio(int fd, return -1; } memset(e, 0, sizeof(struct event_data)); - strncpy(e->e_string, str, EVENT_STRLEN-1); + strncpy(e->e_descr, str, EVENT_STRLEN-1); e->e_fd = fd; e->e_fn = fn; e->e_arg = arg; e->e_type = EVENT_FD; - e->e_prio = prio; - e->e_next = ee; - ee = e; - clixon_debug(CLIXON_DBG_EVENT, "registering %s", e->e_string); + if (prio){ + e->e_next = _ee_prio; + _ee_prio = e; + _ee_prio_nr++; + } + else { + e->e_next = _ee; + _ee = e; + _ee_nr++; + } + clixon_debug(CLIXON_DBG_EVENT, "registering %s", e->e_descr); return 0; } +/*! Register un-prioritized file event callback + * + * @see clixon_event_unreg_fd_prio + */ int clixon_event_reg_fd(int fd, int (*fn)(int, void*), @@ -228,6 +251,7 @@ clixon_event_reg_fd(int fd, * @retval 0 OK * @retval -1 Error * Note: deregister when exactly function and socket match, not argument + * Consider adding prio to argument * @see clixon_event_reg_fd * @see clixon_event_unreg_timeout */ @@ -239,17 +263,33 @@ clixon_event_unreg_fd(int s, int found = 0; struct event_data **e_prev; - e_prev = ⅇ - for (e = ee; e; e = e->e_next){ + /* First try prioritized */ + e_prev = &_ee_prio; + for (e = _ee_prio; e; e = e->e_next){ if (fn == e->e_fn && s == e->e_fd) { found++; *e_prev = e->e_next; + _ee_prio_nr--; _ee_unreg++; free(e); break; } e_prev = &e->e_next; } + if (!found){ + e_prev = &_ee; + for (e = _ee; e; e = e->e_next){ + if (fn == e->e_fn && s == e->e_fd) { + found++; + *e_prev = e->e_next; + _ee_nr--; + _ee_unreg++; + free(e); + break; + } + e_prev = &e->e_next; + } + } return found?0:-1; } @@ -268,9 +308,9 @@ clixon_event_unreg_fd(int s, * t1.tv_sec = 1; t1.tv_usec = 0; * timeradd(&t, &t1, &t); * clixon_event_reg_timeout(t, fn, NULL, "call every second"); - * } - * @endcode - * + * } + * @endcode + * * @note The timestamp is an absolute timestamp, not relative. * @note The callback is not periodic, you need to make a new registration for each period, see example. * @note The first argument to fn is a dummy, just to get the same signature as for file-descriptor callbacks. @@ -278,7 +318,7 @@ clixon_event_unreg_fd(int s, * @see clixon_event_unreg_timeout */ int -clixon_event_reg_timeout(struct timeval t, +clixon_event_reg_timeout(struct timeval t, int (*fn)(int, void*), void *arg, char *str) @@ -297,14 +337,14 @@ clixon_event_reg_timeout(struct timeval t, return -1; } memset(e, 0, sizeof(struct event_data)); - strncpy(e->e_string, str, EVENT_STRLEN-1); + strncpy(e->e_descr, str, EVENT_STRLEN-1); e->e_fn = fn; e->e_arg = arg; e->e_type = EVENT_TIME; e->e_time = t; /* Sort into right place */ - e_prev = &ee_timers; - for (e1=ee_timers; e1; e1=e1->e_next){ + e_prev = &_ee_timers; + for (e1=_ee_timers; e1; e1=e1->e_next){ if (timercmp(&e->e_time, &e1->e_time, <)) break; e_prev = &e1->e_next; @@ -337,8 +377,8 @@ clixon_event_unreg_timeout(int (*fn)(int, void*), int found = 0; struct event_data **e_prev; - e_prev = &ee_timers; - for (e = ee_timers; e; e = e->e_next){ + e_prev = &_ee_timers; + for (e = _ee_timers; e; e = e->e_next){ if (fn == e->e_fn && arg == e->e_arg) { found++; *e_prev = e->e_next; @@ -353,254 +393,242 @@ clixon_event_unreg_timeout(int (*fn)(int, void*), /*! Poll to see if there is any data available on this file descriptor. * * @param[in] fd File descriptor - * @retval 1 Something to read on fd + * @retval >0 Nr of elements to read on fd * @retval 0 Nothing to read/empty fd * @retval -1 Error */ -#ifdef CLIXON_EVENT_POLL -int -clixon_event_poll(int fd) { - struct pollfd pfd; - int retval; - - pfd.fd = fd; - pfd.events = POLLIN; - - retval = poll(&pfd, 1, 0); - - if (retval < 0) { - clixon_err(OE_EVENTS, errno, "poll"); - } - - return retval; -} -#else int clixon_event_poll(int fd) { - int retval = -1; - fd_set fdset; - struct timeval tnull = {0,}; + int retval = -1; + struct pollfd pfd = {0,}; + int ret; - FD_ZERO(&fdset); - FD_SET(fd, &fdset); - if ((retval = select(FD_SETSIZE, &fdset, NULL, NULL, &tnull)) < 0) - clixon_err(OE_EVENTS, errno, "select"); + pfd.fd = fd; + pfd.events = POLLIN; + if ((ret = poll(&pfd, 1, 0)) < 0){ + clixon_err(OE_EVENTS, errno, "poll"); + goto done; + } + retval = ret; + done: + return retval; +} + +/*! Handle signal interrupt + * + * Signals are in three classes: + * (1) Signals that exit gracefully, the function returns 0 + * Must be registered such as by set_signal() of SIGTERM,SIGINT, etc with a + * handler that calls clicon_exit_set(). + * (2) SIGCHILD Childs that exit(), go through clixon_proc list and cal waitpid + * New select loop is called + * (2) Signals are ignored, and the select is rerun, ie handler calls + * clicon_sig_ignore_get. + * New select loop is called + * (3) Other signals result in an error and return -1. + */ +static int +event_handle_eintr(clixon_handle h) +{ + int retval = -1; + + clixon_debug(CLIXON_DBG_EVENT, "poll/select %s", strerror(errno)); + if (clixon_exit_get() == 1){ + clixon_err(OE_EVENTS, errno, "poll/select"); + goto exit; + } + else if (clicon_sig_child_get()){ + /* Go through processes and wait for child processes */ + if (clixon_process_waitpid(h) < 0) + goto done; + clicon_sig_child_set(0); + } + else if (clicon_sig_ignore_get()){ + clicon_sig_ignore_set(0); + } + else{ + clixon_err(OE_EVENTS, errno, "poll/select"); + goto done; + } + retval = 1; + done: + return retval; + exit: + retval = 0; + goto done; +} + +static int +event_handle_fds(struct event_data *ee, + int prio) +{ + int retval = -1; + struct pollfd *pfd; + struct event_data *e = NULL; + + for (e = ee; e; e = e->e_next) { + if (e->e_type != EVENT_FD) + continue; + clixon_debug(CLIXON_DBG_EVENT | CLIXON_DBG_DETAIL, "check s:%d prio:%d fd %s", e->e_fd, prio, e->e_descr); + if ((pfd = e->e_pollfd) == NULL) /* Could be added after poll regitsration */ + continue; + if (pfd->revents != 0) { /* returned events */ + if (pfd->revents & POLLIN || pfd->revents & POLLHUP) { + clixon_debug(CLIXON_DBG_EVENT, "fd %s", e->e_descr); + _ee_unreg = 0; + if ((*e->e_fn)(e->e_fd, e->e_arg) < 0) { + clixon_debug(CLIXON_DBG_EVENT, "Error in: %s", e->e_descr); + goto done; + } + if (_ee_unreg){ /* and this socket,... */ + _ee_unreg = 0; + break; + } + if (prio == 0 && _ee_prio_nr > 0) /* Prioritized exists, break unprio fairness */ + break; + } + else if (pfd->revents & POLLNVAL) { /* fd not open */ + clixon_err(OE_EVENTS, 0, "poll: Invalid request: %s fd %d not open", + e->e_descr, pfd->fd); + goto done; + } + else { + clixon_debug(CLIXON_DBG_EVENT | CLIXON_DBG_DETAIL, + "%s %d revents:0x%x", e->e_descr, pfd->fd, pfd->revents); + goto done; + } + } + } + retval = 0; + done: return retval; } -#endif /*! Dispatch file descriptor events (and timeouts) by invoking callbacks. * * @param[in] h Clixon handle * @retval 0 OK - * @retval -1 Error: eg select, callback, timer, + * @retval -1 Error: eg select, callback, timer, * @note There is an issue with fairness between timeouts and events * Currently a socket that is not read/emptied properly starve timeouts. * One could try to poll the file descriptors after a timeout? + * TODO: unreg, better prio algorithm */ -#ifdef CLIXON_EVENT_POLL int clixon_event_loop(clixon_handle h) { - struct event_data *e = NULL; - struct pollfd fds[MAX_EVENTS]; - int retval = -1; - int nfds = 0; + int retval = -1; + struct event_data *e = NULL; + struct pollfd *fds = NULL; + struct pollfd *pfd; + uint32_t nfds_max = 0; + int nfds = 0; + struct timeval t0; + struct timeval t; + int64_t tdiff; + int timeout; + int n; + int ret; while (clixon_exit_get() != 1) { + nfds = _ee_prio_nr + _ee_nr; + if (nfds > nfds_max){ + nfds_max = nfds; + if ((fds = realloc(fds, nfds_max*sizeof(struct pollfd))) == NULL){ + clixon_err(OE_UNIX, errno, "realloc"); + goto done; + } + } nfds = 0; - for (e = ee; e; e = e->e_next) { + clixon_debug(CLIXON_DBG_EVENT | CLIXON_DBG_DETAIL, "register prio"); + for (e = _ee_prio; e; e = e->e_next) { if (e->e_type == EVENT_FD) { - fds[nfds].fd = e->e_fd; - fds[nfds].events = POLLIN; + pfd = &fds[nfds]; + pfd->fd = e->e_fd; + pfd->events = POLLIN; /* requested event */ + e->e_pollfd = pfd; + clixon_debug(CLIXON_DBG_EVENT | CLIXON_DBG_DETAIL, "register fd prio %s nr:%d", + e->e_descr, nfds); nfds++; } } - - int timeout = -1; - if (ee_timers != NULL) { - struct timeval t0, t; - gettimeofday(&t0, NULL); - timersub(&ee_timers->e_time, &t0, &t); - timeout = t.tv_sec * 1000 + t.tv_usec / 1000; + clixon_debug(CLIXON_DBG_EVENT | CLIXON_DBG_DETAIL, "register unprio"); + for (e = _ee; e; e = e->e_next) { + if (e->e_type == EVENT_FD) { + pfd = &fds[nfds]; + pfd->fd = e->e_fd; + pfd->events = POLLIN; /* requested event */ + e->e_pollfd = pfd; + clixon_debug(CLIXON_DBG_EVENT | CLIXON_DBG_DETAIL, "register fd %s nr:%d", + e->e_descr, nfds); + nfds++; + } } - - int n = poll(fds, nfds, timeout); - + if (nfds != _ee_nr + _ee_prio_nr){ + clixon_err(OE_EVENTS, 0, "File descriptor mismatch"); + goto done; + } + timeout = -1; + clixon_debug(CLIXON_DBG_EVENT | CLIXON_DBG_DETAIL, "timeout"); + if (_ee_timers != NULL) { + gettimeofday(&t0, NULL); + timersub(&_ee_timers->e_time, &t0, &t); + tdiff = t.tv_sec * 1000 + t.tv_usec / 1000; + if (tdiff < 0) + timeout = 0; + else + timeout = (int)tdiff; + } + clixon_debug(CLIXON_DBG_EVENT | CLIXON_DBG_DETAIL, "poll timeout: %d", timeout); + n = poll(fds, nfds, timeout); if (n == -1) { - if (errno == EINTR) { + clixon_debug(CLIXON_DBG_EVENT | CLIXON_DBG_DETAIL, "n=-1 Error"); + if (errno == EINTR){ + if (clixon_exit_get() == 1){ + clixon_err(OE_EVENTS, errno, "poll"); + goto ok; + } + if ((ret = event_handle_eintr(h)) < 0) + goto done; + if (ret == 0){ // exit + retval = 0; + goto done; + } continue; } - clixon_err(OE_EVENTS, errno, "poll"); - goto err; + else + clixon_err(OE_EVENTS, errno, "poll"); + goto done; } - - if (n == 0) { - // Таймаут - e = ee_timers; - ee_timers = ee_timers->e_next; + if (n == 0) { /* timeout */ + clixon_debug(CLIXON_DBG_EVENT | CLIXON_DBG_DETAIL, "n=0 Timeout"); + e = _ee_timers; + _ee_timers = _ee_timers->e_next; + clixon_debug(CLIXON_DBG_EVENT | CLIXON_DBG_DETAIL, "timeout: %s", e->e_descr); if ((*e->e_fn)(0, e->e_arg) < 0) { free(e); - goto err; - } - free(e); - continue; - } - - for (int i = 0; i < nfds; i++) { - if (fds[i].revents & POLLIN) { - for (e = ee; e; e = e->e_next) { - if (e->e_type == EVENT_FD && e->e_fd == fds[i].fd) { - if ((*e->e_fn)(e->e_fd, e->e_arg) < 0) { - goto err; - } - break; - } - } - } - } - } - - retval = 0; - - err: - return retval; -} -#else -int -clixon_event_loop(clixon_handle h) -{ - struct event_data *e; - int n; - struct timeval t; - struct timeval t0; - struct timeval tnull = {0,}; - fd_set fdset; - int retval = -1; - struct event_data *e_next; - - while (clixon_exit_get() != 1){ - FD_ZERO(&fdset); - if (clicon_sig_child_get()){ - /* Go through processes and wait for child processes */ - if (clixon_process_waitpid(h) < 0) - goto err; - clicon_sig_child_set(0); - } - for (e=ee; e; e=e->e_next) - if (e->e_type == EVENT_FD) - FD_SET(e->e_fd, &fdset); - if (ee_timers != NULL){ - gettimeofday(&t0, NULL); - timersub(&ee_timers->e_time, &t0, &t); - if (t.tv_sec < 0) - n = select(FD_SETSIZE, &fdset, NULL, NULL, &tnull); - else - n = select(FD_SETSIZE, &fdset, NULL, NULL, &t); - } - else - n = select(FD_SETSIZE, &fdset, NULL, NULL, NULL); - if (clixon_exit_get() == 1){ - break; - } - if (n == -1) { - if (errno == EINTR){ - /* Signals are checked and are in three classes: - * (1) Signals that exit gracefully, the function returns 0 - * Must be registered such as by set_signal() of SIGTERM,SIGINT, etc with a handler that calls - * clicon_exit_set(). - * (2) SIGCHILD Childs that exit(), go through clixon_proc list and cal waitpid - * New select loop is called - * (2) Signals are ignored, and the select is rerun, ie handler calls clicon_sig_ignore_get - * New select loop is called - * (3) Other signals result in an error and return -1. - */ - clixon_debug(CLIXON_DBG_EVENT, "select: %s", strerror(errno)); - if (clixon_exit_get() == 1){ - clixon_err(OE_EVENTS, errno, "select"); - retval = 0; - } - else if (clicon_sig_child_get()){ - /* Go through processes and wait for child processes */ - if (clixon_process_waitpid(h) < 0) - goto err; - clicon_sig_child_set(0); - continue; - } - else if (clicon_sig_ignore_get()){ - clicon_sig_ignore_set(0); - continue; - } - else - clixon_err(OE_EVENTS, errno, "select"); - } - else - clixon_err(OE_EVENTS, errno, "select"); - goto err; - } - if (n==0){ /* Timeout */ - e = ee_timers; - ee_timers = ee_timers->e_next; - clixon_debug(CLIXON_DBG_EVENT | CLIXON_DBG_DETAIL, "timeout: %s", e->e_string); - if ((*e->e_fn)(0, e->e_arg) < 0){ - free(e); - goto err; + goto done; } free(e); } - _ee_unreg = 0; - if (clicon_option_bool(h, "CLICON_SOCK_PRIO")){ - for (e=ee; e; e=e_next) { - if (clixon_exit_get() == 1) - break; - e_next = e->e_next; - if (e->e_type == EVENT_FD && FD_ISSET(e->e_fd, &fdset) && e->e_prio){ - clixon_debug(CLIXON_DBG_EVENT, "FD_ISSET: %s prio:%d", e->e_string, e->e_prio); - if ((*e->e_fn)(e->e_fd, e->e_arg) < 0){ - clixon_debug(CLIXON_DBG_EVENT, "Error in: %s", e->e_string); - goto err; - } - if (_ee_unreg){ - _ee_unreg = 0; - break; - } - } - } - } - - /* Unprio - * Note that without prio, round-robin fairness is ensured, not with prio */ - for (e=ee; e; e=e_next){ - if (clixon_exit_get() == 1) - break; - e_next = e->e_next; - if (e->e_type == EVENT_FD && FD_ISSET(e->e_fd, &fdset) && e->e_prio==0){ - clixon_debug(CLIXON_DBG_EVENT, "FD_ISSET: %s", e->e_string); - if ((*e->e_fn)(e->e_fd, e->e_arg) < 0){ - clixon_debug(CLIXON_DBG_EVENT, "Error in: %s", e->e_string); - goto err; - } - if (_ee_unreg){ - _ee_unreg = 0; - break; - } - if (clicon_option_bool(h, "CLICON_SOCK_PRIO")) - break; - } - } + /* Prio files */ + if ((ret = event_handle_fds(_ee_prio, 1)) < 0) + goto done; + /* Unprio files */ + if ((ret = event_handle_fds(_ee, 0)) < 0) + goto done; clixon_exit_decr(); /* If exit is set and > 1, decrement it (and exit when 1) */ - continue; - err: - clixon_debug(CLIXON_DBG_EVENT, "err"); - break; - } + } + ok: if (clixon_exit_get() == 1) retval = 0; + done: clixon_debug(CLIXON_DBG_EVENT, "retval:%d", retval); + if (fds) + free(fds); return retval; } -#endif int clixon_event_exit(void) @@ -608,17 +636,25 @@ clixon_event_exit(void) struct event_data *e; struct event_data *e_next; - e_next = ee; + e_next = _ee_prio; while ((e = e_next) != NULL){ e_next = e->e_next; free(e); } - ee = NULL; - e_next = ee_timers; + _ee_prio = NULL; + + e_next = _ee; while ((e = e_next) != NULL){ e_next = e->e_next; free(e); } - ee_timers = NULL; + _ee = NULL; + + e_next = _ee_timers; + while ((e = e_next) != NULL){ + e_next = e->e_next; + free(e); + } + _ee_timers = NULL; return 0; }