r5196: fixed sily bug (that metze found)
[jelmer/samba4-debian.git] / source / lib / events.c
1 /* 
2    Unix SMB/CIFS implementation.
3    main select loop and event handling
4    Copyright (C) Andrew Tridgell 2003
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 /*
22   PLEASE READ THIS BEFORE MODIFYING!
23
24   This module is a general abstraction for the main select loop and
25   event handling. Do not ever put any localised hacks in here, instead
26   register one of the possible event types and implement that event
27   somewhere else.
28
29   There are 2 types of event handling that are handled in this module:
30
31   1) a file descriptor becoming readable or writeable. This is mostly
32      used for network sockets, but can be used for any type of file
33      descriptor. You may only register one handler for each file
34      descriptor/io combination or you will get unpredictable results
35      (this means that you can have a handler for read events, and a
36      separate handler for write events, but not two handlers that are
37      both handling read events)
38
39   2) a timed event. You can register an event that happens at a
40      specific time.  You can register as many of these as you
41      like. They are single shot - add a new timed event in the event
42      handler to get another event.
43
44   To setup a set of events you first need to create a event_context
45   structure using the function event_context_init(); This returns a
46   'struct event_context' that you use in all subsequent calls.
47
48   After that you can add/remove events that you are interested in
49   using event_add_*() and talloc_free()
50
51   Finally, you call event_loop_wait() to block waiting for one of the
52   events to occor. In normal operation event_loop_wait() will loop
53   forever.
54
55 */
56
57 #include "includes.h"
58 #include "system/time.h"
59 #include "system/select.h"
60 #include "dlinklist.h"
61 #include "events.h"
62
63 /* use epoll if it is available */
64 #if defined(HAVE_EPOLL_CREATE) && defined(HAVE_SYS_EPOLL_H)
65 #define WITH_EPOLL 1
66 #endif
67
68 #if WITH_EPOLL
69 #include <sys/epoll.h>
70 #endif
71
72 struct event_context {  
73         /* list of filedescriptor events */
74         struct fd_event {
75                 struct event_context *event_ctx;
76                 struct fd_event *next, *prev;
77                 int fd;
78                 uint16_t flags; /* see EVENT_FD_* flags */
79                 event_fd_handler_t handler;
80                 void *private;
81         } *fd_events;
82
83         /* list of timed events */
84         struct timed_event {
85                 struct event_context *event_ctx;
86                 struct timed_event *next, *prev;
87                 struct timeval next_event;
88                 event_timed_handler_t handler;
89                 void *private;
90         } *timed_events;
91
92         /* the maximum file descriptor number in fd_events */
93         int maxfd;
94
95         /* information for exiting from the event loop */
96         int exit_code;
97
98         /* this is changed by the destructors for the fd event
99            type. It is used to detect event destruction by event
100            handlers, which means the code that is calling the event
101            handler needs to assume that the linked list is no longer
102            valid
103         */
104         uint32_t destruction_count;
105
106 #if WITH_EPOLL
107         /* when using epoll this is the handle from epoll_create */
108         int epoll_fd;
109 #endif
110 };
111
112
113 /*
114   create a event_context structure. This must be the first events
115   call, and all subsequent calls pass this event_context as the first
116   element. Event handlers also receive this as their first argument.
117 */
118 struct event_context *event_context_init(TALLOC_CTX *mem_ctx)
119 {
120         struct event_context *ev;
121
122         ev = talloc_zero(mem_ctx, struct event_context);
123         if (!ev) return NULL;
124
125 #if WITH_EPOLL
126         ev->epoll_fd = epoll_create(64);
127 #endif
128
129         return ev;
130 }
131
132
133 /*
134   recalculate the maxfd
135 */
136 static void calc_maxfd(struct event_context *ev)
137 {
138         struct fd_event *e;
139         ev->maxfd = 0;
140         for (e=ev->fd_events; e; e=e->next) {
141                 if (e->fd > ev->maxfd) {
142                         ev->maxfd = e->fd;
143                 }
144         }
145 }
146
147
148 /* to mark the ev->maxfd invalid
149  * this means we need to recalculate it
150  */
151 #define EVENT_INVALID_MAXFD (-1)
152
153
154 #if WITH_EPOLL
155 /*
156   called when a epoll call fails, and we should fallback
157   to using select
158 */
159 static void epoll_fallback_to_select(struct event_context *ev, const char *reason)
160 {
161         DEBUG(0,("%s - using select() - %s\n", reason, strerror(errno)));
162         close(ev->epoll_fd);
163         ev->epoll_fd = -1;
164 }
165 #endif
166
167
168 #if WITH_EPOLL
169 /*
170   map from EVENT_FD_* to EPOLLIN/EPOLLOUT
171 */
172 static uint32_t epoll_map_flags(uint16_t flags)
173 {
174         uint32_t ret = 0;
175         if (flags & EVENT_FD_READ) ret |= EPOLLIN;
176         if (flags & EVENT_FD_WRITE) ret |= EPOLLOUT;
177         return ret;
178 }
179 #endif
180
181 /*
182   destroy an fd_event
183 */
184 static int event_fd_destructor(void *ptr)
185 {
186         struct fd_event *fde = talloc_get_type(ptr, struct fd_event);
187         struct event_context *ev = fde->event_ctx;
188
189         if (ev->maxfd == fde->fd) {
190                 ev->maxfd = EVENT_INVALID_MAXFD;
191         }
192         DLIST_REMOVE(ev->fd_events, fde);
193         ev->destruction_count++;
194 #if WITH_EPOLL
195         if (ev->epoll_fd != -1) {
196                 struct epoll_event event;
197                 ZERO_STRUCT(event);
198                 event.events = epoll_map_flags(fde->flags);
199                 event.data.ptr = fde;
200                 if (epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event) != 0) {
201                         epoll_fallback_to_select(ev, "EPOLL_CTL_DEL failed");
202                 }
203         }
204 #endif
205         return 0;
206 }
207
208 /*
209   add a fd based event
210   return NULL on failure (memory allocation error)
211 */
212 struct fd_event *event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx,
213                               int fd, uint16_t flags, event_fd_handler_t handler,
214                               void *private)
215 {
216         struct fd_event *e = talloc(ev, struct fd_event);
217         if (!e) return NULL;
218
219         e->event_ctx = ev;
220         e->fd        = fd;
221         e->flags     = flags;
222         e->handler   = handler;
223         e->private   = private;
224
225         DLIST_ADD(ev->fd_events, e);
226
227         if (e->fd > ev->maxfd) {
228                 ev->maxfd = e->fd;
229         }
230
231         talloc_set_destructor(e, event_fd_destructor);
232         if (mem_ctx) {
233                 talloc_steal(mem_ctx, e);
234         }
235
236 #if WITH_EPOLL
237         if (ev->epoll_fd != -1) {
238                 struct epoll_event event;
239                 ZERO_STRUCT(event);
240                 event.events = epoll_map_flags(flags);
241                 event.data.ptr = e;
242                 if (epoll_ctl(ev->epoll_fd, EPOLL_CTL_ADD, e->fd, &event) != 0) {
243                         epoll_fallback_to_select(ev, "EPOLL_CTL_ADD failed");
244                 }
245         }
246 #endif
247
248         return e;
249 }
250
251
252 /*
253   return the fd event flags
254 */
255 uint16_t event_fd_flags(struct fd_event *fde)
256 {
257         return fde?fde->flags:0;
258 }
259
260 /*
261   set the fd event flags
262 */
263 void event_fd_setflags(struct fd_event *fde, uint16_t flags)
264 {
265 #if WITH_EPOLL
266         struct event_context *ev;
267         if (fde == NULL) return;
268         ev = fde->event_ctx;
269         if (ev->epoll_fd != -1) {
270                 struct epoll_event event;
271                 ZERO_STRUCT(event);
272                 event.events = epoll_map_flags(flags);
273                 event.data.ptr = fde;
274                 if (epoll_ctl(ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) {
275                         epoll_fallback_to_select(ev, "EPOLL_CTL_MOD failed");
276                 }
277         }
278 #endif
279         if (fde) {
280                 fde->flags = flags;
281         }
282 }
283
284 /*
285   destroy a timed event
286 */
287 static int event_timed_destructor(void *ptr)
288 {
289         struct timed_event *te = talloc_get_type(ptr, struct timed_event);
290         DLIST_REMOVE(te->event_ctx->timed_events, te);
291         return 0;
292 }
293
294 /*
295   add a timed event
296   return NULL on failure (memory allocation error)
297 */
298 struct timed_event *event_add_timed(struct event_context *ev, TALLOC_CTX *mem_ctx,
299                                     struct timeval next_event, 
300                                     event_timed_handler_t handler, 
301                                     void *private) 
302 {
303         struct timed_event *te, *e;
304
305         e = talloc(mem_ctx?mem_ctx:ev, struct timed_event);
306         if (e == NULL) return NULL;
307
308         e->event_ctx  = ev;
309         e->next_event = next_event;
310         e->handler    = handler;
311         e->private    = private;
312
313         /* keep the list ordered */
314         if (ev->timed_events == NULL || 
315             timeval_compare(&e->next_event, &ev->timed_events->next_event) > 0) {
316                 DLIST_ADD(ev->timed_events, e);
317         } else {
318                 for (te=ev->timed_events;te && te->next;te=te->next) {
319                         if (!timeval_is_zero(&te->next_event) &&
320                             timeval_compare(&te->next_event, &e->next_event) < 0) {
321                                 break;
322                         }
323                 }
324                 DLIST_ADD_AFTER(ev->timed_events, e, te);
325         }
326
327         talloc_set_destructor(e, event_timed_destructor);
328
329         return e;
330 }
331
332 /*
333   a timer has gone off - call it
334 */
335 static void event_loop_timer(struct event_context *ev)
336 {
337         struct timeval t = timeval_current();
338         struct timed_event *te = ev->timed_events;
339
340         te->next_event = timeval_zero();
341
342         te->handler(ev, te, t, te->private);
343
344         /* note the care taken to prevent referencing a event
345            that could have been freed by the handler */
346         if (ev->timed_events && timeval_is_zero(&ev->timed_events->next_event)) {
347                 talloc_free(ev->timed_events);
348         }
349 }
350
351 #if WITH_EPOLL
352 /*
353   event loop handling using epoll
354 */
355 static int event_loop_epoll(struct event_context *ev, struct timeval *tvalp)
356 {
357         int ret, i;
358         const int maxevents = 8;
359         struct epoll_event events[maxevents];
360         uint32_t destruction_count = ev->destruction_count;
361         int timeout = -1;
362
363         if (tvalp) {
364                 timeout = (tvalp->tv_usec / 1000) + (tvalp->tv_sec*1000);
365         }
366
367         ret = epoll_wait(ev->epoll_fd, events, maxevents, timeout);
368
369         if (ret == -1 && errno != EINTR) {
370                 epoll_fallback_to_select(ev, "epoll_wait() failed");
371                 return -1;
372         }
373
374         if (ret == 0 && tvalp) {
375                 event_loop_timer(ev);
376                 return 0;
377         }
378
379         for (i=0;i<ret;i++) {
380                 struct fd_event *fde = talloc_get_type(events[i].data.ptr, 
381                                                        struct fd_event);
382                 uint16_t flags = 0;
383
384                 if (fde == NULL) {
385                         epoll_fallback_to_select(ev, "epoll_wait() gave bad data");
386                         return -1;
387                 }
388                 if (events[i].events & EPOLLIN) flags |= EVENT_FD_READ;
389                 if (events[i].events & EPOLLOUT) flags |= EVENT_FD_WRITE;
390                 if (flags) {
391                         fde->handler(ev, fde, flags, fde->private);
392                         if (destruction_count != ev->destruction_count) {
393                                 break;
394                         }
395                 }
396         }
397
398         return 0;
399 }               
400 #endif
401
402 /*
403   event loop handling using select()
404 */
405 static int event_loop_select(struct event_context *ev, struct timeval *tvalp)
406 {
407         fd_set r_fds, w_fds;
408         int selrtn;
409         uint32_t destruction_count = ev->destruction_count;
410         struct fd_event *fe;
411
412         /* we maybe need to recalculate the maxfd */
413         if (ev->maxfd == EVENT_INVALID_MAXFD) {
414                 calc_maxfd(ev);
415         }
416                 
417         FD_ZERO(&r_fds);
418         FD_ZERO(&w_fds);
419
420         /* setup any fd events */
421         for (fe=ev->fd_events; fe; ) {
422                 struct fd_event *next = fe->next;
423                 if (fe->flags & EVENT_FD_READ) {
424                         FD_SET(fe->fd, &r_fds);
425                 }
426                 if (fe->flags & EVENT_FD_WRITE) {
427                         FD_SET(fe->fd, &w_fds);
428                 }
429                 fe = next;
430         }
431
432         selrtn = select(ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
433                 
434         if (selrtn == -1 && errno == EBADF) {
435                 /* the socket is dead! this should never
436                    happen as the socket should have first been
437                    made readable and that should have removed
438                    the event, so this must be a bug. This is a
439                    fatal error. */
440                 DEBUG(0,("ERROR: EBADF on event_loop_once\n"));
441                 ev->exit_code = EBADF;
442                 return -1;
443         }
444
445         if (selrtn == 0 && tvalp) {
446                 event_loop_timer(ev);
447                 return 0;
448         }
449
450         if (selrtn > 0) {
451                 /* at least one file descriptor is ready - check
452                    which ones and call the handler, being careful to allow
453                    the handler to remove itself when called */
454                 for (fe=ev->fd_events; fe; fe=fe->next) {
455                         uint16_t flags = 0;
456                         if (FD_ISSET(fe->fd, &r_fds)) flags |= EVENT_FD_READ;
457                         if (FD_ISSET(fe->fd, &w_fds)) flags |= EVENT_FD_WRITE;
458                         if (flags) {
459                                 fe->handler(ev, fe, flags, fe->private);
460                                 if (destruction_count != ev->destruction_count) {
461                                         break;
462                                 }
463                         }
464                 }
465         }
466
467         return 0;
468 }               
469
470 /*
471   do a single event loop using the events defined in ev 
472 */
473 int event_loop_once(struct event_context *ev)
474 {
475         struct timeval tval, *tvalp;
476
477         tvalp = NULL;
478                 
479         /* work out the right timeout for all timed events */
480         if (ev->timed_events) {
481                 struct timeval t = timeval_current();
482                 tval = timeval_diff(&ev->timed_events->next_event, &t);
483                 tvalp = &tval;
484                 if (timeval_is_zero(tvalp)) {
485                         event_loop_timer(ev);
486                         return 0;
487                 }
488         }
489
490 #if WITH_EPOLL
491         if (ev->epoll_fd != -1) {
492                 if (event_loop_epoll(ev, tvalp) == 0) {
493                         return 0;
494                 }
495         }
496 #endif
497
498         return event_loop_select(ev, tvalp);
499 }
500
501 /*
502   go into an event loop using the events defined in ev this function
503   will return with the specified code if one of the handlers calls
504   event_loop_exit()
505
506   also return (with code 0) if all fd events are removed
507 */
508 int event_loop_wait(struct event_context *ev)
509 {
510         ev->exit_code = 0;
511         ev->maxfd = EVENT_INVALID_MAXFD;
512
513         while (ev->fd_events && ev->exit_code == 0) {
514                 if (event_loop_once(ev) != 0) {
515                         break;
516                 }
517         }
518
519         return ev->exit_code;
520 }