2 * IRC - Internet Relay Chat, ircd/ircd_events.c
3 * Copyright (C) 2001 Kevin L. Mitchell <klmitch@mit.edu>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 1, or (at your option)
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "ircd_events.h"
26 #include "ircd_alloc.h"
28 #include "ircd_snprintf.h"
36 #define SIGS_PER_SOCK 10 /* number of signals to process per socket
40 extern struct Engine engine_kqueue;
41 #define ENGINE_KQUEUE &engine_kqueue,
44 #endif /* USE_KQUEUE */
47 extern struct Engine engine_devpoll;
48 #define ENGINE_DEVPOLL &engine_devpoll,
50 #define ENGINE_DEVPOLL
51 #endif /* USE_DEVPOLL */
54 extern struct Engine engine_epoll;
55 #define ENGINE_EPOLL &engine_epoll,
58 #endif /* USE_EPOLL */
61 extern struct Engine engine_poll;
62 #define ENGINE_FALLBACK &engine_poll,
64 extern struct Engine engine_select;
65 #define ENGINE_FALLBACK &engine_select,
68 /* list of engines to try */
69 static const struct Engine *evEngines[] = {
77 /* signal routines pipe data */
79 int fd; /* signal routine's fd */
80 struct Socket sock; /* and its struct Socket */
83 /* All the thread info */
85 struct Generators gens; /* List of all generators */
86 struct Event* events_free; /* struct Event free list */
87 unsigned int events_alloc; /* count of allocated struct Events */
88 const struct Engine* engine; /* core engine being used */
90 struct GenHeader* genq_head; /* head of generator event queue */
91 struct GenHeader* genq_tail; /* tail of generator event queue */
92 unsigned int genq_count; /* count of generators on queue */
102 /* Initialize a struct GenHeader */
104 gen_init(struct GenHeader* gen, EventCallBack call, void* data,
105 struct GenHeader* next, struct GenHeader** prev_p)
110 gen->gh_prev_p = prev_p;
117 gen->gh_flags = GEN_ACTIVE;
121 gen->gh_engdata.ed_int = 0;
123 if (prev_p) { /* Going to link into list? */
124 if (next) /* do so */
125 next->gh_prev_p = &gen->gh_next;
130 /* Execute an event; optimizations should inline this */
132 event_execute(struct Event* event)
135 assert(0 == event->ev_prev_p); /* must be off queue first */
136 assert(event->ev_gen.gen_header->gh_flags & GEN_ACTIVE);
138 if (event->ev_type == ET_DESTROY) /* turn off active flag *before* destroy */
139 event->ev_gen.gen_header->gh_flags &= ~GEN_ACTIVE;
140 if (event->ev_type == ET_ERROR) /* turn on error flag before callback */
141 event->ev_gen.gen_header->gh_flags |= GEN_ERROR;
143 (*event->ev_gen.gen_header->gh_call)(event); /* execute the event */
145 /* The logic here is very careful; if the event was an ET_DESTROY,
146 * then we must assume the generator is now invalid; fortunately, we
147 * don't need to do anything to it if so. Otherwise, we decrement
148 * the reference count; if reference count goes to zero, AND we need
149 * to destroy the generator, THEN we generate a DESTROY event.
151 if (event->ev_type != ET_DESTROY)
152 gen_ref_dec(event->ev_gen.gen_header);
154 event->ev_gen.gen_header = 0; /* clear event data */
155 event->ev_type = ET_DESTROY;
157 event->ev_next = evInfo.events_free; /* add to free list */
158 evInfo.events_free = event;
161 #ifndef IRCD_THREADED
162 /* we synchronously execute the event when not threaded */
163 #define event_add(event) \
165 struct Event* _ev = (event); \
167 _ev->ev_prev_p = 0; \
168 event_execute(_ev); \
172 /* add an event to the work queue */
173 /* This is just a placeholder; don't expect ircd to be threaded soon */
174 /* There should be locks all over the place in here */
176 event_add(struct Event* event)
178 struct GenHeader* gen;
182 gen = event->ev_gen.gen_header;
184 /* First, place event on generator's event queue */
187 assert(0 != gen->gh_tail);
189 event->ev_prev_p = &gen->gh_tail->ev_next;
190 gen->gh_tail->ev_next = event;
191 gen->gh_tail = event;
192 } else { /* queue was empty */
193 assert(0 == gen->gh_tail);
195 event->ev_prev_p = &gen->gh_head;
196 gen->gh_head = event;
197 gen->gh_tail = event;
200 /* Now, if the generator isn't on the queue yet... */
201 if (!gen->gh_qprev_p) {
203 if (evInfo.genq_head) {
204 assert(0 != evInfo.genq_tail);
206 gen->gh_qprev_p = &evInfo.genq_tail->gh_qnext;
207 evInfo.genq_tail->gh_qnext = gen;
208 evInfo.genq_tail = gen;
209 } else { /* queue was empty */
210 assert(0 == evInfo.genq_tail);
212 gen->gh_qprev_p = &evInfo.genq_head;
213 evInfo.genq_head = gen;
214 evInfo.genq_tail = gen;
217 /* We'd also have to signal the work crew here */
220 #endif /* IRCD_THREADED */
222 /* Place a timer in the correct spot on the queue */
224 timer_enqueue(struct Timer* timer)
226 struct Timer** ptr_p;
229 assert(0 == timer->t_header.gh_prev_p); /* not already on queue */
230 assert(timer->t_header.gh_flags & GEN_ACTIVE); /* timer is active */
232 /* Calculate expire time */
233 switch (timer->t_type) {
234 case TT_ABSOLUTE: /* no need to consider it relative */
235 timer->t_expire = timer->t_value;
238 case TT_RELATIVE: case TT_PERIODIC: /* relative timer */
239 timer->t_expire = timer->t_value + CurrentTime;
243 /* Find a slot to insert timer */
244 for (ptr_p = &evInfo.gens.g_timer; ;
245 ptr_p = (struct Timer**) &(*ptr_p)->t_header.gh_next)
246 if (!*ptr_p || timer->t_expire < (*ptr_p)->t_expire)
249 /* link it in the right place */
250 timer->t_header.gh_next = (struct GenHeader*) *ptr_p;
251 timer->t_header.gh_prev_p = (struct GenHeader**) ptr_p;
253 (*ptr_p)->t_header.gh_prev_p = &timer->t_header.gh_next;
257 /* signal handler for writing signal notification to pipe */
259 signal_handler(int sig)
263 assert(sigInfo.fd >= 0);
265 c = (unsigned char) sig; /* only write 1 byte to identify sig */
267 write(sigInfo.fd, &c, 1);
270 /* callback for signal "socket" events */
272 signal_callback(struct Event* event)
274 unsigned char sigstr[SIGS_PER_SOCK];
278 assert(event->ev_type == ET_READ); /* readable events only */
280 n_sigs = read(event->ev_gen.gen_socket->s_fd, sigstr, sizeof(sigstr));
282 for (i = 0; i < n_sigs; i++) {
283 sig = (int) sigstr[i]; /* get signal */
285 for (ptr = evInfo.gens.g_signal; ptr;
286 ptr = (struct Signal*) ptr->sig_header.gh_next)
287 if (ptr->sig_signal == sig) /* find its descriptor... */
291 event_generate(ET_SIGNAL, ptr, sig); /* generate signal event */
295 /* Remove something from its queue */
297 gen_dequeue(void* arg)
299 struct GenHeader* gen = (struct GenHeader*) arg;
301 if (gen->gh_next) /* clip it out of the list */
302 gen->gh_next->gh_prev_p = gen->gh_prev_p;
304 *gen->gh_prev_p = gen->gh_next;
306 gen->gh_next = 0; /* mark that it's not in the list anymore */
310 /* Initializes the event system */
312 event_init(int max_sockets)
316 for (i = 0; evEngines[i]; i++) { /* look for an engine... */
317 assert(0 != evEngines[i]->eng_name);
318 assert(0 != evEngines[i]->eng_init);
320 if ((*evEngines[i]->eng_init)(max_sockets))
321 break; /* Found an engine that'll work */
324 assert(0 != evEngines[i]);
326 evInfo.engine = evEngines[i]; /* save engine */
328 if (!evInfo.engine->eng_signal) { /* engine can't do signals */
330 log_write(LS_SYSTEM, L_CRIT, 0, "Failed to open signal pipe");
334 sigInfo.fd = p[1]; /* write end of pipe */
335 socket_add(&sigInfo.sock, signal_callback, 0, SS_NOTSOCK,
336 SOCK_EVENT_READABLE, p[0]); /* read end of pipe */
340 /* Do the event loop */
344 assert(0 != evInfo.engine);
345 assert(0 != evInfo.engine->eng_loop);
347 (*evInfo.engine->eng_loop)(&evInfo.gens);
350 /* Generate an event and add it to the queue (or execute it) */
352 event_generate(enum EventType type, void* arg, int data)
355 struct GenHeader* gen = (struct GenHeader*) arg;
359 /* don't create events (other than ET_DESTROY) for destroyed generators */
360 if (type != ET_DESTROY && (gen->gh_flags & GEN_DESTROY))
363 Debug((DEBUG_LIST, "Generating event type %s for generator %p (%s)",
364 event_to_name(type), gen, gen_flags(gen->gh_flags)));
366 if ((ptr = evInfo.events_free))
367 evInfo.events_free = ptr->ev_next; /* pop one off the freelist */
368 else { /* allocate another structure */
369 ptr = (struct Event*) MyMalloc(sizeof(struct Event));
370 evInfo.events_alloc++; /* count of allocated events */
373 ptr->ev_type = type; /* Record event type */
376 ptr->ev_gen.gen_header = (struct GenHeader*) gen;
377 ptr->ev_gen.gen_header->gh_ref++;
379 event_add(ptr); /* add event to queue */
383 /* Try to verify the timer list */
388 struct Timer** ptr_p = &evInfo.gens.g_timer;
391 for (ptr = evInfo.gens.g_timer; ptr;
392 ptr = (struct Timer*) ptr->t_header.gh_next) {
393 /* verify timer is supposed to be in the list */
394 assert(ptr->t_header.gh_prev_p);
395 /* verify timer is correctly ordered */
396 assert((struct Timer**) ptr->t_header.gh_prev_p == ptr_p);
397 /* verify timer is active */
398 assert(ptr->t_header.gh_flags & GEN_ACTIVE);
399 /* verify timer ordering is correct */
400 assert(lasttime <= ptr->t_expire);
402 lasttime = ptr->t_expire; /* store time for ordering check */
403 ptr_p = (struct Timer**) &ptr->t_header.gh_next; /* store prev pointer */
408 /* Initialize a timer structure */
410 timer_init(struct Timer* timer)
412 gen_init((struct GenHeader*) timer, 0, 0, 0, 0);
414 timer->t_header.gh_flags = 0; /* turn off active flag */
416 return timer; /* convenience return */
419 /* Add a timer to be processed */
421 timer_add(struct Timer* timer, EventCallBack call, void* data,
422 enum TimerType type, time_t value)
427 Debug((DEBUG_LIST, "Adding timer %p; time out %Tu (type %s)", timer, value,
428 timer_to_name(type)));
430 /* initialize a timer... */
431 timer->t_header.gh_flags |= GEN_ACTIVE;
432 if (timer->t_header.gh_flags & GEN_MARKED)
433 timer->t_header.gh_flags |= GEN_READD;
435 timer->t_header.gh_ref = 0;
436 timer->t_header.gh_call = call;
437 timer->t_header.gh_data = data;
439 timer->t_type = type;
440 timer->t_value = value;
443 if (!(timer->t_header.gh_flags & GEN_MARKED))
444 timer_enqueue(timer); /* and enqueue it */
447 /* Remove a timer from the processing queue */
449 timer_del(struct Timer* timer)
453 timer->t_header.gh_flags &= ~GEN_READD;
455 if (timer->t_header.gh_flags & GEN_MARKED)
456 return; /* timer is being used */
458 Debug((DEBUG_LIST, "Deleting timer %p (type %s)", timer,
459 timer_to_name(timer->t_type)));
462 event_generate(ET_DESTROY, timer, 0);
465 /* Change the time a timer expires */
467 timer_chg(struct Timer* timer, enum TimerType type, time_t value)
471 assert(TT_PERIODIC != timer->t_type);
472 assert(TT_PERIODIC != type);
474 Debug((DEBUG_LIST, "Changing timer %p from type %s timeout %Tu to type %s "
475 "timeout %Tu", timer, timer_to_name(timer->t_type), timer->t_value,
476 timer_to_name(type), value));
478 gen_dequeue(timer); /* remove the timer from the queue */
480 timer->t_type = type; /* Set the new type and value */
481 timer->t_value = value;
484 timer_enqueue(timer); /* re-queue the timer */
487 /* Execute all expired timers */
493 /* go through queue... */
494 while ((ptr = evInfo.gens.g_timer)) {
495 if (CurrentTime < ptr->t_expire)
496 break; /* processed all pending timers */
498 gen_dequeue(ptr); /* must dequeue timer here */
499 ptr->t_header.gh_flags |= (GEN_MARKED |
500 (ptr->t_type == TT_PERIODIC ? GEN_READD : 0));
502 event_generate(ET_EXPIRE, ptr, 0); /* generate expire event */
504 ptr->t_header.gh_flags &= ~GEN_MARKED;
506 if (!(ptr->t_header.gh_flags & GEN_READD)) {
507 Debug((DEBUG_LIST, "Destroying timer %p", ptr));
508 event_generate(ET_DESTROY, ptr, 0);
510 Debug((DEBUG_LIST, "Re-enqueuing timer %p", ptr));
511 timer_enqueue(ptr); /* re-queue timer */
512 ptr->t_header.gh_flags &= ~GEN_READD;
517 /* Adds a signal to the event callback system */
519 signal_add(struct Signal* signal, EventCallBack call, void* data, int sig)
521 struct sigaction act;
525 assert(0 != evInfo.engine);
528 gen_init((struct GenHeader*) signal, call, data,
529 (struct GenHeader*) evInfo.gens.g_signal,
530 (struct GenHeader**) &evInfo.gens.g_signal);
532 signal->sig_signal = sig;
534 if (evInfo.engine->eng_signal)
535 (*evInfo.engine->eng_signal)(signal); /* tell engine */
537 act.sa_handler = signal_handler; /* set up signal handler */
539 sigemptyset(&act.sa_mask);
540 sigaction(sig, &act, 0);
544 /* Adds a socket to the event system */
546 socket_add(struct Socket* sock, EventCallBack call, void* data,
547 enum SocketState state, unsigned int events, int fd)
552 assert(0 != evInfo.engine);
553 assert(0 != evInfo.engine->eng_add);
556 gen_init((struct GenHeader*) sock, call, data,
557 (struct GenHeader*) evInfo.gens.g_socket,
558 (struct GenHeader**) &evInfo.gens.g_socket);
560 sock->s_state = state;
561 sock->s_events = events & SOCK_EVENT_MASK;
564 return (*evInfo.engine->eng_add)(sock); /* tell engine about it */
567 /* deletes (or marks for deletion) a socket */
569 socket_del(struct Socket* sock)
572 assert(!(sock->s_header.gh_flags & GEN_DESTROY));
573 assert(0 != evInfo.engine);
574 assert(0 != evInfo.engine->eng_closing);
576 /* tell engine socket is going away */
577 (*evInfo.engine->eng_closing)(sock);
579 sock->s_header.gh_flags |= GEN_DESTROY;
581 if (!sock->s_header.gh_ref) { /* not in use; destroy right now */
583 event_generate(ET_DESTROY, sock, 0);
587 /* Sets the socket state to something else */
589 socket_state(struct Socket* sock, enum SocketState state)
592 assert(0 != evInfo.engine);
593 assert(0 != evInfo.engine->eng_state);
595 /* assertions for invalid socket state transitions */
596 assert(sock->s_state != state); /* not changing states ?! */
597 assert(sock->s_state != SS_LISTENING); /* listening socket to...?! */
598 assert(sock->s_state != SS_CONNECTED); /* connected socket to...?! */
599 /* connecting socket now connected */
600 assert(sock->s_state != SS_CONNECTING || state == SS_CONNECTED);
601 /* unconnected datagram socket now connected */
602 assert(sock->s_state != SS_DATAGRAM || state == SS_CONNECTDG);
603 /* connected datagram socket now unconnected */
604 assert(sock->s_state != SS_CONNECTDG || state == SS_DATAGRAM);
606 /* Don't continue if an error occurred or the socket got destroyed */
607 if (sock->s_header.gh_flags & (GEN_DESTROY | GEN_ERROR))
610 /* tell engine we're changing socket state */
611 (*evInfo.engine->eng_state)(sock, state);
613 sock->s_state = state; /* set new state */
616 /* sets the events a socket's interested in */
618 socket_events(struct Socket* sock, unsigned int events)
620 unsigned int new_events = 0;
623 assert(0 != evInfo.engine);
624 assert(0 != evInfo.engine->eng_events);
626 /* Don't continue if an error occurred or the socket got destroyed */
627 if (sock->s_header.gh_flags & (GEN_DESTROY | GEN_ERROR))
630 switch (events & SOCK_ACTION_MASK) {
631 case SOCK_ACTION_SET: /* set events to given set */
632 new_events = events & SOCK_EVENT_MASK;
635 case SOCK_ACTION_ADD: /* add some events */
636 new_events = sock->s_events | (events & SOCK_EVENT_MASK);
639 case SOCK_ACTION_DEL: /* remove some events */
640 new_events = sock->s_events & ~(events & SOCK_EVENT_MASK);
644 if (sock->s_events == new_events)
645 return; /* no changes have been made */
647 /* tell engine about event mask change */
648 (*evInfo.engine->eng_events)(sock, new_events);
650 sock->s_events = new_events; /* set new events */
653 /* Returns an engine's name for informational purposes */
657 assert(0 != evInfo.engine);
658 assert(0 != evInfo.engine->eng_name);
660 return evInfo.engine->eng_name;
664 /* These routines pretty-print names for states and types for debug printing */
672 #define NM(name) { #name, name }
677 state_to_name(enum SocketState state)
680 NS(enum SocketState) map[] = {
690 for (i = 0; map[i].name; i++)
691 if (map[i].value == state)
694 return "Undefined socket state";
698 timer_to_name(enum TimerType type)
701 NS(enum TimerType) map[] = {
708 for (i = 0; map[i].name; i++)
709 if (map[i].value == type)
712 return "Undefined timer type";
716 event_to_name(enum EventType type)
719 NS(enum EventType) map[] = {
732 for (i = 0; map[i].name; i++)
733 if (map[i].value == type)
736 return "Undefined event type";
740 gen_flags(unsigned int flags)
743 static char buf[256];
744 NS(unsigned int) map[] = {
755 for (i = 0; map[i].name; i++)
756 if (map[i].value & flags) {
759 loc += ircd_snprintf(0, buf + loc, sizeof(buf) - loc, "%s", map[i].name);
760 if (loc >= sizeof(buf))
761 return buf; /* overflow case */
768 sock_flags(unsigned int flags)
771 static char buf[256];
772 NS(unsigned int) map[] = {
773 NM(SOCK_EVENT_READABLE),
774 NM(SOCK_EVENT_WRITABLE),
783 for (i = 0; map[i].name; i++)
784 if (map[i].value & flags) {
787 loc += ircd_snprintf(0, buf + loc, sizeof(buf) - loc, "%s", map[i].name);
788 if (loc >= sizeof(buf))
789 return buf; /* overflow case */
795 #endif /* DEBUGMODE */