📄 event.c
字号:
/************************************************************************* event.c** Abstraction of select call into "event-handling" to make programming* easier.** Copyright (C) 2001 Roaring Penguin Software Inc.** This program may be distributed according to the terms of the GNU* General Public License, version 2 or (at your option) any later version.** LIC: GPL************************************************************************/static char const RCSID[] ="$Id: event.c,v 1.2 2002/04/09 17:28:40 dfs Exp $";#include "event.h"#include <stdlib.h>#include <errno.h>static void DestroySelector(EventSelector *es);static void DestroyHandler(EventHandler *eh);static void DoPendingChanges(EventSelector *es);/*********************************************************************** %FUNCTION: Event_CreateSelector* %ARGUMENTS:* None* %RETURNS:* A newly-allocated EventSelector, or NULL if out of memory.* %DESCRIPTION:* Creates a new EventSelector.***********************************************************************/EventSelector *Event_CreateSelector(void){ EventSelector *es = malloc(sizeof(EventSelector)); if (!es) return NULL; es->handlers = NULL; es->nestLevel = 0; es->destroyPending = 0; es->opsPending = 0; EVENT_DEBUG(("CreateSelector() -> %p\n", (void *) es)); return es;}/*********************************************************************** %FUNCTION: Event_DestroySelector* %ARGUMENTS:* es -- EventSelector to destroy* %RETURNS:* Nothing* %DESCRIPTION:* Destroys an EventSelector. Destruction may be delayed if we* are in the HandleEvent function.***********************************************************************/voidEvent_DestroySelector(EventSelector *es){ if (es->nestLevel) { es->destroyPending = 1; es->opsPending = 1; return; } DestroySelector(es);}/*********************************************************************** %FUNCTION: Event_HandleEvent* %ARGUMENTS:* es -- EventSelector* %RETURNS:* 0 if OK, non-zero on error. errno is set appropriately.* %DESCRIPTION:* Handles a single event (uses select() to wait for an event.)***********************************************************************/intEvent_HandleEvent(EventSelector *es){ fd_set readfds, writefds; fd_set *rd, *wr; unsigned int flags; struct timeval abs_timeout, now; struct timeval timeout; struct timeval *tm; EventHandler *eh; int r = 0; int errno_save = 0; int foundTimeoutEvent = 0; int foundReadEvent = 0; int foundWriteEvent = 0; int maxfd = -1; int pastDue; EVENT_DEBUG(("Enter Event_HandleEvent(es=%p)\n", (void *) es)); /* Build the select sets */ FD_ZERO(&readfds); FD_ZERO(&writefds); eh = es->handlers; for (eh=es->handlers; eh; eh=eh->next) { if (eh->flags & EVENT_FLAG_DELETED) continue; if (eh->flags & EVENT_FLAG_READABLE) { foundReadEvent = 1; FD_SET(eh->fd, &readfds); if (eh->fd > maxfd) maxfd = eh->fd; } if (eh->flags & EVENT_FLAG_WRITEABLE) { foundWriteEvent = 1; FD_SET(eh->fd, &writefds); if (eh->fd > maxfd) maxfd = eh->fd; } if (eh->flags & EVENT_TIMER_BITS) { if (!foundTimeoutEvent) { abs_timeout = eh->tmout; foundTimeoutEvent = 1; } else { if (eh->tmout.tv_sec < abs_timeout.tv_sec || (eh->tmout.tv_sec == abs_timeout.tv_sec && eh->tmout.tv_usec < abs_timeout.tv_usec)) { abs_timeout = eh->tmout; } } } } if (foundReadEvent) { rd = &readfds; } else { rd = NULL; } if (foundWriteEvent) { wr = &writefds; } else { wr = NULL; } if (foundTimeoutEvent) { gettimeofday(&now, NULL); /* Convert absolute timeout to relative timeout for select */ timeout.tv_usec = abs_timeout.tv_usec - now.tv_usec; timeout.tv_sec = abs_timeout.tv_sec - now.tv_sec; if (timeout.tv_usec < 0) { timeout.tv_usec += 1000000; timeout.tv_sec--; } if (timeout.tv_sec < 0 || (timeout.tv_sec == 0 && timeout.tv_usec < 0)) { timeout.tv_sec = 0; timeout.tv_usec = 0; } tm = &timeout; } else { tm = NULL; } if (foundReadEvent || foundWriteEvent || foundTimeoutEvent) { for(;;) { r = select(maxfd+1, rd, wr, NULL, tm); if (r < 0) { if (errno == EINTR) continue; } break; } } if (foundTimeoutEvent) gettimeofday(&now, NULL); errno_save = errno; es->nestLevel++; if (r >= 0) { /* Call handlers */ for (eh=es->handlers; eh; eh=eh->next) { /* Pending delete for this handler? Ignore it */ if (eh->flags & EVENT_FLAG_DELETED) continue; flags = 0; if ((eh->flags & EVENT_FLAG_READABLE) && FD_ISSET(eh->fd, &readfds)) { flags |= EVENT_FLAG_READABLE; } if ((eh->flags & EVENT_FLAG_WRITEABLE) && FD_ISSET(eh->fd, &writefds)) { flags |= EVENT_FLAG_WRITEABLE; } if (eh->flags & EVENT_TIMER_BITS) { pastDue = (eh->tmout.tv_sec < now.tv_sec || (eh->tmout.tv_sec == now.tv_sec && eh->tmout.tv_usec <= now.tv_usec)); if (pastDue) { flags |= EVENT_TIMER_BITS; if (eh->flags & EVENT_FLAG_TIMER) { /* Timer events are only called once */ es->opsPending = 1; eh->flags |= EVENT_FLAG_DELETED; } } } /* Do callback */ if (flags) { EVENT_DEBUG(("Enter callback: eh=%p flags=%u\n", eh, flags)); eh->fn(es, eh->fd, flags, eh->data); EVENT_DEBUG(("Leave callback: eh=%p flags=%u\n", eh, flags)); } } } es->nestLevel--; if (!es->nestLevel && es->opsPending) { DoPendingChanges(es); } errno = errno_save; return r;}/*********************************************************************** %FUNCTION: Event_AddHandler* %ARGUMENTS:* es -- event selector* fd -- file descriptor to watch* flags -- combination of EVENT_FLAG_READABLE and EVENT_FLAG_WRITEABLE* fn -- callback function to call when event is triggered* data -- extra data to pass to callback function* %RETURNS:* A newly-allocated EventHandler, or NULL.***********************************************************************/EventHandler *Event_AddHandler(EventSelector *es, int fd, unsigned int flags, EventCallbackFunc fn, void *data){ EventHandler *eh; /* Specifically disable timer and deleted flags */ flags &= (~(EVENT_TIMER_BITS | EVENT_FLAG_DELETED)); /* Bad file descriptor */ if (fd < 0) { errno = EBADF; return NULL; } eh = malloc(sizeof(EventHandler)); if (!eh) return NULL; eh->fd = fd; eh->flags = flags; eh->tmout.tv_usec = 0; eh->tmout.tv_sec = 0; eh->fn = fn; eh->data = data; /* Add immediately. This is safe even if we are in a handler. */ eh->next = es->handlers; es->handlers = eh; EVENT_DEBUG(("Event_AddHandler(es=%p, fd=%d, flags=%u) -> %p\n", es, fd, flags, eh)); return eh;}/*********************************************************************** %FUNCTION: Event_AddHandlerWithTimeout* %ARGUMENTS:* es -- event selector* fd -- file descriptor to watch* flags -- combination of EVENT_FLAG_READABLE and EVENT_FLAG_WRITEABLE* t -- Timeout after which to call handler, even if not readable/writable.* If t.tv_sec < 0, calls normal Event_AddHandler with no timeout.* fn -- callback function to call when event is triggered* data -- extra data to pass to callback function* %RETURNS:* A newly-allocated EventHandler, or NULL.***********************************************************************/EventHandler *Event_AddHandlerWithTimeout(EventSelector *es, int fd, unsigned int flags, struct timeval t, EventCallbackFunc fn, void *data){ EventHandler *eh; struct timeval now; /* If timeout is negative, just do normal non-timing-out event */ if (t.tv_sec < 0 || t.tv_usec < 0) { return Event_AddHandler(es, fd, flags, fn, data); } /* Specifically disable timer and deleted flags */ flags &= (~(EVENT_FLAG_TIMER | EVENT_FLAG_DELETED)); flags |= EVENT_FLAG_TIMEOUT; /* Bad file descriptor? */ if (fd < 0) { errno = EBADF; return NULL; } /* Bad timeout? */ if (t.tv_usec >= 1000000) { errno = EINVAL; return NULL; } eh = malloc(sizeof(EventHandler)); if (!eh) return NULL; /* Convert time interval to absolute time */ gettimeofday(&now, NULL); t.tv_sec += now.tv_sec; t.tv_usec += now.tv_usec;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -