tevent: use helper variables to hold the epoll_ctl() result
[metze/samba/wip.git] / lib / tevent / tevent_epoll.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    main select loop and event handling - epoll implementation
5
6    Copyright (C) Andrew Tridgell        2003-2005
7    Copyright (C) Stefan Metzmacher      2005-2009
8
9      ** NOTE! The following LGPL license applies to the tevent
10      ** library. This does NOT imply that all of Samba is released
11      ** under the LGPL
12
13    This library is free software; you can redistribute it and/or
14    modify it under the terms of the GNU Lesser General Public
15    License as published by the Free Software Foundation; either
16    version 3 of the License, or (at your option) any later version.
17
18    This library is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21    Lesser General Public License for more details.
22
23    You should have received a copy of the GNU Lesser General Public
24    License along with this library; if not, see <http://www.gnu.org/licenses/>.
25 */
26
27 #include "replace.h"
28 #include "system/filesys.h"
29 #include "system/select.h"
30 #include "tevent.h"
31 #include "tevent_internal.h"
32 #include "tevent_util.h"
33
34 struct epoll_event_context {
35         /* a pointer back to the generic event_context */
36         struct tevent_context *ev;
37
38         /* when using epoll this is the handle from epoll_create */
39         int epoll_fd;
40
41         pid_t pid;
42
43         bool panic_force_replay;
44         bool *panic_state;
45         bool (*panic_fallback)(struct tevent_context *ev, bool replay);
46 };
47
48 #ifdef TEST_PANIC_FALLBACK
49
50 static int epoll_create_panic_fallback(struct epoll_event_context *epoll_ev,
51                                        int size)
52 {
53         if (epoll_ev->panic_fallback == NULL) {
54                 return epoll_create(size);
55         }
56
57         /* 50% of the time, fail... */
58         if ((random() % 2) == 0) {
59                 errno = EINVAL;
60                 return -1;
61         }
62
63         return epoll_create(size);
64 }
65
66 static int epoll_ctl_panic_fallback(struct epoll_event_context *epoll_ev,
67                                     int epfd, int op, int fd,
68                                     struct epoll_event *event)
69 {
70         if (epoll_ev->panic_fallback == NULL) {
71                 return epoll_ctl(epfd, op, fd, event);
72         }
73
74         /* 50% of the time, fail... */
75         if ((random() % 2) == 0) {
76                 errno = EINVAL;
77                 return -1;
78         }
79
80         return epoll_ctl(epfd, op, fd, event);
81 }
82
83 static int epoll_wait_panic_fallback(struct epoll_event_context *epoll_ev,
84                                      int epfd,
85                                      struct epoll_event *events,
86                                      int maxevents,
87                                      int timeout)
88 {
89         if (epoll_ev->panic_fallback == NULL) {
90                 return epoll_wait(epfd, events, maxevents, timeout);
91         }
92
93         /* 50% of the time, fail... */
94         if ((random() % 2) == 0) {
95                 errno = EINVAL;
96                 return -1;
97         }
98
99         return epoll_wait(epfd, events, maxevents, timeout);
100 }
101
102 #define epoll_create(_size) \
103         epoll_create_panic_fallback(epoll_ev, _size)
104 #define epoll_ctl(_epfd, _op, _fd, _event) \
105         epoll_ctl_panic_fallback(epoll_ev,_epfd, _op, _fd, _event)
106 #define epoll_wait(_epfd, _events, _maxevents, _timeout) \
107         epoll_wait_panic_fallback(epoll_ev, _epfd, _events, _maxevents, _timeout)
108 #endif
109
110 /*
111   called to set the panic fallback function.
112 */
113 _PRIVATE_ bool tevent_epoll_set_panic_fallback(struct tevent_context *ev,
114                                 bool (*panic_fallback)(struct tevent_context *ev,
115                                                        bool replay))
116 {
117         struct epoll_event_context *epoll_ev;
118
119         if (ev->additional_data == NULL) {
120                 return false;
121         }
122
123         epoll_ev = talloc_get_type(ev->additional_data,
124                                 struct epoll_event_context);
125         if (epoll_ev == NULL) {
126                 return false;
127         }
128         epoll_ev->panic_fallback = panic_fallback;
129         return true;
130 }
131
132 /*
133   called when a epoll call fails
134 */
135 static void epoll_panic(struct epoll_event_context *epoll_ev,
136                         const char *reason, bool replay)
137 {
138         struct tevent_context *ev = epoll_ev->ev;
139         bool (*panic_fallback)(struct tevent_context *ev, bool replay);
140
141         panic_fallback = epoll_ev->panic_fallback;
142
143         if (epoll_ev->panic_state != NULL) {
144                 *epoll_ev->panic_state = true;
145         }
146
147         if (epoll_ev->panic_force_replay) {
148                 replay = true;
149         }
150
151         TALLOC_FREE(ev->additional_data);
152
153         if (panic_fallback == NULL) {
154                 tevent_debug(ev, TEVENT_DEBUG_FATAL,
155                         "%s (%s) replay[%u] - calling abort()\n",
156                         reason, strerror(errno), (unsigned)replay);
157                 abort();
158         }
159
160         tevent_debug(ev, TEVENT_DEBUG_WARNING,
161                      "%s (%s) replay[%u] - calling panic_fallback\n",
162                      reason, strerror(errno), (unsigned)replay);
163
164         if (!panic_fallback(ev, replay)) {
165                 /* Fallback failed. */
166                 tevent_debug(ev, TEVENT_DEBUG_FATAL,
167                         "%s (%s) replay[%u] - calling abort()\n",
168                         reason, strerror(errno), (unsigned)replay);
169                 abort();
170         }
171 }
172
173 /*
174   map from TEVENT_FD_* to EPOLLIN/EPOLLOUT
175 */
176 static uint32_t epoll_map_flags(uint16_t flags)
177 {
178         uint32_t ret = 0;
179         if (flags & TEVENT_FD_READ) ret |= (EPOLLIN | EPOLLERR | EPOLLHUP);
180         if (flags & TEVENT_FD_WRITE) ret |= (EPOLLOUT | EPOLLERR | EPOLLHUP);
181         return ret;
182 }
183
184 /*
185  free the epoll fd
186 */
187 static int epoll_ctx_destructor(struct epoll_event_context *epoll_ev)
188 {
189         close(epoll_ev->epoll_fd);
190         epoll_ev->epoll_fd = -1;
191         return 0;
192 }
193
194 /*
195  init the epoll fd
196 */
197 static int epoll_init_ctx(struct epoll_event_context *epoll_ev)
198 {
199         epoll_ev->epoll_fd = epoll_create(64);
200         if (epoll_ev->epoll_fd == -1) {
201                 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
202                              "Failed to create epoll handle.\n");
203                 return -1;
204         }
205
206         if (!ev_set_close_on_exec(epoll_ev->epoll_fd)) {
207                 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_WARNING,
208                              "Failed to set close-on-exec, file descriptor may be leaked to children.\n");
209         }
210
211         epoll_ev->pid = getpid();
212         talloc_set_destructor(epoll_ev, epoll_ctx_destructor);
213
214         return 0;
215 }
216
217 static void epoll_add_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde);
218
219 /*
220   reopen the epoll handle when our pid changes
221   see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an 
222   demonstration of why this is needed
223  */
224 static void epoll_check_reopen(struct epoll_event_context *epoll_ev)
225 {
226         struct tevent_fd *fde;
227         bool *caller_panic_state = epoll_ev->panic_state;
228         bool panic_triggered = false;
229
230         if (epoll_ev->pid == getpid()) {
231                 return;
232         }
233
234         close(epoll_ev->epoll_fd);
235         epoll_ev->epoll_fd = epoll_create(64);
236         if (epoll_ev->epoll_fd == -1) {
237                 epoll_panic(epoll_ev, "epoll_create() failed", false);
238                 return;
239         }
240
241         if (!ev_set_close_on_exec(epoll_ev->epoll_fd)) {
242                 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_WARNING,
243                              "Failed to set close-on-exec, file descriptor may be leaked to children.\n");
244         }
245
246         epoll_ev->pid = getpid();
247         epoll_ev->panic_state = &panic_triggered;
248         for (fde=epoll_ev->ev->fd_events;fde;fde=fde->next) {
249                 epoll_add_event(epoll_ev, fde);
250                 if (panic_triggered) {
251                         if (caller_panic_state != NULL) {
252                                 *caller_panic_state = true;
253                         }
254                         return;
255                 }
256         }
257         epoll_ev->panic_state = NULL;
258 }
259
260 #define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT      (1<<0)
261 #define EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR   (1<<1)
262 #define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR      (1<<2)
263
264 /*
265  add the epoll event to the given fd_event
266 */
267 static void epoll_add_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
268 {
269         struct epoll_event event;
270         int ret;
271
272         fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
273
274         /* if we don't want events yet, don't add an epoll_event */
275         if (fde->flags == 0) return;
276
277         ZERO_STRUCT(event);
278         event.events = epoll_map_flags(fde->flags);
279         event.data.ptr = fde;
280         ret = epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event);
281         if (ret != 0) {
282                 epoll_panic(epoll_ev, "EPOLL_CTL_ADD failed", false);
283                 return;
284         }
285         fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
286
287         /* only if we want to read we want to tell the event handler about errors */
288         if (fde->flags & TEVENT_FD_READ) {
289                 fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
290         }
291 }
292
293 /*
294  delete the epoll event for given fd_event
295 */
296 static void epoll_del_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
297 {
298         struct epoll_event event;
299         int ret;
300
301         fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
302
303         /* if there's no epoll_event, we don't need to delete it */
304         if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) return;
305
306         ZERO_STRUCT(event);
307         event.events = epoll_map_flags(fde->flags);
308         event.data.ptr = fde;
309         ret = epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event);
310         if (ret != 0) {
311                 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
312                              "epoll_del_event failed! probable early close bug (%s)\n",
313                              strerror(errno));
314         }
315         fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
316 }
317
318 /*
319  change the epoll event to the given fd_event
320 */
321 static void epoll_mod_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
322 {
323         struct epoll_event event;
324         int ret;
325
326         fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
327
328         ZERO_STRUCT(event);
329         event.events = epoll_map_flags(fde->flags);
330         event.data.ptr = fde;
331         ret = epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event);
332         if (ret != 0) {
333                 epoll_panic(epoll_ev, "EPOLL_CTL_MOD failed", false);
334                 return;
335         }
336
337         /* only if we want to read we want to tell the event handler about errors */
338         if (fde->flags & TEVENT_FD_READ) {
339                 fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
340         }
341 }
342
343 static void epoll_change_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
344 {
345         bool got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR);
346         bool want_read = (fde->flags & TEVENT_FD_READ);
347         bool want_write= (fde->flags & TEVENT_FD_WRITE);
348
349         fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
350
351         /* there's already an event */
352         if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT) {
353                 if (want_read || (want_write && !got_error)) {
354                         epoll_mod_event(epoll_ev, fde);
355                         return;
356                 }
357                 /* 
358                  * if we want to match the select behavior, we need to remove the epoll_event
359                  * when the caller isn't interested in events.
360                  *
361                  * this is because epoll reports EPOLLERR and EPOLLHUP, even without asking for them
362                  */
363                 epoll_del_event(epoll_ev, fde);
364                 return;
365         }
366
367         /* there's no epoll_event attached to the fde */
368         if (want_read || (want_write && !got_error)) {
369                 epoll_add_event(epoll_ev, fde);
370                 return;
371         }
372 }
373
374 /*
375   event loop handling using epoll
376 */
377 static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval *tvalp)
378 {
379         int ret, i;
380 #define MAXEVENTS 1
381         struct epoll_event events[MAXEVENTS];
382         int timeout = -1;
383         int wait_errno;
384
385         if (tvalp) {
386                 /* it's better to trigger timed events a bit later than too early */
387                 timeout = ((tvalp->tv_usec+999) / 1000) + (tvalp->tv_sec*1000);
388         }
389
390         if (epoll_ev->ev->signal_events &&
391             tevent_common_check_signal(epoll_ev->ev)) {
392                 return 0;
393         }
394
395         tevent_trace_point_callback(epoll_ev->ev, TEVENT_TRACE_BEFORE_WAIT);
396         ret = epoll_wait(epoll_ev->epoll_fd, events, MAXEVENTS, timeout);
397         wait_errno = errno;
398         tevent_trace_point_callback(epoll_ev->ev, TEVENT_TRACE_AFTER_WAIT);
399
400         if (ret == -1 && wait_errno == EINTR && epoll_ev->ev->signal_events) {
401                 if (tevent_common_check_signal(epoll_ev->ev)) {
402                         return 0;
403                 }
404         }
405
406         if (ret == -1 && wait_errno != EINTR) {
407                 epoll_panic(epoll_ev, "epoll_wait() failed", true);
408                 return -1;
409         }
410
411         if (ret == 0 && tvalp) {
412                 /* we don't care about a possible delay here */
413                 tevent_common_loop_timer_delay(epoll_ev->ev);
414                 return 0;
415         }
416
417         for (i=0;i<ret;i++) {
418                 struct tevent_fd *fde = talloc_get_type(events[i].data.ptr, 
419                                                        struct tevent_fd);
420                 uint16_t flags = 0;
421
422                 if (fde == NULL) {
423                         epoll_panic(epoll_ev, "epoll_wait() gave bad data", true);
424                         return -1;
425                 }
426                 if (events[i].events & (EPOLLHUP|EPOLLERR)) {
427                         fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR;
428                         /*
429                          * if we only wait for TEVENT_FD_WRITE, we should not tell the
430                          * event handler about it, and remove the epoll_event,
431                          * as we only report errors when waiting for read events,
432                          * to match the select() behavior
433                          */
434                         if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR)) {
435                                 epoll_del_event(epoll_ev, fde);
436                                 continue;
437                         }
438                         flags |= TEVENT_FD_READ;
439                 }
440                 if (events[i].events & EPOLLIN) flags |= TEVENT_FD_READ;
441                 if (events[i].events & EPOLLOUT) flags |= TEVENT_FD_WRITE;
442                 if (flags) {
443                         fde->handler(epoll_ev->ev, fde, flags, fde->private_data);
444                         break;
445                 }
446         }
447
448         return 0;
449 }
450
451 /*
452   create a epoll_event_context structure.
453 */
454 static int epoll_event_context_init(struct tevent_context *ev)
455 {
456         int ret;
457         struct epoll_event_context *epoll_ev;
458
459         /*
460          * We might be called during tevent_re_initialise()
461          * which means we need to free our old additional_data.
462          */
463         TALLOC_FREE(ev->additional_data);
464
465         epoll_ev = talloc_zero(ev, struct epoll_event_context);
466         if (!epoll_ev) return -1;
467         epoll_ev->ev = ev;
468         epoll_ev->epoll_fd = -1;
469
470         ret = epoll_init_ctx(epoll_ev);
471         if (ret != 0) {
472                 talloc_free(epoll_ev);
473                 return ret;
474         }
475
476         ev->additional_data = epoll_ev;
477         return 0;
478 }
479
480 /*
481   destroy an fd_event
482 */
483 static int epoll_event_fd_destructor(struct tevent_fd *fde)
484 {
485         struct tevent_context *ev = fde->event_ctx;
486         struct epoll_event_context *epoll_ev = NULL;
487         bool panic_triggered = false;
488
489         if (ev == NULL) {
490                 return tevent_common_fd_destructor(fde);
491         }
492
493         epoll_ev = talloc_get_type_abort(ev->additional_data,
494                                          struct epoll_event_context);
495
496         /*
497          * we must remove the event from the list
498          * otherwise a panic fallback handler may
499          * reuse invalid memory
500          */
501         DLIST_REMOVE(ev->fd_events, fde);
502
503         epoll_ev->panic_state = &panic_triggered;
504         epoll_check_reopen(epoll_ev);
505         if (panic_triggered) {
506                 return tevent_common_fd_destructor(fde);
507         }
508
509         epoll_del_event(epoll_ev, fde);
510         if (panic_triggered) {
511                 return tevent_common_fd_destructor(fde);
512         }
513         epoll_ev->panic_state = NULL;
514
515         return tevent_common_fd_destructor(fde);
516 }
517
518 /*
519   add a fd based event
520   return NULL on failure (memory allocation error)
521 */
522 static struct tevent_fd *epoll_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
523                                             int fd, uint16_t flags,
524                                             tevent_fd_handler_t handler,
525                                             void *private_data,
526                                             const char *handler_name,
527                                             const char *location)
528 {
529         struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data,
530                                                            struct epoll_event_context);
531         struct tevent_fd *fde;
532         bool panic_triggered = false;
533
534         fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
535                                    handler, private_data,
536                                    handler_name, location);
537         if (!fde) return NULL;
538
539         talloc_set_destructor(fde, epoll_event_fd_destructor);
540
541         epoll_ev->panic_state = &panic_triggered;
542         epoll_check_reopen(epoll_ev);
543         if (panic_triggered) {
544                 return fde;
545         }
546         epoll_ev->panic_state = NULL;
547
548         epoll_add_event(epoll_ev, fde);
549
550         return fde;
551 }
552
553 /*
554   set the fd event flags
555 */
556 static void epoll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
557 {
558         struct tevent_context *ev;
559         struct epoll_event_context *epoll_ev;
560         bool panic_triggered = false;
561
562         if (fde->flags == flags) return;
563
564         ev = fde->event_ctx;
565         epoll_ev = talloc_get_type(ev->additional_data, struct epoll_event_context);
566
567         fde->flags = flags;
568
569         epoll_ev->panic_state = &panic_triggered;
570         epoll_check_reopen(epoll_ev);
571         if (panic_triggered) {
572                 return;
573         }
574         epoll_ev->panic_state = NULL;
575
576         epoll_change_event(epoll_ev, fde);
577 }
578
579 /*
580   do a single event loop using the events defined in ev 
581 */
582 static int epoll_event_loop_once(struct tevent_context *ev, const char *location)
583 {
584         struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data,
585                                                            struct epoll_event_context);
586         struct timeval tval;
587         bool panic_triggered = false;
588
589         if (ev->signal_events &&
590             tevent_common_check_signal(ev)) {
591                 return 0;
592         }
593
594         if (ev->immediate_events &&
595             tevent_common_loop_immediate(ev)) {
596                 return 0;
597         }
598
599         tval = tevent_common_loop_timer_delay(ev);
600         if (tevent_timeval_is_zero(&tval)) {
601                 return 0;
602         }
603
604         epoll_ev->panic_state = &panic_triggered;
605         epoll_ev->panic_force_replay = true;
606         epoll_check_reopen(epoll_ev);
607         if (panic_triggered) {
608                 errno = EINVAL;
609                 return -1;
610         }
611         epoll_ev->panic_force_replay = false;
612         epoll_ev->panic_state = NULL;
613
614         return epoll_event_loop(epoll_ev, &tval);
615 }
616
617 static const struct tevent_ops epoll_event_ops = {
618         .context_init           = epoll_event_context_init,
619         .add_fd                 = epoll_event_add_fd,
620         .set_fd_close_fn        = tevent_common_fd_set_close_fn,
621         .get_fd_flags           = tevent_common_fd_get_flags,
622         .set_fd_flags           = epoll_event_set_fd_flags,
623         .add_timer              = tevent_common_add_timer,
624         .schedule_immediate     = tevent_common_schedule_immediate,
625         .add_signal             = tevent_common_add_signal,
626         .loop_once              = epoll_event_loop_once,
627         .loop_wait              = tevent_common_loop_wait,
628 };
629
630 _PRIVATE_ bool tevent_epoll_init(void)
631 {
632         return tevent_register_backend("epoll", &epoll_event_ops);
633 }