diff options
Diffstat (limited to 'src/libmowgli/eventloop/windows_pollops.c')
-rw-r--r-- | src/libmowgli/eventloop/windows_pollops.c | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/src/libmowgli/eventloop/windows_pollops.c b/src/libmowgli/eventloop/windows_pollops.c new file mode 100644 index 0000000..f1c9c0f --- /dev/null +++ b/src/libmowgli/eventloop/windows_pollops.c @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2012 William Pitcock <nenolod@dereferenced.org>. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mowgli.h" + +#ifdef _WIN32 + +#define DEFAULT_SOCKETMAX (2048) + +typedef struct { + WSAEVENT *pfd; + unsigned short pfd_size; + unsigned short last_slot; + mowgli_eventloop_pollable_t **pollables; +} mowgli_winsock_eventloop_private_t; + +static WSADATA wsock_env; + +void mowgli_winsock_bootstrap(void) +{ + int r; + + r = WSAStartup((short) 0x202, &wsock_env); + if (r != 0) + { + printf("mowgli bootstrap failure (win32): %d\n", r); + exit(EXIT_FAILURE); + } + + if (!wsock_env.iMaxSockets) + wsock_env.iMaxSockets = DEFAULT_SOCKETMAX; + else + wsock_env.iMaxSockets -= (wsock_env.iMaxSockets % MAXIMUM_WAIT_OBJECTS); +} + +static void mowgli_winsock_eventloop_pollsetup(mowgli_eventloop_t *eventloop) +{ + unsigned short i; + mowgli_winsock_eventloop_private_t *priv; + + return_if_fail(wsock_env.iMaxSockets > 0); + + priv = mowgli_alloc(sizeof(mowgli_winsock_eventloop_private_t)); + eventloop->poller = priv; + + priv->pfd_size = wsock_env.iMaxSockets; + priv->pfd = mowgli_alloc(sizeof(WSAEVENT) * priv->pfd_size); + priv->pollables = mowgli_alloc(sizeof(mowgli_eventloop_pollable_t *) * priv->pfd_size); + + /* sanitize NT port handle values to a known-good default */ + for (i = 0; i < priv->pfd_size; i++) + { + priv->pfd[i] = INVALID_HANDLE_VALUE; + priv->pollables[i] = NULL; + } + + return; +} + +static unsigned short mowgli_winsock_eventloop_find_slot(mowgli_winsock_eventloop_private_t *priv) +{ + unsigned short i = 1; + + return_val_if_fail(priv != NULL, 0); + + if (priv->last_slot) + i = priv->last_slot; + + for (; i < priv->pfd_size; i++) + { + if (priv->pfd[i] == INVALID_HANDLE_VALUE) + { + priv->last_slot = i; + return i; + } + } + + /* miss, try from beginning. */ + for (i = 1; i < priv->pfd_size; i++) + { + if (priv->pfd[i] == INVALID_HANDLE_VALUE) + { + priv->last_slot = i; + return i; + } + } + + /* if this happens, we're boned... */ + mowgli_log("out of handles for eventloop %p, aborting\n", priv); + abort(); + + return 0; +} + +static void mowgli_winsock_eventloop_pollshutdown(mowgli_eventloop_t *eventloop) +{ + unsigned short i; + mowgli_winsock_eventloop_private_t *priv; + + return_if_fail(eventloop != NULL); + + priv = eventloop->poller; + + for (i = 0; i < priv->pfd_size; i++) + { + WSACloseEvent(priv->pfd[i]); + priv->pfd[i] = INVALID_HANDLE_VALUE; + } + + mowgli_free(priv->pfd); + mowgli_free(priv); + + return; +} + +static void mowgli_winsock_eventloop_destroy(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable) +{ + mowgli_winsock_eventloop_private_t *priv; + + return_if_fail(eventloop != NULL); + return_if_fail(pollable != NULL); + + priv = eventloop->poller; + + if (pollable->slot) + { + WSAEventSelect(pollable->fd, priv->pfd[pollable->slot], 0); + WSACloseEvent(priv->pfd[pollable->slot]); + + priv->pfd[pollable->slot] = INVALID_HANDLE_VALUE; + priv->pollables[pollable->slot] = NULL; + } + + pollable->slot = 0; + pollable->events = 0; +} + +static void mowgli_winsock_eventloop_setselect(mowgli_eventloop_t *eventloop, mowgli_eventloop_pollable_t *pollable, mowgli_eventloop_io_dir_t dir, mowgli_eventloop_io_cb_t *event_function) +{ + mowgli_winsock_eventloop_private_t *priv; + unsigned int old_flags; + + return_if_fail(eventloop != NULL); + return_if_fail(pollable != NULL); + + priv = eventloop->poller; + old_flags = pollable->events; + +#ifdef DEBUG + mowgli_log("setselect %p fd %d func %p", pollable, pollable->fd, event_function); +#endif + + switch (dir) + { + case MOWGLI_EVENTLOOP_IO_READ: + pollable->read_function = event_function; + pollable->events |= (FD_READ | FD_CLOSE | FD_ACCEPT | FD_OOB); + break; + case MOWGLI_EVENTLOOP_IO_WRITE: + pollable->write_function = event_function; + pollable->events |= (FD_WRITE | FD_CONNECT | FD_CLOSE); + break; + default: + mowgli_log("unhandled pollable direction %d", dir); + break; + } + +#ifdef DEBUG + mowgli_log("%p -> read %p : write %p", pollable, pollable->read_function, pollable->write_function); +#endif + + if (pollable->read_function == NULL) + pollable->events &= ~(FD_READ | FD_CLOSE | FD_ACCEPT | FD_OOB); + + if (pollable->write_function == NULL) + pollable->events &= ~(FD_WRITE | FD_CONNECT | FD_CLOSE); + + if (old_flags == 0 && pollable->events == 0) + return; + else if (pollable->events <= 0) + { + mowgli_winsock_eventloop_destroy(eventloop, pollable); + return; + } + + /* set up the HANDLE if we have not already */ + if (!pollable->slot) + { + pollable->slot = mowgli_winsock_eventloop_find_slot(priv); + + priv->pfd[pollable->slot] = WSACreateEvent(); + priv->pollables[pollable->slot] = pollable; + } + + if (WSAEventSelect(pollable->fd, priv->pfd[pollable->slot], pollable->events) != 0) + { + if (mowgli_eventloop_ignore_errno(WSAGetLastError())) + return; + + mowgli_log("mowgli_winsock_eventloop_setselect(): WSAEventSelect failed: %d", WSAGetLastError()); + } + + return; +} + +static void mowgli_winsock_eventloop_select(mowgli_eventloop_t *eventloop, int delay) +{ + mowgli_winsock_eventloop_private_t *priv; + int i, j; + DWORD result; + + return_if_fail(eventloop != NULL); + + priv = eventloop->poller; + + return_if_fail(priv->pfd_size % MAXIMUM_WAIT_OBJECTS == 0); + + for (i = 0; i < priv->pfd_size; i += MAXIMUM_WAIT_OBJECTS) + { + result = WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS, priv->pfd + i, FALSE, delay); + + if (result == WAIT_FAILED) + { + if (mowgli_eventloop_ignore_errno(WSAGetLastError())) + return; + + mowgli_log("mowgli_winsock_eventloop_select(): WaitForMultipleObjects failed: %d", WSAGetLastError()); + return; + } + + for (j = (result - WAIT_OBJECT_0); j < MAXIMUM_WAIT_OBJECTS; j++) + { + mowgli_eventloop_pollable_t *pollable = priv->pollables[i + j]; + WSANETWORKEVENTS events; + + WSAEnumNetworkEvents(pollable->fd, priv->pfd[pollable->slot], &events); + + if (events.lNetworkEvents & (FD_READ | FD_CLOSE | FD_ACCEPT | FD_OOB) && pollable->read_function != NULL) + pollable->read_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_READ, pollable->userdata); + + if (events.lNetworkEvents & (FD_WRITE | FD_CONNECT | FD_CLOSE) && pollable->write_function != NULL) + pollable->write_function(eventloop, pollable, MOWGLI_EVENTLOOP_IO_WRITE, pollable->userdata); + } + } + + mowgli_eventloop_synchronize(eventloop); +} + +mowgli_eventloop_ops_t _mowgli_winsock_pollops = { + .timeout_once = mowgli_simple_eventloop_timeout_once, + .run_once = mowgli_simple_eventloop_run_once, + .pollsetup = mowgli_winsock_eventloop_pollsetup, + .pollshutdown = mowgli_winsock_eventloop_pollshutdown, + .setselect = mowgli_winsock_eventloop_setselect, + .select = mowgli_winsock_eventloop_select, + .destroy = mowgli_winsock_eventloop_destroy, +}; + +#endif |