Replace select with poll
Added prio fdes, handling of EINTR, optimized double for loops, handle POLLHUP
This commit is contained in:
parent
aa617fd677
commit
74c8244c66
6 changed files with 283 additions and 277 deletions
|
|
@ -18,6 +18,8 @@ Planned: April 2025
|
||||||
|
|
||||||
### Features
|
### 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
|
* Added new `ca_userdef` callback
|
||||||
* New `clixon-restconf@2025-02-01.yang` revision
|
* New `clixon-restconf@2025-02-01.yang` revision
|
||||||
* Added timeout parameter
|
* Added timeout parameter
|
||||||
|
|
|
||||||
14
configure
vendored
14
configure
vendored
|
|
@ -777,7 +777,6 @@ with_yang_standard_dir
|
||||||
with_clicon_user
|
with_clicon_user
|
||||||
with_clicon_group
|
with_clicon_group
|
||||||
enable_nls
|
enable_nls
|
||||||
enable_event_poll
|
|
||||||
'
|
'
|
||||||
ac_precious_vars='build_alias
|
ac_precious_vars='build_alias
|
||||||
host_alias
|
host_alias
|
||||||
|
|
@ -1424,7 +1423,6 @@ Optional Features:
|
||||||
http/1 only
|
http/1 only
|
||||||
--enable-netsnmp Enable net-snmp Clixon YANG mapping
|
--enable-netsnmp Enable net-snmp Clixon YANG mapping
|
||||||
|
|
||||||
--enable-event-poll Enable event polling feature
|
|
||||||
|
|
||||||
Optional Packages:
|
Optional Packages:
|
||||||
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
|
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
|
||||||
|
|
@ -6249,18 +6247,6 @@ fi
|
||||||
|
|
||||||
test "x$prefix" = xNONE && prefix=$ac_default_prefix
|
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"
|
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
|
cat >confcache <<\_ACEOF
|
||||||
|
|
|
||||||
15
configure.ac
15
configure.ac
|
|
@ -463,21 +463,6 @@ AH_BOTTOM([#include <clixon_custom.h>])
|
||||||
|
|
||||||
test "x$prefix" = xNONE && prefix=$ac_default_prefix
|
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
|
AC_CONFIG_FILES([Makefile
|
||||||
lib/Makefile
|
lib/Makefile
|
||||||
lib/src/Makefile
|
lib/src/Makefile
|
||||||
|
|
|
||||||
|
|
@ -75,9 +75,6 @@
|
||||||
/* Define to 1 if you have the `fcgi' library (-lfcgi). */
|
/* Define to 1 if you have the `fcgi' library (-lfcgi). */
|
||||||
#undef HAVE_LIBFCGI
|
#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). */
|
/* Define to 1 if you have the `netsnmp' library (-lnetsnmp). */
|
||||||
#undef HAVE_LIBNETSNMP
|
#undef HAVE_LIBNETSNMP
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <poll.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
@ -69,10 +70,6 @@
|
||||||
#include "clixon_options.h"
|
#include "clixon_options.h"
|
||||||
#include "clixon_event.h"
|
#include "clixon_event.h"
|
||||||
|
|
||||||
#ifdef CLIXON_EVENT_POLL
|
|
||||||
#include <poll.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Constants
|
* Constants
|
||||||
*/
|
*/
|
||||||
|
|
@ -86,20 +83,30 @@ struct event_data{
|
||||||
int (*e_fn)(int, void*); /* Callback function */
|
int (*e_fn)(int, void*); /* Callback function */
|
||||||
enum {EVENT_FD, EVENT_TIME} e_type; /* Type of event */
|
enum {EVENT_FD, EVENT_TIME} e_type; /* Type of event */
|
||||||
int e_fd; /* File descriptor */
|
int e_fd; /* File descriptor */
|
||||||
int e_prio; /* 1: high-prio FD:s only*/
|
|
||||||
struct timeval e_time; /* Timeout */
|
struct timeval e_time; /* Timeout */
|
||||||
void *e_arg; /* Function argument */
|
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
|
* 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;
|
/* File event handlers */
|
||||||
static struct event_data *ee_timers = NULL;
|
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;
|
static int _ee_unreg = 0;
|
||||||
|
|
||||||
/* If set (eg by signal handler) exit select loop on next run and return 0 */
|
/* If set (eg by signal handler) exit select loop on next run and return 0 */
|
||||||
|
|
@ -174,17 +181,22 @@ clicon_sig_ignore_get(void)
|
||||||
|
|
||||||
/*! Register a callback function to be called on input on a file descriptor.
|
/*! 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] fd File descriptor
|
||||||
* @param[in] fn Function to call when input available on fd
|
* @param[in] fn Function to call when input available on fd
|
||||||
* @param[in] arg Argument to function fn
|
* @param[in] arg Argument to function fn
|
||||||
* @param[in] str Describing string for logging
|
* @param[in] str Describing string for logging
|
||||||
* @param[in] prio Priority (0 or 1)
|
* @param[in] prio Priority (0 or 1)
|
||||||
* @code
|
* @code
|
||||||
* int fn(int fd, void *arg){
|
* static int fn(int fd, void *arg){}
|
||||||
* }
|
* clixon_event_reg_fd(fd, fn, (void*)42, "call fn on input on fd", 0);
|
||||||
* clixon_event_reg_fd(fd, fn, (void*)42, "call fn on input on fd");
|
|
||||||
* @endcode
|
* @endcode
|
||||||
* @see clixon_event_unreg_fd
|
* @see clixon_event_loop
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clixon_event_reg_fd_prio(int fd,
|
clixon_event_reg_fd_prio(int fd,
|
||||||
|
|
@ -200,18 +212,29 @@ clixon_event_reg_fd_prio(int fd,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
memset(e, 0, sizeof(struct event_data));
|
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_fd = fd;
|
||||||
e->e_fn = fn;
|
e->e_fn = fn;
|
||||||
e->e_arg = arg;
|
e->e_arg = arg;
|
||||||
e->e_type = EVENT_FD;
|
e->e_type = EVENT_FD;
|
||||||
e->e_prio = prio;
|
if (prio){
|
||||||
e->e_next = ee;
|
e->e_next = _ee_prio;
|
||||||
ee = e;
|
_ee_prio = e;
|
||||||
clixon_debug(CLIXON_DBG_EVENT, "registering %s", e->e_string);
|
_ee_prio_nr++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
e->e_next = _ee;
|
||||||
|
_ee = e;
|
||||||
|
_ee_nr++;
|
||||||
|
}
|
||||||
|
clixon_debug(CLIXON_DBG_EVENT, "registering %s", e->e_descr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Register un-prioritized file event callback
|
||||||
|
*
|
||||||
|
* @see clixon_event_unreg_fd_prio
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
clixon_event_reg_fd(int fd,
|
clixon_event_reg_fd(int fd,
|
||||||
int (*fn)(int, void*),
|
int (*fn)(int, void*),
|
||||||
|
|
@ -228,6 +251,7 @@ clixon_event_reg_fd(int fd,
|
||||||
* @retval 0 OK
|
* @retval 0 OK
|
||||||
* @retval -1 Error
|
* @retval -1 Error
|
||||||
* Note: deregister when exactly function and socket match, not argument
|
* Note: deregister when exactly function and socket match, not argument
|
||||||
|
* Consider adding prio to argument
|
||||||
* @see clixon_event_reg_fd
|
* @see clixon_event_reg_fd
|
||||||
* @see clixon_event_unreg_timeout
|
* @see clixon_event_unreg_timeout
|
||||||
*/
|
*/
|
||||||
|
|
@ -239,17 +263,33 @@ clixon_event_unreg_fd(int s,
|
||||||
int found = 0;
|
int found = 0;
|
||||||
struct event_data **e_prev;
|
struct event_data **e_prev;
|
||||||
|
|
||||||
e_prev = ⅇ
|
/* First try prioritized */
|
||||||
for (e = ee; e; e = e->e_next){
|
e_prev = &_ee_prio;
|
||||||
|
for (e = _ee_prio; e; e = e->e_next){
|
||||||
if (fn == e->e_fn && s == e->e_fd) {
|
if (fn == e->e_fn && s == e->e_fd) {
|
||||||
found++;
|
found++;
|
||||||
*e_prev = e->e_next;
|
*e_prev = e->e_next;
|
||||||
|
_ee_prio_nr--;
|
||||||
_ee_unreg++;
|
_ee_unreg++;
|
||||||
free(e);
|
free(e);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
e_prev = &e->e_next;
|
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;
|
return found?0:-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -297,14 +337,14 @@ clixon_event_reg_timeout(struct timeval t,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
memset(e, 0, sizeof(struct event_data));
|
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_fn = fn;
|
||||||
e->e_arg = arg;
|
e->e_arg = arg;
|
||||||
e->e_type = EVENT_TIME;
|
e->e_type = EVENT_TIME;
|
||||||
e->e_time = t;
|
e->e_time = t;
|
||||||
/* Sort into right place */
|
/* Sort into right place */
|
||||||
e_prev = &ee_timers;
|
e_prev = &_ee_timers;
|
||||||
for (e1=ee_timers; e1; e1=e1->e_next){
|
for (e1=_ee_timers; e1; e1=e1->e_next){
|
||||||
if (timercmp(&e->e_time, &e1->e_time, <))
|
if (timercmp(&e->e_time, &e1->e_time, <))
|
||||||
break;
|
break;
|
||||||
e_prev = &e1->e_next;
|
e_prev = &e1->e_next;
|
||||||
|
|
@ -337,8 +377,8 @@ clixon_event_unreg_timeout(int (*fn)(int, void*),
|
||||||
int found = 0;
|
int found = 0;
|
||||||
struct event_data **e_prev;
|
struct event_data **e_prev;
|
||||||
|
|
||||||
e_prev = &ee_timers;
|
e_prev = &_ee_timers;
|
||||||
for (e = ee_timers; e; e = e->e_next){
|
for (e = _ee_timers; e; e = e->e_next){
|
||||||
if (fn == e->e_fn && arg == e->e_arg) {
|
if (fn == e->e_fn && arg == e->e_arg) {
|
||||||
found++;
|
found++;
|
||||||
*e_prev = e->e_next;
|
*e_prev = e->e_next;
|
||||||
|
|
@ -353,42 +393,117 @@ clixon_event_unreg_timeout(int (*fn)(int, void*),
|
||||||
/*! Poll to see if there is any data available on this file descriptor.
|
/*! Poll to see if there is any data available on this file descriptor.
|
||||||
*
|
*
|
||||||
* @param[in] fd 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 0 Nothing to read/empty fd
|
||||||
* @retval -1 Error
|
* @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
|
int
|
||||||
clixon_event_poll(int fd)
|
clixon_event_poll(int fd)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
fd_set fdset;
|
struct pollfd pfd = {0,};
|
||||||
struct timeval tnull = {0,};
|
int ret;
|
||||||
|
|
||||||
FD_ZERO(&fdset);
|
pfd.fd = fd;
|
||||||
FD_SET(fd, &fdset);
|
pfd.events = POLLIN;
|
||||||
if ((retval = select(FD_SETSIZE, &fdset, NULL, NULL, &tnull)) < 0)
|
if ((ret = poll(&pfd, 1, 0)) < 0){
|
||||||
clixon_err(OE_EVENTS, errno, "select");
|
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;
|
return retval;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/*! Dispatch file descriptor events (and timeouts) by invoking callbacks.
|
/*! Dispatch file descriptor events (and timeouts) by invoking callbacks.
|
||||||
*
|
*
|
||||||
|
|
@ -398,209 +513,122 @@ clixon_event_poll(int fd)
|
||||||
* @note There is an issue with fairness between timeouts and events
|
* @note There is an issue with fairness between timeouts and events
|
||||||
* Currently a socket that is not read/emptied properly starve timeouts.
|
* Currently a socket that is not read/emptied properly starve timeouts.
|
||||||
* One could try to poll the file descriptors after a timeout?
|
* One could try to poll the file descriptors after a timeout?
|
||||||
|
* TODO: unreg, better prio algorithm
|
||||||
*/
|
*/
|
||||||
#ifdef CLIXON_EVENT_POLL
|
|
||||||
int
|
int
|
||||||
clixon_event_loop(clixon_handle h)
|
clixon_event_loop(clixon_handle h)
|
||||||
{
|
{
|
||||||
struct event_data *e = NULL;
|
|
||||||
struct pollfd fds[MAX_EVENTS];
|
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
struct event_data *e = NULL;
|
||||||
|
struct pollfd *fds = NULL;
|
||||||
|
struct pollfd *pfd;
|
||||||
|
uint32_t nfds_max = 0;
|
||||||
int nfds = 0;
|
int nfds = 0;
|
||||||
|
struct timeval t0;
|
||||||
|
struct timeval t;
|
||||||
|
int64_t tdiff;
|
||||||
|
int timeout;
|
||||||
|
int n;
|
||||||
|
int ret;
|
||||||
|
|
||||||
while (clixon_exit_get() != 1) {
|
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;
|
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) {
|
if (e->e_type == EVENT_FD) {
|
||||||
fds[nfds].fd = e->e_fd;
|
pfd = &fds[nfds];
|
||||||
fds[nfds].events = POLLIN;
|
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++;
|
nfds++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
clixon_debug(CLIXON_DBG_EVENT | CLIXON_DBG_DETAIL, "register unprio");
|
||||||
int timeout = -1;
|
for (e = _ee; e; e = e->e_next) {
|
||||||
if (ee_timers != NULL) {
|
if (e->e_type == EVENT_FD) {
|
||||||
struct timeval t0, t;
|
pfd = &fds[nfds];
|
||||||
gettimeofday(&t0, NULL);
|
pfd->fd = e->e_fd;
|
||||||
timersub(&ee_timers->e_time, &t0, &t);
|
pfd->events = POLLIN; /* requested event */
|
||||||
timeout = t.tv_sec * 1000 + t.tv_usec / 1000;
|
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 (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;
|
continue;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
clixon_err(OE_EVENTS, errno, "poll");
|
clixon_err(OE_EVENTS, errno, "poll");
|
||||||
goto err;
|
goto done;
|
||||||
}
|
}
|
||||||
|
if (n == 0) { /* timeout */
|
||||||
if (n == 0) {
|
clixon_debug(CLIXON_DBG_EVENT | CLIXON_DBG_DETAIL, "n=0 Timeout");
|
||||||
// Таймаут
|
e = _ee_timers;
|
||||||
e = ee_timers;
|
_ee_timers = _ee_timers->e_next;
|
||||||
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) {
|
if ((*e->e_fn)(0, e->e_arg) < 0) {
|
||||||
free(e);
|
free(e);
|
||||||
goto err;
|
goto done;
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
free(e);
|
free(e);
|
||||||
}
|
}
|
||||||
_ee_unreg = 0;
|
/* Prio files */
|
||||||
if (clicon_option_bool(h, "CLICON_SOCK_PRIO")){
|
if ((ret = event_handle_fds(_ee_prio, 1)) < 0)
|
||||||
for (e=ee; e; e=e_next) {
|
goto done;
|
||||||
if (clixon_exit_get() == 1)
|
/* Unprio files */
|
||||||
break;
|
if ((ret = event_handle_fds(_ee, 0)) < 0)
|
||||||
e_next = e->e_next;
|
goto done;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
clixon_exit_decr(); /* If exit is set and > 1, decrement it (and exit when 1) */
|
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)
|
if (clixon_exit_get() == 1)
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
done:
|
||||||
clixon_debug(CLIXON_DBG_EVENT, "retval:%d", retval);
|
clixon_debug(CLIXON_DBG_EVENT, "retval:%d", retval);
|
||||||
|
if (fds)
|
||||||
|
free(fds);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
int
|
int
|
||||||
clixon_event_exit(void)
|
clixon_event_exit(void)
|
||||||
|
|
@ -608,17 +636,25 @@ clixon_event_exit(void)
|
||||||
struct event_data *e;
|
struct event_data *e;
|
||||||
struct event_data *e_next;
|
struct event_data *e_next;
|
||||||
|
|
||||||
e_next = ee;
|
e_next = _ee_prio;
|
||||||
while ((e = e_next) != NULL){
|
while ((e = e_next) != NULL){
|
||||||
e_next = e->e_next;
|
e_next = e->e_next;
|
||||||
free(e);
|
free(e);
|
||||||
}
|
}
|
||||||
ee = NULL;
|
_ee_prio = NULL;
|
||||||
e_next = ee_timers;
|
|
||||||
|
e_next = _ee;
|
||||||
while ((e = e_next) != NULL){
|
while ((e = e_next) != NULL){
|
||||||
e_next = e->e_next;
|
e_next = e->e_next;
|
||||||
free(e);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue