diff options
author | Alberto Gonzalez Iniesta <agi@inittab.org> | 2012-11-05 16:28:09 +0100 |
---|---|---|
committer | Alberto Gonzalez Iniesta <agi@inittab.org> | 2012-11-05 16:28:09 +0100 |
commit | 8dd0350e1607aa30f7a043c8d5ec7a7eeb874115 (patch) | |
tree | 566d0620eb693320cb121dfd93a5675fa704a30b /event.c | |
parent | 349cfa7acb95abe865209a28e417ec74b56f9bba (diff) |
Imported Upstream version 2.3_rc1
Diffstat (limited to 'event.c')
-rw-r--r-- | event.c | 1055 |
1 files changed, 0 insertions, 1055 deletions
diff --git a/event.c b/event.c deleted file mode 100644 index 6a9161b..0000000 --- a/event.c +++ /dev/null @@ -1,1055 +0,0 @@ -/* - * OpenVPN -- An application to securely tunnel IP networks - * over a single TCP/UDP port, with support for SSL/TLS-based - * session authentication and key exchange, - * packet encryption, packet authentication, and - * packet compression. - * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (see the file COPYING included with this - * distribution); if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "syshead.h" - -#include "buffer.h" -#include "error.h" -#include "integer.h" -#include "event.h" - -#include "memdbg.h" - -/* - * Some OSes will prefer select() over poll() - * when both are available. - */ -#if defined(TARGET_DARWIN) -#define SELECT_PREFERRED_OVER_POLL -#endif - -/* - * All non-windows OSes are assumed to have select() - */ -#ifdef WIN32 -#define SELECT 0 -#else -#define SELECT 1 -#endif - -/* - * This should be set to the highest file descriptor - * which can be used in one of the FD_ macros. - */ -#ifdef FD_SETSIZE -#define SELECT_MAX_FDS FD_SETSIZE -#else -#define SELECT_MAX_FDS 256 -#endif - -static inline int -tv_to_ms_timeout (const struct timeval *tv) -{ - if (tv->tv_sec == 0 && tv->tv_usec == 0) - return 0; - else - return max_int (tv->tv_sec * 1000 + (tv->tv_usec + 500) / 1000, 1); -} - -#ifdef WIN32 - -struct we_set -{ - struct event_set_functions func; - bool fast; - HANDLE *events; - struct event_set_return *esr; - int n_events; - int capacity; -}; - -static inline void -we_set_event (struct we_set *wes, int i, event_t event, unsigned int rwflags, void *arg) -{ - ASSERT (i >= 0 && i < wes->capacity); - - if (rwflags == EVENT_READ) - { - ASSERT (event->read != NULL); - wes->events[i] = event->read; - } - else if (rwflags == EVENT_WRITE) - { - ASSERT (event->write != NULL); - wes->events[i] = event->write; - } - else - msg (M_FATAL, "fatal error in we_set_events: rwflags=%d", rwflags); - - wes->esr[i].rwflags = rwflags; - wes->esr[i].arg = arg; -} - -static inline bool -we_append_event (struct we_set *wes, event_t event, unsigned int rwflags, void *arg) -{ - if (rwflags & EVENT_WRITE) - { - if (wes->n_events < wes->capacity) - { - we_set_event (wes, wes->n_events, event, EVENT_WRITE, arg); - ++wes->n_events; - } - else - return false; - } - if (rwflags & EVENT_READ) - { - if (wes->n_events < wes->capacity) - { - we_set_event (wes, wes->n_events, event, EVENT_READ, arg); - ++wes->n_events; - } - else - return false; - } - return true; -} - -static void -we_del_event (struct we_set *wes, event_t event) -{ - int i, j = 0; - const int len = wes->n_events; - - for (i = 0; i < len; ++i) - { - const HANDLE h = wes->events[i]; - if (h == event->read || h == event->write) - --wes->n_events; - else - { - if (i != j) - { - wes->events[j] = wes->events[i]; - wes->esr[j] = wes->esr[i]; - } - ++j; - } - } -} - -static void -we_del_index (struct we_set *wes, int index) -{ - int i; - ASSERT (index >= 0 && index < wes->n_events); - for (i = index; i < wes->n_events - 1; ++i) - { - wes->events[i] = wes->events[i+1]; - wes->esr[i] = wes->esr[i+1]; - } - --wes->n_events; -} - -static void -we_get_rw_indices (struct we_set *wes, event_t event, int *ri, int *wi) -{ - int i; - *ri = *wi = -1; - for (i = 0; i < wes->n_events; ++i) - { - const HANDLE h = wes->events[i]; - if (h == event->read) - { - ASSERT (*ri == -1); - *ri = i; - } - else if (h == event->write) - { - ASSERT (*wi == -1); - *wi = i; - } - } -} - -static void -we_free (struct event_set *es) -{ - struct we_set *wes = (struct we_set *) es; - free (wes->events); - free (wes->esr); - free (wes); -} - -static void -we_reset (struct event_set *es) -{ - struct we_set *wes = (struct we_set *) es; - ASSERT (wes->fast); - wes->n_events = 0; -} - -static void -we_del (struct event_set *es, event_t event) -{ - struct we_set *wes = (struct we_set *) es; - ASSERT (!wes->fast); - we_del_event (wes, event); -} - -static void -we_ctl (struct event_set *es, event_t event, unsigned int rwflags, void *arg) -{ - struct we_set *wes = (struct we_set *) es; - - dmsg (D_EVENT_WAIT, "WE_CTL n=%d ev=0x%08x rwflags=0x%04x arg=" ptr_format, - wes->n_events, - (unsigned int)event, - rwflags, - (ptr_type)arg); - - if (wes->fast) - { - if (!we_append_event (wes, event, rwflags, arg)) - goto err; - } - else - { - int ri, wi; - int one = -1; - int n = 0; - - we_get_rw_indices (wes, event, &ri, &wi); - if (wi >= 0) - { - one = wi; - ++n; - } - if (ri >= 0) - { - one = ri; - ++n; - } - switch (rwflags) - { - case 0: - switch (n) - { - case 0: - break; - case 1: - we_del_index (wes, one); - break; - case 2: - we_del_event (wes, event); - break; - default: - ASSERT (0); - } - break; - case EVENT_READ: - switch (n) - { - case 0: - if (!we_append_event (wes, event, EVENT_READ, arg)) - goto err; - break; - case 1: - we_set_event (wes, one, event, EVENT_READ, arg); - break; - case 2: - we_del_index (wes, wi); - break; - default: - ASSERT (0); - } - break; - case EVENT_WRITE: - switch (n) - { - case 0: - if (!we_append_event (wes, event, EVENT_WRITE, arg)) - goto err; - break; - case 1: - we_set_event (wes, one, event, EVENT_WRITE, arg); - break; - case 2: - we_del_index (wes, ri); - break; - default: - ASSERT (0); - } - break; - case EVENT_READ|EVENT_WRITE: - switch (n) - { - case 0: - if (!we_append_event (wes, event, EVENT_READ|EVENT_WRITE, arg)) - goto err; - break; - case 1: - if (ri == -1) - { - ASSERT (wi != -1); - if (!we_append_event (wes, event, EVENT_READ, arg)) - goto err; - } - else if (wi == -1) - { - if (!we_append_event (wes, event, EVENT_WRITE, arg)) - goto err; - } - else - ASSERT (0); - break; - case 2: - break; - default: - ASSERT (0); - } - break; - default: - msg (M_FATAL, "fatal error in we_ctl: rwflags=%d", rwflags); - } - } - return; - - err: - msg (D_EVENT_ERRORS, "Error: Windows resource limit WSA_MAXIMUM_WAIT_EVENTS (%d) has been exceeded", WSA_MAXIMUM_WAIT_EVENTS); -} - -static int -we_wait (struct event_set *es, const struct timeval *tv, struct event_set_return *out, int outlen) -{ - struct we_set *wes = (struct we_set *) es; - const int timeout = tv_to_ms_timeout (tv); - DWORD status; - - dmsg (D_EVENT_WAIT, "WE_WAIT enter n=%d to=%d", wes->n_events, timeout); - -#ifdef ENABLE_DEBUG - if (check_debug_level (D_EVENT_WAIT)) { - int i; - for (i = 0; i < wes->n_events; ++i) - dmsg (D_EVENT_WAIT, "[%d] ev=0x%08x rwflags=0x%04x arg=" ptr_format, - i, - (unsigned int)wes->events[i], - wes->esr[i].rwflags, - (ptr_type)wes->esr[i].arg); - } -#endif - - /* - * First poll our event list with 0 timeout - */ - status = WSAWaitForMultipleEvents( - (DWORD) wes->n_events, - wes->events, - FALSE, - (DWORD) 0, - FALSE); - - /* - * If at least one event is already set, we must - * individually poll the whole list. - */ - if (status >= WSA_WAIT_EVENT_0 && status < WSA_WAIT_EVENT_0 + (DWORD) wes->n_events) - { - int i; - int j = 0; - for (i = 0; i < wes->n_events; ++i) - { - if (j >= outlen) - break; - if (WaitForSingleObject (wes->events[i], 0) == WAIT_OBJECT_0) - { - *out = wes->esr[i]; - dmsg (D_EVENT_WAIT, "WE_WAIT leave [%d,%d] rwflags=0x%04x arg=" ptr_format, - i, j, out->rwflags, (ptr_type)out->arg); - ++j; - ++out; - } - } - return j; - } - else - { - /* - * If caller specified timeout > 0, we know at this point - * that no events are set, so wait only for the first event - * (or timeout) and return at most one event_set_return object. - * - * If caller specified timeout == 0, the second call to - * WSAWaitForMultipleEvents would be redundant -- just - * return 0 indicating timeout. - */ - if (timeout > 0) - status = WSAWaitForMultipleEvents( - (DWORD) wes->n_events, - wes->events, - FALSE, - (DWORD) timeout, - FALSE); - - if (outlen >= 1 && status >= WSA_WAIT_EVENT_0 && status < WSA_WAIT_EVENT_0 + (DWORD) wes->n_events) - { - *out = wes->esr[status - WSA_WAIT_EVENT_0]; - dmsg (D_EVENT_WAIT, "WE_WAIT leave rwflags=0x%04x arg=" ptr_format, - out->rwflags, (ptr_type)out->arg); - return 1; - } - else if (status == WSA_WAIT_TIMEOUT) - return 0; - else - return -1; - } -} - -static struct event_set * -we_init (int *maxevents, unsigned int flags) -{ - struct we_set *wes; - - dmsg (D_EVENT_WAIT, "WE_INIT maxevents=%d flags=0x%08x", *maxevents, flags); - - ALLOC_OBJ_CLEAR (wes, struct we_set); - - /* set dispatch functions */ - wes->func.free = we_free; - wes->func.reset = we_reset; - wes->func.del = we_del; - wes->func.ctl = we_ctl; - wes->func.wait = we_wait; - - if (flags & EVENT_METHOD_FAST) - wes->fast = true; - wes->n_events = 0; - - /* Figure our event capacity */ - ASSERT (*maxevents > 0); - wes->capacity = min_int (*maxevents * 2, WSA_MAXIMUM_WAIT_EVENTS); - *maxevents = min_int (*maxevents, WSA_MAXIMUM_WAIT_EVENTS); - - /* Allocate space for Win32 event handles */ - ALLOC_ARRAY_CLEAR (wes->events, HANDLE, wes->capacity); - - /* Allocate space for event_set_return objects */ - ALLOC_ARRAY_CLEAR (wes->esr, struct event_set_return, wes->capacity); - - dmsg (D_EVENT_WAIT, "WE_INIT maxevents=%d capacity=%d", - *maxevents, wes->capacity); - - return (struct event_set *) wes; -} - -#endif /* WIN32 */ - -#if EPOLL - -struct ep_set -{ - struct event_set_functions func; - bool fast; - int epfd; - int maxevents; - struct epoll_event *events; -}; - -static void -ep_free (struct event_set *es) -{ - struct ep_set *eps = (struct ep_set *) es; - close (eps->epfd); - free (eps->events); - free (eps); -} - -static void -ep_reset (struct event_set *es) -{ - const struct ep_set *eps = (struct ep_set *) es; - ASSERT (eps->fast); -} - -static void -ep_del (struct event_set *es, event_t event) -{ - struct epoll_event ev; - struct ep_set *eps = (struct ep_set *) es; - - dmsg (D_EVENT_WAIT, "EP_DEL ev=%d", (int)event); - - ASSERT (!eps->fast); - CLEAR (ev); - epoll_ctl (eps->epfd, EPOLL_CTL_DEL, event, &ev); -} - -static void -ep_ctl (struct event_set *es, event_t event, unsigned int rwflags, void *arg) -{ - struct ep_set *eps = (struct ep_set *) es; - struct epoll_event ev; - - CLEAR (ev); - - ev.data.ptr = arg; - if (rwflags & EVENT_READ) - ev.events |= EPOLLIN; - if (rwflags & EVENT_WRITE) - ev.events |= EPOLLOUT; - - dmsg (D_EVENT_WAIT, "EP_CTL fd=%d rwflags=0x%04x ev=0x%08x arg=" ptr_format, - (int)event, - rwflags, - (unsigned int)ev.events, - (ptr_type)ev.data.ptr); - - if (epoll_ctl (eps->epfd, EPOLL_CTL_MOD, event, &ev) < 0) - { - if (errno == ENOENT) - { - if (epoll_ctl (eps->epfd, EPOLL_CTL_ADD, event, &ev) < 0) - msg (M_ERR, "EVENT: epoll_ctl EPOLL_CTL_ADD failed"); - } - else - msg (M_ERR, "EVENT: epoll_ctl EPOLL_CTL_MOD failed"); - } -} - -static int -ep_wait (struct event_set *es, const struct timeval *tv, struct event_set_return *out, int outlen) -{ - struct ep_set *eps = (struct ep_set *) es; - int stat; - - if (outlen > eps->maxevents) - outlen = eps->maxevents; - - stat = epoll_wait (eps->epfd, eps->events, outlen, tv_to_ms_timeout (tv)); - ASSERT (stat <= outlen); - - if (stat > 0) - { - int i; - const struct epoll_event *ev = eps->events; - struct event_set_return *esr = out; - for (i = 0; i < stat; ++i) - { - esr->rwflags = 0; - if (ev->events & (EPOLLIN|EPOLLPRI|EPOLLERR|EPOLLHUP)) - esr->rwflags |= EVENT_READ; - if (ev->events & EPOLLOUT) - esr->rwflags |= EVENT_WRITE; - esr->arg = ev->data.ptr; - dmsg (D_EVENT_WAIT, "EP_WAIT[%d] rwflags=0x%04x ev=0x%08x arg=" ptr_format, - i, esr->rwflags, ev->events, (ptr_type)ev->data.ptr); - ++ev; - ++esr; - } - } - return stat; -} - -static struct event_set * -ep_init (int *maxevents, unsigned int flags) -{ - struct ep_set *eps; - int fd; - - dmsg (D_EVENT_WAIT, "EP_INIT maxevents=%d flags=0x%08x", *maxevents, flags); - - /* open epoll file descriptor */ - fd = epoll_create (*maxevents); - if (fd < 0) - return NULL; - - ALLOC_OBJ_CLEAR (eps, struct ep_set); - - /* set dispatch functions */ - eps->func.free = ep_free; - eps->func.reset = ep_reset; - eps->func.del = ep_del; - eps->func.ctl = ep_ctl; - eps->func.wait = ep_wait; - - /* fast method ("sort of") corresponds to epoll one-shot */ - if (flags & EVENT_METHOD_FAST) - eps->fast = true; - - /* allocate space for epoll_wait return */ - ASSERT (*maxevents > 0); - eps->maxevents = *maxevents; - ALLOC_ARRAY_CLEAR (eps->events, struct epoll_event, eps->maxevents); - - /* set epoll control fd */ - eps->epfd = fd; - - return (struct event_set *) eps; -} -#endif /* EPOLL */ - -#if POLL - -struct po_set -{ - struct event_set_functions func; - bool fast; - struct pollfd *events; - void **args; - int n_events; - int capacity; -}; - -static void -po_free (struct event_set *es) -{ - struct po_set *pos = (struct po_set *) es; - free (pos->events); - free (pos->args); - free (pos); -} - -static void -po_reset (struct event_set *es) -{ - struct po_set *pos = (struct po_set *) es; - ASSERT (pos->fast); - pos->n_events = 0; -} - -static void -po_del (struct event_set *es, event_t event) -{ - struct po_set *pos = (struct po_set *) es; - int i; - - dmsg (D_EVENT_WAIT, "PO_DEL ev=%d", (int)event); - - ASSERT (!pos->fast); - for (i = 0; i < pos->n_events; ++i) - { - if (pos->events[i].fd == event) - { - int j; - for (j = i; j < pos->n_events - 1; ++j) - { - pos->events[j] = pos->events[j+1]; - pos->args[j] = pos->args[j+1]; - } - --pos->n_events; - break; - } - } -} - -static inline void -po_set_pollfd_events (struct pollfd *pfdp, unsigned int rwflags) -{ - pfdp->events = 0; - if (rwflags & EVENT_WRITE) - pfdp->events |= POLLOUT; - if (rwflags & EVENT_READ) - pfdp->events |= (POLLIN|POLLPRI); -} - -static inline bool -po_append_event (struct po_set *pos, event_t event, unsigned int rwflags, void *arg) -{ - if (pos->n_events < pos->capacity) - { - struct pollfd *pfdp = &pos->events[pos->n_events]; - pfdp->fd = event; - pos->args[pos->n_events] = arg; - po_set_pollfd_events (pfdp, rwflags); - ++pos->n_events; - return true; - } - else - return false; -} - -static void -po_ctl (struct event_set *es, event_t event, unsigned int rwflags, void *arg) -{ - struct po_set *pos = (struct po_set *) es; - - dmsg (D_EVENT_WAIT, "PO_CTL rwflags=0x%04x ev=%d arg=" ptr_format, - rwflags, (int)event, (ptr_type)arg); - - if (pos->fast) - { - if (!po_append_event (pos, event, rwflags, arg)) - goto err; - } - else - { - int i; - for (i = 0; i < pos->n_events; ++i) - { - struct pollfd *pfdp = &pos->events[i]; - if (pfdp->fd == event) - { - pos->args[i] = arg; - po_set_pollfd_events (pfdp, rwflags); - goto done; - } - } - if (!po_append_event (pos, event, rwflags, arg)) - goto err; - } - - done: - return; - - err: - msg (D_EVENT_ERRORS, "Error: poll: too many I/O wait events"); -} - -static int -po_wait (struct event_set *es, const struct timeval *tv, struct event_set_return *out, int outlen) -{ - struct po_set *pos = (struct po_set *) es; - int stat; - - stat = poll (pos->events, pos->n_events, tv_to_ms_timeout (tv)); - - ASSERT (stat <= pos->n_events); - - if (stat > 0) - { - int i, j=0; - const struct pollfd *pfdp = pos->events; - for (i = 0; i < pos->n_events && j < outlen; ++i) - { - if (pfdp->revents & (POLLIN|POLLPRI|POLLERR|POLLHUP|POLLOUT)) - { - out->rwflags = 0; - if (pfdp->revents & (POLLIN|POLLPRI|POLLERR|POLLHUP)) - out->rwflags |= EVENT_READ; - if (pfdp->revents & POLLOUT) - out->rwflags |= EVENT_WRITE; - out->arg = pos->args[i]; - dmsg (D_EVENT_WAIT, "PO_WAIT[%d,%d] fd=%d rev=0x%08x rwflags=0x%04x arg=" ptr_format " %s", - i, j, pfdp->fd, pfdp->revents, out->rwflags, (ptr_type)out->arg, pos->fast ? "" : "[scalable]"); - ++out; - ++j; - } - else if (pfdp->revents) - { - msg (D_EVENT_ERRORS, "Error: poll: unknown revents=0x%04x", (unsigned int)pfdp->revents); - } - ++pfdp; - } - return j; - } - return stat; -} - -static struct event_set * -po_init (int *maxevents, unsigned int flags) -{ - struct po_set *pos; - - dmsg (D_EVENT_WAIT, "PO_INIT maxevents=%d flags=0x%08x", *maxevents, flags); - - ALLOC_OBJ_CLEAR (pos, struct po_set); - - /* set dispatch functions */ - pos->func.free = po_free; - pos->func.reset = po_reset; - pos->func.del = po_del; - pos->func.ctl = po_ctl; - pos->func.wait = po_wait; - - if (flags & EVENT_METHOD_FAST) - pos->fast = true; - - pos->n_events = 0; - - /* Figure our event capacity */ - ASSERT (*maxevents > 0); - pos->capacity = *maxevents; - - /* Allocate space for pollfd structures to be passed to poll() */ - ALLOC_ARRAY_CLEAR (pos->events, struct pollfd, pos->capacity); - - /* Allocate space for event_set_return objects */ - ALLOC_ARRAY_CLEAR (pos->args, void *, pos->capacity); - - return (struct event_set *) pos; -} -#endif /* POLL */ - -#if SELECT - -struct se_set -{ - struct event_set_functions func; - bool fast; - fd_set readfds; - fd_set writefds; - void **args; /* allocated to capacity size */ - int maxfd; /* largest fd seen so far, always < capacity */ - int capacity; /* fixed largest fd + 1 */ -}; - -static void -se_free (struct event_set *es) -{ - struct se_set *ses = (struct se_set *) es; - free (ses->args); - free (ses); -} - -static void -se_reset (struct event_set *es) -{ - struct se_set *ses = (struct se_set *) es; - int i; - ASSERT (ses->fast); - - dmsg (D_EVENT_WAIT, "SE_RESET"); - - FD_ZERO (&ses->readfds); - FD_ZERO (&ses->writefds); - for (i = 0; i <= ses->maxfd; ++i) - ses->args[i] = NULL; - ses->maxfd = -1; -} - -static void -se_del (struct event_set *es, event_t event) -{ - struct se_set *ses = (struct se_set *) es; - ASSERT (!ses->fast); - - dmsg (D_EVENT_WAIT, "SE_DEL ev=%d", (int)event); - - if (event >= 0 && event < ses->capacity) - { - FD_CLR (event, &ses->readfds); - FD_CLR (event, &ses->writefds); - ses->args[event] = NULL; - } - else - msg (D_EVENT_ERRORS, "Error: select/se_del: too many I/O wait events"); - return; -} - -static void -se_ctl (struct event_set *es, event_t event, unsigned int rwflags, void *arg) -{ - struct se_set *ses = (struct se_set *) es; - - dmsg (D_EVENT_WAIT, "SE_CTL rwflags=0x%04x ev=%d fast=%d cap=%d maxfd=%d arg=" ptr_format, - rwflags, (int)event, (int)ses->fast, ses->capacity, ses->maxfd, (ptr_type)arg); - - if (event >= 0 && event < ses->capacity) - { - ses->maxfd = max_int (event, ses->maxfd); - ses->args[event] = arg; - if (ses->fast) - { - if (rwflags & EVENT_READ) - FD_SET (event, &ses->readfds); - if (rwflags & EVENT_WRITE) - FD_SET (event, &ses->writefds); - } - else - { - if (rwflags & EVENT_READ) - FD_SET (event, &ses->readfds); - else - FD_CLR (event, &ses->readfds); - if (rwflags & EVENT_WRITE) - FD_SET (event, &ses->writefds); - else - FD_CLR (event, &ses->writefds); - } - } - else - { - msg (D_EVENT_ERRORS, "Error: select: too many I/O wait events, fd=%d cap=%d", - (int) event, - ses->capacity); - } -} - -static int -se_wait_return (struct se_set *ses, - fd_set *read, - fd_set *write, - struct event_set_return *out, - int outlen) -{ - int i, j = 0; - for (i = 0; i <= ses->maxfd && j < outlen; ++i) - { - const bool r = FD_ISSET (i, read); - const bool w = FD_ISSET (i, write); - if (r || w) - { - out->rwflags = 0; - if (r) - out->rwflags |= EVENT_READ; - if (w) - out->rwflags |= EVENT_WRITE; - out->arg = ses->args[i]; - dmsg (D_EVENT_WAIT, "SE_WAIT[%d,%d] rwflags=0x%04x arg=" ptr_format, - i, j, out->rwflags, (ptr_type)out->arg); - ++out; - ++j; - } - } - return j; -} - -static int -se_wait_fast (struct event_set *es, const struct timeval *tv, struct event_set_return *out, int outlen) -{ - struct se_set *ses = (struct se_set *) es; - struct timeval tv_tmp = *tv; - int stat; - - dmsg (D_EVENT_WAIT, "SE_WAIT_FAST maxfd=%d tv=%d/%d", - ses->maxfd, - (int)tv_tmp.tv_sec, - (int)tv_tmp.tv_usec); - - stat = select (ses->maxfd + 1, &ses->readfds, &ses->writefds, NULL, &tv_tmp); - - if (stat > 0) - stat = se_wait_return (ses, &ses->readfds, &ses->writefds, out, outlen); - - return stat; -} - -static int -se_wait_scalable (struct event_set *es, const struct timeval *tv, struct event_set_return *out, int outlen) -{ - struct se_set *ses = (struct se_set *) es; - struct timeval tv_tmp = *tv; - fd_set read = ses->readfds; - fd_set write = ses->writefds; - int stat; - - dmsg (D_EVENT_WAIT, "SE_WAIT_SCALEABLE maxfd=%d tv=%d/%d", - ses->maxfd, (int)tv_tmp.tv_sec, (int)tv_tmp.tv_usec); - - stat = select (ses->maxfd + 1, &read, &write, NULL, &tv_tmp); - - if (stat > 0) - stat = se_wait_return (ses, &read, &write, out, outlen); - - return stat; -} - -static struct event_set * -se_init (int *maxevents, unsigned int flags) -{ - struct se_set *ses; - - dmsg (D_EVENT_WAIT, "SE_INIT maxevents=%d flags=0x%08x", *maxevents, flags); - - ALLOC_OBJ_CLEAR (ses, struct se_set); - - /* set dispatch functions */ - ses->func.free = se_free; - ses->func.reset = se_reset; - ses->func.del = se_del; - ses->func.ctl = se_ctl; - ses->func.wait = se_wait_scalable; - - if (flags & EVENT_METHOD_FAST) - { - ses->fast = true; - ses->func.wait = se_wait_fast; - } - - /* Select needs to be passed this value + 1 */ - ses->maxfd = -1; - - /* Set our event capacity */ - ASSERT (*maxevents > 0); - *maxevents = min_int (*maxevents, SELECT_MAX_FDS); - ses->capacity = SELECT_MAX_FDS; - - /* Allocate space for event_set_return void * args */ - ALLOC_ARRAY_CLEAR (ses->args, void *, ses->capacity); - - return (struct event_set *) ses; -} -#endif /* SELECT */ - -static struct event_set * -event_set_init_simple (int *maxevents, unsigned int flags) -{ - struct event_set *ret = NULL; -#ifdef WIN32 - ret = we_init (maxevents, flags); -#elif POLL && SELECT -#if 0 /* Define to 1 if EVENT_METHOD_US_TIMEOUT should cause select to be favored over poll */ - if (flags & EVENT_METHOD_US_TIMEOUT) - ret = se_init (maxevents, flags); -#endif -# ifdef SELECT_PREFERRED_OVER_POLL - if (!ret) - ret = se_init (maxevents, flags); - if (!ret) - ret = po_init (maxevents, flags); -# else - if (!ret) - ret = po_init (maxevents, flags); - if (!ret) - ret = se_init (maxevents, flags); -# endif -#elif POLL - ret = po_init (maxevents, flags); -#elif SELECT - ret = se_init (maxevents, flags); -#else -#error At least one of poll, select, or WSAWaitForMultipleEvents must be supported by the kernel -#endif - ASSERT (ret); - return ret; -} - -static struct event_set * -event_set_init_scalable (int *maxevents, unsigned int flags) -{ - struct event_set *ret = NULL; -#if EPOLL - ret = ep_init (maxevents, flags); - if (!ret) - { - msg (M_WARN, "Note: sys_epoll API is unavailable, falling back to poll/select API"); - ret = event_set_init_simple (maxevents, flags); - } -#else - ret = event_set_init_simple (maxevents, flags); -#endif - ASSERT (ret); - return ret; -} - -struct event_set * -event_set_init (int *maxevents, unsigned int flags) -{ - if (flags & EVENT_METHOD_FAST) - return event_set_init_simple (maxevents, flags); - else - return event_set_init_scalable (maxevents, flags); -} |