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