r5217: avoid epoll_ctl() if the event flags are already set correctly
[bbaumbach/samba-autobuild/.git] / source4 / lib / events / 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 "lib/events/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 (%s) - falling back to select()\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                 epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event);
201         }
202 #endif
203         return 0;
204 }
205
206 /*
207   add a fd based event
208   return NULL on failure (memory allocation error)
209 */
210 struct fd_event *event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx,
211                               int fd, uint16_t flags, event_fd_handler_t handler,
212                               void *private)
213 {
214         struct fd_event *e = talloc(ev, struct fd_event);
215         if (!e) return NULL;
216
217         e->event_ctx = ev;
218         e->fd        = fd;
219         e->flags     = flags;
220         e->handler   = handler;
221         e->private   = private;
222
223         DLIST_ADD(ev->fd_events, e);
224
225         if (e->fd > ev->maxfd) {
226                 ev->maxfd = e->fd;
227         }
228
229         talloc_set_destructor(e, event_fd_destructor);
230         if (mem_ctx) {
231                 talloc_steal(mem_ctx, e);
232         }
233
234 #if WITH_EPOLL
235         if (ev->epoll_fd != -1) {
236                 struct epoll_event event;
237                 ZERO_STRUCT(event);
238                 event.events = epoll_map_flags(flags);
239                 event.data.ptr = e;
240                 if (epoll_ctl(ev->epoll_fd, EPOLL_CTL_ADD, e->fd, &event) != 0) {
241                         epoll_fallback_to_select(ev, "EPOLL_CTL_ADD failed");
242                 }
243         }
244 #endif
245
246         return e;
247 }
248
249
250 /*
251   return the fd event flags
252 */
253 uint16_t event_fd_flags(struct fd_event *fde)
254 {
255         return fde?fde->flags:0;
256 }
257
258 /*
259   set the fd event flags
260 */
261 void event_fd_setflags(struct fd_event *fde, uint16_t flags)
262 {
263 #if WITH_EPOLL
264         struct event_context *ev;
265         if (fde == NULL || 
266             fde->flags == flags) {
267                 return;
268         }
269         ev = fde->event_ctx;
270         if (ev->epoll_fd != -1) {
271                 struct epoll_event event;
272                 ZERO_STRUCT(event);
273                 event.events = epoll_map_flags(flags);
274                 event.data.ptr = fde;
275                 if (epoll_ctl(ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) {
276                         epoll_fallback_to_select(ev, "EPOLL_CTL_MOD failed");
277                 }
278         }
279 #endif
280         if (fde) {
281                 fde->flags = flags;
282         }
283 }
284
285 /*
286   destroy a timed event
287 */
288 static int event_timed_destructor(void *ptr)
289 {
290         struct timed_event *te = talloc_get_type(ptr, struct timed_event);
291         DLIST_REMOVE(te->event_ctx->timed_events, te);
292         return 0;
293 }
294
295 /*
296   add a timed event
297   return NULL on failure (memory allocation error)
298 */
299 struct timed_event *event_add_timed(struct event_context *ev, TALLOC_CTX *mem_ctx,
300                                     struct timeval next_event, 
301                                     event_timed_handler_t handler, 
302                                     void *private) 
303 {
304         struct timed_event *te, *e;
305
306         e = talloc(mem_ctx?mem_ctx:ev, struct timed_event);
307         if (e == NULL) return NULL;
308
309         e->event_ctx  = ev;
310         e->next_event = next_event;
311         e->handler    = handler;
312         e->private    = private;
313
314         /* keep the list ordered */
315         if (ev->timed_events == NULL || 
316             timeval_compare(&e->next_event, &ev->timed_events->next_event) > 0) {
317                 DLIST_ADD(ev->timed_events, e);
318         } else {
319                 for (te=ev->timed_events;te && te->next;te=te->next) {
320                         if (!timeval_is_zero(&te->next_event) &&
321                             timeval_compare(&te->next_event, &e->next_event) < 0) {
322                                 break;
323                         }
324                 }
325                 DLIST_ADD_AFTER(ev->timed_events, e, te);
326         }
327
328         talloc_set_destructor(e, event_timed_destructor);
329
330         return e;
331 }
332
333 /*
334   a timer has gone off - call it
335 */
336 static void event_loop_timer(struct event_context *ev)
337 {
338         struct timeval t = timeval_current();
339         struct timed_event *te = ev->timed_events;
340
341         te->next_event = timeval_zero();
342
343         te->handler(ev, te, t, te->private);
344
345         /* note the care taken to prevent referencing a event
346            that could have been freed by the handler */
347         if (ev->timed_events && timeval_is_zero(&ev->timed_events->next_event)) {
348                 talloc_free(ev->timed_events);
349         }
350 }
351
352 #if WITH_EPOLL
353 /*
354   event loop handling using epoll
355 */
356 static int event_loop_epoll(struct event_context *ev, struct timeval *tvalp)
357 {
358         int ret, i;
359         const int maxevents = 8;
360         struct epoll_event events[maxevents];
361         uint32_t destruction_count = ev->destruction_count;
362         int timeout = -1;
363
364         if (tvalp) {
365                 timeout = (tvalp->tv_usec / 1000) + (tvalp->tv_sec*1000);
366         }
367
368         ret = epoll_wait(ev->epoll_fd, events, maxevents, timeout);
369
370         if (ret == -1 && errno != EINTR) {
371                 epoll_fallback_to_select(ev, "epoll_wait() failed");
372                 return -1;
373         }
374
375         if (ret == 0 && tvalp) {
376                 event_loop_timer(ev);
377                 return 0;
378         }
379
380         for (i=0;i<ret;i++) {
381                 struct fd_event *fde = talloc_get_type(events[i].data.ptr, 
382                                                        struct fd_event);
383                 uint16_t flags = 0;
384
385                 if (fde == NULL) {
386                         epoll_fallback_to_select(ev, "epoll_wait() gave bad data");
387                         return -1;
388                 }
389                 if (events[i].events & EPOLLIN) flags |= EVENT_FD_READ;
390                 if (events[i].events & EPOLLOUT) flags |= EVENT_FD_WRITE;
391                 if (flags) {
392                         fde->handler(ev, fde, flags, fde->private);
393                         if (destruction_count != ev->destruction_count) {
394                                 break;
395                         }
396                 }
397         }
398
399         return 0;
400 }               
401 #endif
402
403 /*
404   event loop handling using select()
405 */
406 static int event_loop_select(struct event_context *ev, struct timeval *tvalp)
407 {
408         fd_set r_fds, w_fds;
409         int selrtn;
410         uint32_t destruction_count = ev->destruction_count;
411         struct fd_event *fe;
412
413         /* we maybe need to recalculate the maxfd */
414         if (ev->maxfd == EVENT_INVALID_MAXFD) {
415                 calc_maxfd(ev);
416         }
417                 
418         FD_ZERO(&r_fds);
419         FD_ZERO(&w_fds);
420
421         /* setup any fd events */
422         for (fe=ev->fd_events; fe; ) {
423                 struct fd_event *next = fe->next;
424                 if (fe->flags & EVENT_FD_READ) {
425                         FD_SET(fe->fd, &r_fds);
426                 }
427                 if (fe->flags & EVENT_FD_WRITE) {
428                         FD_SET(fe->fd, &w_fds);
429                 }
430                 fe = next;
431         }
432
433         selrtn = select(ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
434                 
435         if (selrtn == -1 && errno == EBADF) {
436                 /* the socket is dead! this should never
437                    happen as the socket should have first been
438                    made readable and that should have removed
439                    the event, so this must be a bug. This is a
440                    fatal error. */
441                 DEBUG(0,("ERROR: EBADF on event_loop_once\n"));
442                 ev->exit_code = EBADF;
443                 return -1;
444         }
445
446         if (selrtn == 0 && tvalp) {
447                 event_loop_timer(ev);
448                 return 0;
449         }
450
451         if (selrtn > 0) {
452                 /* at least one file descriptor is ready - check
453                    which ones and call the handler, being careful to allow
454                    the handler to remove itself when called */
455                 for (fe=ev->fd_events; fe; fe=fe->next) {
456                         uint16_t flags = 0;
457                         if (FD_ISSET(fe->fd, &r_fds)) flags |= EVENT_FD_READ;
458                         if (FD_ISSET(fe->fd, &w_fds)) flags |= EVENT_FD_WRITE;
459                         if (flags) {
460                                 fe->handler(ev, fe, flags, fe->private);
461                                 if (destruction_count != ev->destruction_count) {
462                                         break;
463                                 }
464                         }
465                 }
466         }
467
468         return 0;
469 }               
470
471 /*
472   do a single event loop using the events defined in ev 
473 */
474 int event_loop_once(struct event_context *ev)
475 {
476         struct timeval tval, *tvalp;
477
478         tvalp = NULL;
479                 
480         /* work out the right timeout for all timed events */
481         if (ev->timed_events) {
482                 struct timeval t = timeval_current();
483                 tval = timeval_diff(&ev->timed_events->next_event, &t);
484                 tvalp = &tval;
485                 if (timeval_is_zero(tvalp)) {
486                         event_loop_timer(ev);
487                         return 0;
488                 }
489         }
490
491 #if WITH_EPOLL
492         if (ev->epoll_fd != -1) {
493                 if (event_loop_epoll(ev, tvalp) == 0) {
494                         return 0;
495                 }
496         }
497 #endif
498
499         return event_loop_select(ev, tvalp);
500 }
501
502 /*
503   go into an event loop using the events defined in ev this function
504   will return with the specified code if one of the handlers calls
505   event_loop_exit()
506
507   also return (with code 0) if all fd events are removed
508 */
509 int event_loop_wait(struct event_context *ev)
510 {
511         ev->exit_code = 0;
512         ev->maxfd = EVENT_INVALID_MAXFD;
513
514         while (ev->fd_events && ev->exit_code == 0) {
515                 if (event_loop_once(ev) != 0) {
516                         break;
517                 }
518         }
519
520         return ev->exit_code;
521 }