X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=ircd%2Fircd_events.c;h=f21ecdbe29ca8c775f9e93da66e46b5dcccc28b3;hb=refs%2Fheads%2Fupstream;hp=6befeaec096ff863bdbc1cdf810c62c80afcdf31;hpb=fda30451cac5936729c683d38a700f4928812c6f;p=ircu2.10.12-pk.git diff --git a/ircd/ircd_events.c b/ircd/ircd_events.c index 6befeae..f21ecdb 100644 --- a/ircd/ircd_events.c +++ b/ircd/ircd_events.c @@ -15,8 +15,10 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id$ + */ +/** @file + * @brief Implementation of event loop mid-layer. + * @version $Id$ */ #include "config.h" @@ -28,17 +30,19 @@ #include "ircd_snprintf.h" #include "s_debug.h" -#include +/* #include -- Now using assert in ircd_log.h */ #include +#include #include -#define SIGS_PER_SOCK 10 /* number of signals to process per socket +#define SIGS_PER_SOCK 10 /**< number of signals to process per socket readable event */ #ifdef USE_KQUEUE extern struct Engine engine_kqueue; #define ENGINE_KQUEUE &engine_kqueue, #else +/** Address of kqueue engine (if used). */ #define ENGINE_KQUEUE #endif /* USE_KQUEUE */ @@ -46,41 +50,56 @@ extern struct Engine engine_kqueue; extern struct Engine engine_devpoll; #define ENGINE_DEVPOLL &engine_devpoll, #else +/** Address of /dev/poll engine (if used). */ #define ENGINE_DEVPOLL #endif /* USE_DEVPOLL */ +#ifdef USE_EPOLL +extern struct Engine engine_epoll; +#define ENGINE_EPOLL &engine_epoll, +#else +/** Address of epoll engine (if used). */ +#define ENGINE_EPOLL +#endif /* USE_EPOLL */ + #ifdef USE_POLL extern struct Engine engine_poll; +/** Address of fallback (poll) engine. */ #define ENGINE_FALLBACK &engine_poll, #else extern struct Engine engine_select; +/** Address of fallback (select) engine. */ #define ENGINE_FALLBACK &engine_select, #endif /* USE_POLL */ -/* list of engines to try */ +/** list of engines to try */ static const struct Engine *evEngines[] = { ENGINE_KQUEUE + ENGINE_EPOLL ENGINE_DEVPOLL ENGINE_FALLBACK 0 }; -/* signal routines pipe data */ +/** Signal routines pipe data. + * This is used if an engine does not implement signal handling itself + * (when Engine::eng_signal is NULL). + */ static struct { - int fd; /* signal routine's fd */ - struct Socket sock; /* and its struct Socket */ + int fd; /**< signal routine's fd */ + struct Socket sock; /**< and its struct Socket */ } sigInfo = { -1 }; -/* All the thread info */ +/** All the thread info */ static struct { - struct Generators gens; /* List of all generators */ - struct Event* events_free; /* struct Event free list */ - unsigned int events_alloc; /* count of allocated struct Events */ - const struct Engine* engine; /* core engine being used */ + struct Generators gens; /**< List of all generators */ + struct Event* events_free; /**< struct Event free list */ + unsigned int events_alloc; /**< count of allocated struct Events */ + const struct Engine* engine; /**< core engine being used */ #ifdef IRCD_THREADED - struct GenHeader* genq_head; /* head of generator event queue */ - struct GenHeader* genq_tail; /* tail of generator event queue */ - unsigned int genq_count; /* count of generators on queue */ + struct GenHeader* genq_head; /**< head of generator event queue */ + struct GenHeader* genq_tail; /**< tail of generator event queue */ + unsigned int genq_count; /**< count of generators on queue */ #endif } evInfo = { { 0, 0, 0 }, @@ -90,7 +109,13 @@ static struct { #endif }; -/* Initialize a struct GenHeader */ +/** Initialize a struct GenHeader. + * @param[in,out] gen GenHeader to initialize. + * @param[in] call Callback for generated events. + * @param[in] data User data pointer. + * @param[in] next Pointer to next generator. + * @param[in,out] prev_p Pointer to previous pointer for this list. + */ static void gen_init(struct GenHeader* gen, EventCallBack call, void* data, struct GenHeader* next, struct GenHeader** prev_p) @@ -118,7 +143,10 @@ gen_init(struct GenHeader* gen, EventCallBack call, void* data, } } -/* Execute an event; optimizations should inline this */ +/** Execute an event. + * Optimizations should inline this. + * @param[in] event Event to execute. + */ static void event_execute(struct Event* event) { @@ -128,6 +156,8 @@ event_execute(struct Event* event) if (event->ev_type == ET_DESTROY) /* turn off active flag *before* destroy */ event->ev_gen.gen_header->gh_flags &= ~GEN_ACTIVE; + if (event->ev_type == ET_ERROR) /* turn on error flag before callback */ + event->ev_gen.gen_header->gh_flags |= GEN_ERROR; (*event->ev_gen.gen_header->gh_call)(event); /* execute the event */ @@ -148,7 +178,7 @@ event_execute(struct Event* event) } #ifndef IRCD_THREADED -/* we synchronously execute the event when not threaded */ +/** we synchronously execute the event when not threaded */ #define event_add(event) \ do { \ struct Event* _ev = (event); \ @@ -158,7 +188,9 @@ do { \ } while (0) #else -/* add an event to the work queue */ +/** Add an event to the work queue. + * @param[in] event Event to enqueue. + */ /* This is just a placeholder; don't expect ircd to be threaded soon */ /* There should be locks all over the place in here */ static void @@ -208,14 +240,17 @@ event_add(struct Event* event) } #endif /* IRCD_THREADED */ -/* Place a timer in the correct spot on the queue */ +/** Place a timer in the correct spot on the queue. + * @param[in] timer Timer to enqueue. + */ static void timer_enqueue(struct Timer* timer) { - struct Timer** ptr_p; + struct GenHeader** ptr_p; assert(0 != timer); assert(0 == timer->t_header.gh_prev_p); /* not already on queue */ + assert(timer->t_header.gh_flags & GEN_ACTIVE); /* timer is active */ /* Calculate expire time */ switch (timer->t_type) { @@ -230,19 +265,21 @@ timer_enqueue(struct Timer* timer) /* Find a slot to insert timer */ for (ptr_p = &evInfo.gens.g_timer; ; - ptr_p = (struct Timer**) &(*ptr_p)->t_header.gh_next) - if (!*ptr_p || timer->t_expire < (*ptr_p)->t_expire) + ptr_p = &(*ptr_p)->gh_next) + if (!*ptr_p || timer->t_expire < ((struct Timer*)*ptr_p)->t_expire) break; /* link it in the right place */ - timer->t_header.gh_next = (struct GenHeader*) *ptr_p; - timer->t_header.gh_prev_p = (struct GenHeader**) ptr_p; + timer->t_header.gh_next = *ptr_p; + timer->t_header.gh_prev_p = ptr_p; if (*ptr_p) - (*ptr_p)->t_header.gh_prev_p = &timer->t_header.gh_next; - *ptr_p = timer; + (*ptr_p)->gh_prev_p = &timer->t_header.gh_next; + *ptr_p = &timer->t_header; } -/* signal handler for writing signal notification to pipe */ +/** &Signal handler for writing signal notification to pipe. + * @param[in] sig Signal number that just happened. + */ static void signal_handler(int sig) { @@ -255,13 +292,15 @@ signal_handler(int sig) write(sigInfo.fd, &c, 1); } -/* callback for signal "socket" events */ +/** Callback for signal "socket" (really pipe) events. + * @param[in] event Event activity descriptor. + */ static void signal_callback(struct Event* event) { unsigned char sigstr[SIGS_PER_SOCK]; int sig, n_sigs, i; - struct Signal* ptr; + struct GenHeader* ptr; assert(event->ev_type == ET_READ); /* readable events only */ @@ -271,8 +310,8 @@ signal_callback(struct Event* event) sig = (int) sigstr[i]; /* get signal */ for (ptr = evInfo.gens.g_signal; ptr; - ptr = (struct Signal*) ptr->sig_header.gh_next) - if (ptr->sig_signal == sig) /* find its descriptor... */ + ptr = ptr->gh_next) + if (((struct Signal*)ptr)->sig_signal == sig) /* find its descriptor... */ break; if (ptr) @@ -280,7 +319,9 @@ signal_callback(struct Event* event) } } -/* Remove something from its queue */ +/** Remove a generator from its queue. + * @param[in] arg Pointer to a GenHeader to dequeue. + */ void gen_dequeue(void* arg) { @@ -295,7 +336,9 @@ gen_dequeue(void* arg) gen->gh_prev_p = 0; } -/* Initializes the event system */ +/** Initializes the event system. + * @param[in] max_sockets Maximum number of sockets to support. + */ void event_init(int max_sockets) { @@ -325,7 +368,7 @@ event_init(int max_sockets) } } -/* Do the event loop */ +/** Do the event loop. */ void event_loop(void) { @@ -335,7 +378,11 @@ event_loop(void) (*evInfo.engine->eng_loop)(&evInfo.gens); } -/* Generate an event and add it to the queue (or execute it) */ +/** Generate an event and add it to the queue (or execute it). + * @param[in] type Type of event to generate. + * @param[in] arg Pointer to an event generator (GenHeader). + * @param[in] data Extra data for event. + */ void event_generate(enum EventType type, void* arg, int data) { @@ -367,7 +414,53 @@ event_generate(enum EventType type, void* arg, int data) event_add(ptr); /* add event to queue */ } -/* Add a timer to be processed */ +#if 0 +/* Try to verify the timer list */ +void +timer_verify(void) +{ + struct Timer* ptr; + struct Timer** ptr_p = &evInfo.gens.g_timer; + time_t lasttime = 0; + + for (ptr = evInfo.gens.g_timer; ptr; + ptr = (struct Timer*) ptr->t_header.gh_next) { + /* verify timer is supposed to be in the list */ + assert(ptr->t_header.gh_prev_p); + /* verify timer is correctly ordered */ + assert((struct Timer**) ptr->t_header.gh_prev_p == ptr_p); + /* verify timer is active */ + assert(ptr->t_header.gh_flags & GEN_ACTIVE); + /* verify timer ordering is correct */ + assert(lasttime <= ptr->t_expire); + + lasttime = ptr->t_expire; /* store time for ordering check */ + ptr_p = (struct Timer**) &ptr->t_header.gh_next; /* store prev pointer */ + } +} +#endif + +/** Initialize a timer structure. + * @param[in,out] timer Timer to initialize. + * @return The pointer \a timer. + */ +struct Timer* +timer_init(struct Timer* timer) +{ + gen_init(&timer->t_header, 0, 0, 0, 0); + + timer->t_header.gh_flags = 0; /* turn off active flag */ + + return timer; /* convenience return */ +} + +/** Add a timer to be processed. + * @param[in] timer Timer to add. + * @param[in] call Callback for when the timer expires or is removed. + * @param[in] data User data pointer for the timer. + * @param[in] type Timer type. + * @param[in] value Timer expiration, duration or interval (per \a type). + */ void timer_add(struct Timer* timer, EventCallBack call, void* data, enum TimerType type, time_t value) @@ -379,36 +472,47 @@ timer_add(struct Timer* timer, EventCallBack call, void* data, timer_to_name(type))); /* initialize a timer... */ - gen_init((struct GenHeader*) timer, call, data, 0, 0); + timer->t_header.gh_flags |= GEN_ACTIVE; + if (timer->t_header.gh_flags & GEN_MARKED) + timer->t_header.gh_flags |= GEN_READD; + + timer->t_header.gh_ref = 0; + timer->t_header.gh_call = call; + timer->t_header.gh_data = data; timer->t_type = type; timer->t_value = value; timer->t_expire = 0; - timer_enqueue(timer); /* and enqueue it */ + if (!(timer->t_header.gh_flags & GEN_MARKED)) + timer_enqueue(timer); /* and enqueue it */ } -/* Remove a timer from the processing queue */ +/** Remove a timer from the processing queue. + * @param[in] timer Timer to remove. + */ void timer_del(struct Timer* timer) { assert(0 != timer); - if (timer->t_header.gh_flags & GEN_MARKED) - return; /* timer already marked for destruction */ + timer->t_header.gh_flags &= ~GEN_READD; - timer->t_header.gh_flags |= GEN_DESTROY; + if (timer->t_header.gh_flags & GEN_MARKED) + return; /* timer is being used */ Debug((DEBUG_LIST, "Deleting timer %p (type %s)", timer, timer_to_name(timer->t_type))); - if (!timer->t_header.gh_ref) { /* not in use; destroy right now */ - gen_dequeue(timer); - event_generate(ET_DESTROY, timer, 0); - } + gen_dequeue(timer); + event_generate(ET_DESTROY, timer, 0); } -/* Change the time a timer expires */ +/** Change the time a timer expires. + * @param[in] timer Timer to update. + * @param[in] type New timer type. + * @param[in] value New timer expiration value. + */ void timer_chg(struct Timer* timer, enum TimerType type, time_t value) { @@ -421,46 +525,58 @@ timer_chg(struct Timer* timer, enum TimerType type, time_t value) "timeout %Tu", timer, timer_to_name(timer->t_type), timer->t_value, timer_to_name(type), value)); - gen_dequeue(timer); /* remove the timer from the queue */ - timer->t_type = type; /* Set the new type and value */ timer->t_value = value; timer->t_expire = 0; + /* If the timer expiration callback tries to change the timer + * expiration, flag the timer but do not dequeue it yet. + */ + if (timer->t_header.gh_flags & GEN_MARKED) + { + timer->t_header.gh_flags |= GEN_READD; + return; + } + gen_dequeue(timer); /* remove the timer from the queue */ timer_enqueue(timer); /* re-queue the timer */ } -/* Execute all expired timers */ +/** Execute all expired timers. */ void timer_run(void) { struct Timer* ptr; - struct Timer* next = 0; /* go through queue... */ - for (ptr = evInfo.gens.g_timer; ptr; ptr = next) { - next = (struct Timer*) ptr->t_header.gh_next; + while ((ptr = (struct Timer*)evInfo.gens.g_timer)) { if (CurrentTime < ptr->t_expire) break; /* processed all pending timers */ gen_dequeue(ptr); /* must dequeue timer here */ - if (ptr->t_type == TT_ABSOLUTE || ptr->t_type == TT_RELATIVE) { - Debug((DEBUG_LIST, "Marking timer %p for later destruction", ptr)); - ptr->t_header.gh_flags |= GEN_MARKED; /* mark for destruction */ - } + ptr->t_header.gh_flags |= (GEN_MARKED | + (ptr->t_type == TT_PERIODIC ? GEN_READD : 0)); + event_generate(ET_EXPIRE, ptr, 0); /* generate expire event */ - if (ptr->t_header.gh_flags & (GEN_MARKED | GEN_DESTROY)) { + ptr->t_header.gh_flags &= ~GEN_MARKED; + + if (!(ptr->t_header.gh_flags & GEN_READD)) { Debug((DEBUG_LIST, "Destroying timer %p", ptr)); event_generate(ET_DESTROY, ptr, 0); - } else if (ptr->t_type == TT_PERIODIC) { - Debug((DEBUG_LIST, "Re-enqueuing periodic timer %p", ptr)); - timer_enqueue(ptr); /* re-queue periodic timer */ + } else { + Debug((DEBUG_LIST, "Re-enqueuing timer %p", ptr)); + timer_enqueue(ptr); /* re-queue timer */ + ptr->t_header.gh_flags &= ~GEN_READD; } } } -/* Adds a signal to the event callback system */ +/** Adds a signal to the event callback system. + * @param[in] signal Signal event generator to use. + * @param[in] call Callback function to use. + * @param[in] data User data pointer for generator. + * @param[in] sig Signal number to hook. + */ void signal_add(struct Signal* signal, EventCallBack call, void* data, int sig) { @@ -471,9 +587,9 @@ signal_add(struct Signal* signal, EventCallBack call, void* data, int sig) assert(0 != evInfo.engine); /* set up struct */ - gen_init((struct GenHeader*) signal, call, data, - (struct GenHeader*) evInfo.gens.g_signal, - (struct GenHeader**) &evInfo.gens.g_signal); + gen_init(&signal->sig_header, call, data, + evInfo.gens.g_signal, + &evInfo.gens.g_signal); signal->sig_signal = sig; @@ -487,7 +603,15 @@ signal_add(struct Signal* signal, EventCallBack call, void* data, int sig) } } -/* Adds a socket to the event system */ +/** Adds a socket to the event system. + * @param[in] sock Socket event generator to use. + * @param[in] call Callback function to use. + * @param[in] data User data pointer for the generator. + * @param[in] state Current socket state. + * @param[in] events Event interest mask for connected or connectionless sockets. + * @param[in] fd &Socket file descriptor. + * @return Zero on error, non-zero on success. + */ int socket_add(struct Socket* sock, EventCallBack call, void* data, enum SocketState state, unsigned int events, int fd) @@ -499,9 +623,9 @@ socket_add(struct Socket* sock, EventCallBack call, void* data, assert(0 != evInfo.engine->eng_add); /* set up struct */ - gen_init((struct GenHeader*) sock, call, data, - (struct GenHeader*) evInfo.gens.g_socket, - (struct GenHeader**) &evInfo.gens.g_socket); + gen_init(&sock->s_header, call, data, + evInfo.gens.g_socket, + &evInfo.gens.g_socket); sock->s_state = state; sock->s_events = events & SOCK_EVENT_MASK; @@ -510,7 +634,9 @@ socket_add(struct Socket* sock, EventCallBack call, void* data, return (*evInfo.engine->eng_add)(sock); /* tell engine about it */ } -/* deletes (or marks for deletion) a socket */ +/** Deletes (or marks for deletion) a socket generator. + * @param[in] sock Event generator to clear. + */ void socket_del(struct Socket* sock) { @@ -530,7 +656,10 @@ socket_del(struct Socket* sock) } } -/* Sets the socket state to something else */ +/** Sets the socket state to something else. + * @param[in] sock Socket generator to update. + * @param[in] state New socket state. + */ void socket_state(struct Socket* sock, enum SocketState state) { @@ -549,7 +678,8 @@ socket_state(struct Socket* sock, enum SocketState state) /* connected datagram socket now unconnected */ assert(sock->s_state != SS_CONNECTDG || state == SS_DATAGRAM); - if (sock->s_header.gh_flags & GEN_DESTROY) /* socket's been destroyed */ + /* Don't continue if an error occurred or the socket got destroyed */ + if (sock->s_header.gh_flags & (GEN_DESTROY | GEN_ERROR)) return; /* tell engine we're changing socket state */ @@ -558,7 +688,10 @@ socket_state(struct Socket* sock, enum SocketState state) sock->s_state = state; /* set new state */ } -/* sets the events a socket's interested in */ +/** Sets the events a socket's interested in. + * @param[in] sock Socket generator to update. + * @param[in] events New event interest mask. + */ void socket_events(struct Socket* sock, unsigned int events) { @@ -568,7 +701,8 @@ socket_events(struct Socket* sock, unsigned int events) assert(0 != evInfo.engine); assert(0 != evInfo.engine->eng_events); - if (sock->s_header.gh_flags & GEN_DESTROY) /* socket's been destroyed */ + /* Don't continue if an error occurred or the socket got destroyed */ + if (sock->s_header.gh_flags & (GEN_DESTROY | GEN_ERROR)) return; switch (events & SOCK_ACTION_MASK) { @@ -594,7 +728,9 @@ socket_events(struct Socket* sock, unsigned int events) sock->s_events = new_events; /* set new events */ } -/* Returns an engine's name for informational purposes */ +/** Returns the current engine's name for informational purposes. + * @return Pointer to a static buffer containing the engine name. + */ const char* engine_name(void) { @@ -607,16 +743,23 @@ engine_name(void) #ifdef DEBUGMODE /* These routines pretty-print names for states and types for debug printing */ +/** Declares a struct variable containing name(s) and value(s) of \a TYPE. */ #define NS(TYPE) \ struct { \ char *name; \ TYPE value; \ } +/** Declares an element initialize for an NS() struct. */ #define NM(name) { #name, name } -#define NE { 0, 0 } +/** Declares end of an NS() struct array. */ +#define NE { 0 } +/** Looks up name for a socket state. + * @param[in] state &Socket state to look up. + * @return Pointer to a static buffer containing the name, or "Undefined socket state". + */ const char* state_to_name(enum SocketState state) { @@ -638,6 +781,10 @@ state_to_name(enum SocketState state) return "Undefined socket state"; } +/** Looks up name for a timer type. + * @param[in] type &Timer type to look up. + * @return Pointer to a static buffer containing the name, or "Undefined timer type". + */ const char* timer_to_name(enum TimerType type) { @@ -656,6 +803,10 @@ timer_to_name(enum TimerType type) return "Undefined timer type"; } +/** Looks up name for an event type. + * @param[in] type &Event type to look up. + * @return Pointer to a static buffer containing the name, or "Undefined event type". + */ const char* event_to_name(enum EventType type) { @@ -680,6 +831,10 @@ event_to_name(enum EventType type) return "Undefined event type"; } +/** Constructs a string describing certain generator flags. + * @param[in] flags Bitwise combination of generator flags. + * @return Pointer to a static buffer containing the names of flags set in \a flags. + */ const char* gen_flags(unsigned int flags) { @@ -688,6 +843,9 @@ gen_flags(unsigned int flags) NS(unsigned int) map[] = { NM(GEN_DESTROY), NM(GEN_MARKED), + NM(GEN_ACTIVE), + NM(GEN_READD), + NM(GEN_ERROR), NE }; @@ -705,6 +863,10 @@ gen_flags(unsigned int flags) return buf; } +/** Constructs a string describing certain socket flags. + * @param[in] flags Bitwise combination of socket flags. + * @return Pointer to a static buffer containing the names of flags set in \a flags. + */ const char* sock_flags(unsigned int flags) {