Author: Kev <klmitch@mit.edu>
[ircu2.10.12-pk.git] / ircd / ircd_events.c
1 /*
2  * IRC - Internet Relay Chat, ircd/ircd_events.c
3  * Copyright (C) 2001 Kevin L. Mitchell <klmitch@mit.edu>
4  *
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)
8  * any later version.
9  *
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.
14  *
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.
18  *
19  * $Id$
20  */
21 #include "config.h"
22
23 #include "ircd_events.h"
24
25 #include "ircd.h"
26 #include "ircd_alloc.h"
27 #include "ircd_log.h"
28 #include "ircd_snprintf.h"
29 #include "s_debug.h"
30
31 #include <assert.h>
32 #include <signal.h>
33 #include <unistd.h>
34
35 #define SIGS_PER_SOCK   10      /* number of signals to process per socket
36                                    readable event */
37
38 #ifdef USE_KQUEUE
39 extern struct Engine engine_kqueue;
40 #define ENGINE_KQUEUE   &engine_kqueue,
41 #else
42 #define ENGINE_KQUEUE
43 #endif /* USE_KQUEUE */
44
45 #ifdef USE_DEVPOLL
46 extern struct Engine engine_devpoll;
47 #define ENGINE_DEVPOLL  &engine_devpoll,
48 #else
49 #define ENGINE_DEVPOLL
50 #endif /* USE_DEVPOLL */
51
52 #ifdef USE_POLL
53 extern struct Engine engine_poll;
54 #define ENGINE_FALLBACK &engine_poll,
55 #else
56 extern struct Engine engine_select;
57 #define ENGINE_FALLBACK &engine_select,
58 #endif /* USE_POLL */
59
60 /* list of engines to try */
61 static const struct Engine *evEngines[] = {
62   ENGINE_KQUEUE
63   ENGINE_DEVPOLL
64   ENGINE_FALLBACK
65   0
66 };
67
68 /* signal routines pipe data */
69 static struct {
70   int           fd;     /* signal routine's fd */
71   struct Socket sock;   /* and its struct Socket */
72 } sigInfo = { -1 };
73
74 /* All the thread info */
75 static struct {
76   struct Generators    gens;            /* List of all generators */
77   struct Event*        events_free;     /* struct Event free list */
78   unsigned int         events_alloc;    /* count of allocated struct Events */
79   const struct Engine* engine;          /* core engine being used */
80 #ifdef IRCD_THREADED
81   struct GenHeader*    genq_head;       /* head of generator event queue */
82   struct GenHeader*    genq_tail;       /* tail of generator event queue */
83   unsigned int         genq_count;      /* count of generators on queue */
84 #endif
85 } evInfo = {
86   { 0, 0, 0 },
87   0, 0, 0
88 #ifdef IRCD_THREADED
89   , 0, 0, 0
90 #endif
91 };
92
93 /* Initialize a struct GenHeader */
94 static void
95 gen_init(struct GenHeader* gen, EventCallBack call, void* data,
96          struct GenHeader* next, struct GenHeader** prev_p)
97 {
98   assert(0 != gen);
99
100   gen->gh_next = next;
101   gen->gh_prev_p = prev_p;
102 #ifdef IRCD_THREADED
103   gen->gh_qnext = 0;
104   gen->gh_qprev_p = 0;
105   gen->gh_head = 0;
106   gen->gh_tail = 0;
107 #endif
108   gen->gh_flags = GEN_ACTIVE;
109   gen->gh_ref = 0;
110   gen->gh_call = call;
111   gen->gh_data = data;
112   gen->gh_engdata.ed_int = 0;
113
114   if (prev_p) { /* Going to link into list? */
115     if (next) /* do so */
116       next->gh_prev_p = &gen->gh_next;
117     *prev_p = gen;
118   }
119 }
120
121 /* Execute an event; optimizations should inline this */
122 static void
123 event_execute(struct Event* event)
124 {
125   assert(0 != event);
126   assert(0 == event->ev_prev_p); /* must be off queue first */
127   assert(event->ev_gen.gen_header->gh_flags & GEN_ACTIVE);
128
129   if (event->ev_type == ET_DESTROY) /* turn off active flag *before* destroy */
130     event->ev_gen.gen_header->gh_flags &= ~GEN_ACTIVE;
131
132   (*event->ev_gen.gen_header->gh_call)(event); /* execute the event */
133
134   /* The logic here is very careful; if the event was an ET_DESTROY,
135    * then we must assume the generator is now invalid; fortunately, we
136    * don't need to do anything to it if so.  Otherwise, we decrement
137    * the reference count; if reference count goes to zero, AND we need
138    * to destroy the generator, THEN we generate a DESTROY event.
139    */
140   if (event->ev_type != ET_DESTROY)
141     gen_ref_dec(event->ev_gen.gen_header);
142
143   event->ev_gen.gen_header = 0; /* clear event data */
144   event->ev_type = ET_DESTROY;
145
146   event->ev_next = evInfo.events_free; /* add to free list */
147   evInfo.events_free = event;
148 }
149
150 #ifndef IRCD_THREADED
151 /* we synchronously execute the event when not threaded */
152 #define event_add(event)        \
153 do {                                                                          \
154   struct Event* _ev = (event);                                                \
155   _ev->ev_next = 0;                                                           \
156   _ev->ev_prev_p = 0;                                                         \
157   event_execute(_ev);                                                         \
158 } while (0)
159
160 #else
161 /* add an event to the work queue */
162 /* This is just a placeholder; don't expect ircd to be threaded soon */
163 /* There should be locks all over the place in here */
164 static void
165 event_add(struct Event* event)
166 {
167   struct GenHeader* gen;
168
169   assert(0 != event);
170
171   gen = event->ev_gen.gen_header;
172
173   /* First, place event on generator's event queue */
174   event->ev_next = 0;
175   if (gen->gh_head) {
176     assert(0 != gen->gh_tail);
177
178     event->ev_prev_p = &gen->gh_tail->ev_next;
179     gen->gh_tail->ev_next = event;
180     gen->gh_tail = event;
181   } else { /* queue was empty */
182     assert(0 == gen->gh_tail);
183
184     event->ev_prev_p = &gen->gh_head;
185     gen->gh_head = event;
186     gen->gh_tail = event;
187   }
188
189   /* Now, if the generator isn't on the queue yet... */
190   if (!gen->gh_qprev_p) {
191     gen->gh_qnext = 0;
192     if (evInfo.genq_head) {
193       assert(0 != evInfo.genq_tail);
194
195       gen->gh_qprev_p = &evInfo.genq_tail->gh_qnext;
196       evInfo.genq_tail->gh_qnext = gen;
197       evInfo.genq_tail = gen;
198     } else { /* queue was empty */
199       assert(0 == evInfo.genq_tail);
200
201       gen->gh_qprev_p = &evInfo.genq_head;
202       evInfo.genq_head = gen;
203       evInfo.genq_tail = gen;
204     }
205
206     /* We'd also have to signal the work crew here */
207   }
208 }
209 #endif /* IRCD_THREADED */
210
211 /* Place a timer in the correct spot on the queue */
212 static void
213 timer_enqueue(struct Timer* timer)
214 {
215   struct Timer** ptr_p;
216
217   assert(0 != timer);
218   assert(0 == timer->t_header.gh_prev_p); /* not already on queue */
219
220   /* Calculate expire time */
221   switch (timer->t_type) {
222   case TT_ABSOLUTE: /* no need to consider it relative */
223     timer->t_expire = timer->t_value;
224     break;
225
226   case TT_RELATIVE: case TT_PERIODIC: /* relative timer */
227     timer->t_expire = timer->t_value + CurrentTime;
228     break;
229   }
230
231   /* Find a slot to insert timer */
232   for (ptr_p = &evInfo.gens.g_timer; ;
233        ptr_p = (struct Timer**) &(*ptr_p)->t_header.gh_next)
234     if (!*ptr_p || timer->t_expire < (*ptr_p)->t_expire)
235       break;
236
237   /* link it in the right place */
238   timer->t_header.gh_next = (struct GenHeader*) *ptr_p;
239   timer->t_header.gh_prev_p = (struct GenHeader**) ptr_p;
240   if (*ptr_p)
241     (*ptr_p)->t_header.gh_prev_p = &timer->t_header.gh_next;
242   *ptr_p = timer;
243 }
244
245 /* signal handler for writing signal notification to pipe */
246 static void
247 signal_handler(int sig)
248 {
249   unsigned char c;
250
251   assert(sigInfo.fd >= 0);
252
253   c = (unsigned char) sig; /* only write 1 byte to identify sig */
254
255   write(sigInfo.fd, &c, 1);
256 }
257
258 /* callback for signal "socket" events */
259 static void
260 signal_callback(struct Event* event)
261 {
262   unsigned char sigstr[SIGS_PER_SOCK];
263   int sig, n_sigs, i;
264   struct Signal* ptr;
265
266   assert(event->ev_type == ET_READ); /* readable events only */
267
268   n_sigs = read(event->ev_gen.gen_socket->s_fd, sigstr, sizeof(sigstr));
269
270   for (i = 0; i < n_sigs; i++) {
271     sig = (int) sigstr[i]; /* get signal */
272
273     for (ptr = evInfo.gens.g_signal; ptr;
274          ptr = (struct Signal*) ptr->sig_header.gh_next)
275       if (ptr->sig_signal == sig) /* find its descriptor... */
276         break;
277
278     if (ptr)
279       event_generate(ET_SIGNAL, ptr, sig); /* generate signal event */
280   }
281 }
282
283 /* Remove something from its queue */
284 void
285 gen_dequeue(void* arg)
286 {
287   struct GenHeader* gen = (struct GenHeader*) arg;
288
289   if (gen->gh_next) /* clip it out of the list */
290     gen->gh_next->gh_prev_p = gen->gh_prev_p;
291   if (gen->gh_prev_p)
292     *gen->gh_prev_p = gen->gh_next;
293
294   gen->gh_next = 0; /* mark that it's not in the list anymore */
295   gen->gh_prev_p = 0;
296 }
297
298 /* Initializes the event system */
299 void
300 event_init(int max_sockets)
301 {
302   int i, p[2];
303
304   for (i = 0; evEngines[i]; i++) { /* look for an engine... */
305     assert(0 != evEngines[i]->eng_name);
306     assert(0 != evEngines[i]->eng_init);
307
308     if ((*evEngines[i]->eng_init)(max_sockets))
309       break; /* Found an engine that'll work */
310   }
311
312   assert(0 != evEngines[i]);
313
314   evInfo.engine = evEngines[i]; /* save engine */
315
316   if (!evInfo.engine->eng_signal) { /* engine can't do signals */
317     if (pipe(p)) {
318       log_write(LS_SYSTEM, L_CRIT, 0, "Failed to open signal pipe");
319       exit(8);
320     }
321
322     sigInfo.fd = p[1]; /* write end of pipe */
323     socket_add(&sigInfo.sock, signal_callback, 0, SS_NOTSOCK,
324                SOCK_EVENT_READABLE, p[0]); /* read end of pipe */
325   }
326 }
327
328 /* Do the event loop */
329 void
330 event_loop(void)
331 {
332   assert(0 != evInfo.engine);
333   assert(0 != evInfo.engine->eng_loop);
334
335   (*evInfo.engine->eng_loop)(&evInfo.gens);
336 }
337
338 /* Generate an event and add it to the queue (or execute it) */
339 void
340 event_generate(enum EventType type, void* arg, int data)
341 {
342   struct Event* ptr;
343   struct GenHeader* gen = (struct GenHeader*) arg;
344
345   assert(0 != gen);
346
347   /* don't create events (other than ET_DESTROY) for destroyed generators */
348   if (type != ET_DESTROY && (gen->gh_flags & GEN_DESTROY))
349     return;
350
351   Debug((DEBUG_LIST, "Generating event type %s for generator %p (%s)",
352          event_to_name(type), gen, gen_flags(gen->gh_flags)));
353
354   if ((ptr = evInfo.events_free))
355     evInfo.events_free = ptr->ev_next; /* pop one off the freelist */
356   else { /* allocate another structure */
357     ptr = (struct Event*) MyMalloc(sizeof(struct Event));
358     evInfo.events_alloc++; /* count of allocated events */
359   }
360
361   ptr->ev_type = type; /* Record event type */
362   ptr->ev_data = data;
363
364   ptr->ev_gen.gen_header = (struct GenHeader*) gen;
365   ptr->ev_gen.gen_header->gh_ref++;
366
367   event_add(ptr); /* add event to queue */
368 }
369
370 /* Add a timer to be processed */
371 void
372 timer_add(struct Timer* timer, EventCallBack call, void* data,
373           enum TimerType type, time_t value)
374 {
375   assert(0 != timer);
376   assert(0 != call);
377
378   Debug((DEBUG_LIST, "Adding timer %p; time out %Tu (type %s)", timer, value,
379          timer_to_name(type)));
380
381   /* initialize a timer... */
382   gen_init((struct GenHeader*) timer, call, data, 0, 0);
383
384   timer->t_type = type;
385   timer->t_value = value;
386   timer->t_expire = 0;
387
388   timer_enqueue(timer); /* and enqueue it */
389 }
390
391 /* Remove a timer from the processing queue */
392 void
393 timer_del(struct Timer* timer)
394 {
395   assert(0 != timer);
396
397   if (timer->t_header.gh_flags & GEN_MARKED)
398     return; /* timer already marked for destruction */
399
400   timer->t_header.gh_flags |= GEN_DESTROY;
401
402   Debug((DEBUG_LIST, "Deleting timer %p (type %s)", timer,
403          timer_to_name(timer->t_type)));
404
405   if (!timer->t_header.gh_ref) { /* not in use; destroy right now */
406     gen_dequeue(timer);
407     event_generate(ET_DESTROY, timer, 0);
408   }
409 }
410
411 /* Change the time a timer expires */
412 void
413 timer_chg(struct Timer* timer, enum TimerType type, time_t value)
414 {
415   assert(0 != timer);
416   assert(0 != value);
417   assert(TT_PERIODIC != timer->t_type);
418   assert(TT_PERIODIC != type);
419
420   Debug((DEBUG_LIST, "Changing timer %p from type %s timeout %Tu to type %s "
421          "timeout %Tu", timer, timer_to_name(timer->t_type), timer->t_value,
422          timer_to_name(type), value));
423
424   gen_dequeue(timer); /* remove the timer from the queue */
425
426   timer->t_type = type; /* Set the new type and value */
427   timer->t_value = value;
428   timer->t_expire = 0;
429
430   timer_enqueue(timer); /* re-queue the timer */
431 }
432
433 /* Execute all expired timers */
434 void
435 timer_run(void)
436 {
437   struct Timer* ptr;
438   struct Timer* next = 0;
439
440   /* go through queue... */
441   for (ptr = evInfo.gens.g_timer; ptr; ptr = next) {
442     next = (struct Timer*) ptr->t_header.gh_next;
443     if (CurrentTime < ptr->t_expire)
444       break; /* processed all pending timers */
445
446     gen_dequeue(ptr); /* must dequeue timer here */
447     if (ptr->t_type == TT_ABSOLUTE || ptr->t_type == TT_RELATIVE) {
448       Debug((DEBUG_LIST, "Marking timer %p for later destruction", ptr));
449       ptr->t_header.gh_flags |= GEN_MARKED; /* mark for destruction */
450     }
451     event_generate(ET_EXPIRE, ptr, 0); /* generate expire event */
452
453     if (ptr->t_header.gh_flags & (GEN_MARKED | GEN_DESTROY)) {
454       Debug((DEBUG_LIST, "Destroying timer %p", ptr));
455       event_generate(ET_DESTROY, ptr, 0);
456     } else if (ptr->t_type == TT_PERIODIC) {
457       Debug((DEBUG_LIST, "Re-enqueuing periodic timer %p", ptr));
458       timer_enqueue(ptr); /* re-queue periodic timer */
459     }
460   }
461 }
462
463 /* Adds a signal to the event callback system */
464 void
465 signal_add(struct Signal* signal, EventCallBack call, void* data, int sig)
466 {
467   struct sigaction act;
468
469   assert(0 != signal);
470   assert(0 != call);
471   assert(0 != evInfo.engine);
472
473   /* set up struct */
474   gen_init((struct GenHeader*) signal, call, data,
475            (struct GenHeader*) evInfo.gens.g_signal,
476            (struct GenHeader**) &evInfo.gens.g_signal);
477
478   signal->sig_signal = sig;
479
480   if (evInfo.engine->eng_signal)
481     (*evInfo.engine->eng_signal)(signal); /* tell engine */
482   else {
483     act.sa_handler = signal_handler; /* set up signal handler */
484     act.sa_flags = 0;
485     sigemptyset(&act.sa_mask);
486     sigaction(sig, &act, 0);
487   }
488 }
489
490 /* Adds a socket to the event system */
491 int
492 socket_add(struct Socket* sock, EventCallBack call, void* data,
493            enum SocketState state, unsigned int events, int fd)
494 {
495   assert(0 != sock);
496   assert(0 != call);
497   assert(fd >= 0);
498   assert(0 != evInfo.engine);
499   assert(0 != evInfo.engine->eng_add);
500
501   /* set up struct */
502   gen_init((struct GenHeader*) sock, call, data,
503            (struct GenHeader*) evInfo.gens.g_socket,
504            (struct GenHeader**) &evInfo.gens.g_socket);
505
506   sock->s_state = state;
507   sock->s_events = events & SOCK_EVENT_MASK;
508   sock->s_fd = fd;
509
510   return (*evInfo.engine->eng_add)(sock); /* tell engine about it */
511 }
512
513 /* deletes (or marks for deletion) a socket */
514 void
515 socket_del(struct Socket* sock)
516 {
517   assert(0 != sock);
518   assert(!(sock->s_header.gh_flags & GEN_DESTROY));
519   assert(0 != evInfo.engine);
520   assert(0 != evInfo.engine->eng_closing);
521
522   /* tell engine socket is going away */
523   (*evInfo.engine->eng_closing)(sock);
524
525   sock->s_header.gh_flags |= GEN_DESTROY;
526
527   if (!sock->s_header.gh_ref) { /* not in use; destroy right now */
528     gen_dequeue(sock);
529     event_generate(ET_DESTROY, sock, 0);
530   }
531 }
532
533 /* Sets the socket state to something else */
534 void
535 socket_state(struct Socket* sock, enum SocketState state)
536 {
537   assert(0 != sock);
538   assert(0 != evInfo.engine);
539   assert(0 != evInfo.engine->eng_state);
540
541   /* assertions for invalid socket state transitions */
542   assert(sock->s_state != state); /* not changing states ?! */
543   assert(sock->s_state != SS_LISTENING); /* listening socket to...?! */
544   assert(sock->s_state != SS_CONNECTED); /* connected socket to...?! */
545   /* connecting socket now connected */
546   assert(sock->s_state != SS_CONNECTING || state == SS_CONNECTED);
547   /* unconnected datagram socket now connected */
548   assert(sock->s_state != SS_DATAGRAM || state == SS_CONNECTDG);
549   /* connected datagram socket now unconnected */
550   assert(sock->s_state != SS_CONNECTDG || state == SS_DATAGRAM);
551
552   if (sock->s_header.gh_flags & GEN_DESTROY) /* socket's been destroyed */
553     return;
554
555   /* tell engine we're changing socket state */
556   (*evInfo.engine->eng_state)(sock, state);
557
558   sock->s_state = state; /* set new state */
559 }
560
561 /* sets the events a socket's interested in */
562 void
563 socket_events(struct Socket* sock, unsigned int events)
564 {
565   unsigned int new_events = 0;
566
567   assert(0 != sock);
568   assert(0 != evInfo.engine);
569   assert(0 != evInfo.engine->eng_events);
570
571   if (sock->s_header.gh_flags & GEN_DESTROY) /* socket's been destroyed */
572     return;
573
574   switch (events & SOCK_ACTION_MASK) {
575   case SOCK_ACTION_SET: /* set events to given set */
576     new_events = events & SOCK_EVENT_MASK;
577     break;
578
579   case SOCK_ACTION_ADD: /* add some events */
580     new_events = sock->s_events | (events & SOCK_EVENT_MASK);
581     break;
582
583   case SOCK_ACTION_DEL: /* remove some events */
584     new_events = sock->s_events & ~(events & SOCK_EVENT_MASK);
585     break;
586   }
587
588   if (sock->s_events == new_events)
589     return; /* no changes have been made */
590
591   /* tell engine about event mask change */
592   (*evInfo.engine->eng_events)(sock, new_events);
593
594   sock->s_events = new_events; /* set new events */
595 }
596
597 /* Returns an engine's name for informational purposes */
598 const char*
599 engine_name(void)
600 {
601   assert(0 != evInfo.engine);
602   assert(0 != evInfo.engine->eng_name);
603
604   return evInfo.engine->eng_name;
605 }
606
607 #ifdef DEBUGMODE
608 /* These routines pretty-print names for states and types for debug printing */
609
610 #define NS(TYPE) \
611 struct {        \
612   char *name;   \
613   TYPE value;   \
614 }
615
616 #define NM(name)        { #name, name }
617
618 #define NE              { 0, 0 }
619
620 const char*
621 state_to_name(enum SocketState state)
622 {
623   int i;
624   NS(enum SocketState) map[] = {
625     NM(SS_CONNECTING),
626     NM(SS_LISTENING),
627     NM(SS_CONNECTED),
628     NM(SS_DATAGRAM),
629     NM(SS_CONNECTDG),
630     NM(SS_NOTSOCK),
631     NE
632   };
633
634   for (i = 0; map[i].name; i++)
635     if (map[i].value == state)
636       return map[i].name;
637
638   return "Undefined socket state";
639 }
640
641 const char*
642 timer_to_name(enum TimerType type)
643 {
644   int i;
645   NS(enum TimerType) map[] = {
646     NM(TT_ABSOLUTE),
647     NM(TT_RELATIVE),
648     NM(TT_PERIODIC),
649     NE
650   };
651
652   for (i = 0; map[i].name; i++)
653     if (map[i].value == type)
654       return map[i].name;
655
656   return "Undefined timer type";
657 }
658
659 const char*
660 event_to_name(enum EventType type)
661 {
662   int i;
663   NS(enum EventType) map[] = {
664     NM(ET_READ),
665     NM(ET_WRITE),
666     NM(ET_ACCEPT),
667     NM(ET_CONNECT),
668     NM(ET_EOF),
669     NM(ET_ERROR),
670     NM(ET_SIGNAL),
671     NM(ET_EXPIRE),
672     NM(ET_DESTROY),
673     NE
674   };
675
676   for (i = 0; map[i].name; i++)
677     if (map[i].value == type)
678       return map[i].name;
679
680   return "Undefined event type";
681 }
682
683 const char*
684 gen_flags(unsigned int flags)
685 {
686   int i, loc = 0;
687   static char buf[256];
688   NS(unsigned int) map[] = {
689     NM(GEN_DESTROY),
690     NM(GEN_MARKED),
691     NE
692   };
693
694   buf[0] = '\0';
695
696   for (i = 0; map[i].name; i++)
697     if (map[i].value & flags) {
698       if (loc != 0)
699         buf[loc++] = ' ';
700       loc += ircd_snprintf(0, buf + loc, sizeof(buf) - loc, "%s", map[i].name);
701       if (loc >= sizeof(buf))
702         return buf; /* overflow case */
703     }
704
705   return buf;
706 }
707
708 const char*
709 sock_flags(unsigned int flags)
710 {
711   int i, loc = 0;
712   static char buf[256];
713   NS(unsigned int) map[] = {
714     NM(SOCK_EVENT_READABLE),
715     NM(SOCK_EVENT_WRITABLE),
716     NM(SOCK_ACTION_SET),
717     NM(SOCK_ACTION_ADD),
718     NM(SOCK_ACTION_DEL),
719     NE
720   };
721
722   buf[0] = '\0';
723
724   for (i = 0; map[i].name; i++)
725     if (map[i].value & flags) {
726       if (loc != 0)
727         buf[loc++] = ' ';
728       loc += ircd_snprintf(0, buf + loc, sizeof(buf) - loc, "%s", map[i].name);
729       if (loc >= sizeof(buf))
730         return buf; /* overflow case */
731     }
732
733   return buf;
734 }
735
736 #endif /* DEBUGMODE */