tevent: avoid any operation on epoll_ev after a epoll_panic()
[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
271         if (epoll_ev->epoll_fd == -1) return;
272
273         fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
274
275         /* if we don't want events yet, don't add an epoll_event */
276         if (fde->flags == 0) return;
277
278         ZERO_STRUCT(event);
279         event.events = epoll_map_flags(fde->flags);
280         event.data.ptr = fde;
281         if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event) != 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
300         if (epoll_ev->epoll_fd == -1) return;
301
302         fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
303
304         /* if there's no epoll_event, we don't need to delete it */
305         if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) return;
306
307         ZERO_STRUCT(event);
308         event.events = epoll_map_flags(fde->flags);
309         event.data.ptr = fde;
310         if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event) != 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         if (epoll_ev->epoll_fd == -1) return;
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         if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) {
332                 epoll_panic(epoll_ev, "EPOLL_CTL_MOD failed", false);
333                 return;
334         }
335
336         /* only if we want to read we want to tell the event handler about errors */
337         if (fde->flags & TEVENT_FD_READ) {
338                 fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
339         }
340 }
341
342 static void epoll_change_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
343 {
344         bool got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR);
345         bool want_read = (fde->flags & TEVENT_FD_READ);
346         bool want_write= (fde->flags & TEVENT_FD_WRITE);
347
348         if (epoll_ev->epoll_fd == -1) return;
349
350         fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
351
352         /* there's already an event */
353         if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT) {
354                 if (want_read || (want_write && !got_error)) {
355                         epoll_mod_event(epoll_ev, fde);
356                         return;
357                 }
358                 /* 
359                  * if we want to match the select behavior, we need to remove the epoll_event
360                  * when the caller isn't interested in events.
361                  *
362                  * this is because epoll reports EPOLLERR and EPOLLHUP, even without asking for them
363                  */
364                 epoll_del_event(epoll_ev, fde);
365                 return;
366         }
367
368         /* there's no epoll_event attached to the fde */
369         if (want_read || (want_write && !got_error)) {
370                 epoll_add_event(epoll_ev, fde);
371                 return;
372         }
373 }
374
375 /*
376   event loop handling using epoll
377 */
378 static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval *tvalp)
379 {
380         int ret, i;
381 #define MAXEVENTS 1
382         struct epoll_event events[MAXEVENTS];
383         int timeout = -1;
384         int wait_errno;
385
386         if (epoll_ev->epoll_fd == -1) return -1;
387
388         if (tvalp) {
389                 /* it's better to trigger timed events a bit later than too early */
390                 timeout = ((tvalp->tv_usec+999) / 1000) + (tvalp->tv_sec*1000);
391         }
392
393         if (epoll_ev->ev->signal_events &&
394             tevent_common_check_signal(epoll_ev->ev)) {
395                 return 0;
396         }
397
398         tevent_trace_point_callback(epoll_ev->ev, TEVENT_TRACE_BEFORE_WAIT);
399         ret = epoll_wait(epoll_ev->epoll_fd, events, MAXEVENTS, timeout);
400         wait_errno = errno;
401         tevent_trace_point_callback(epoll_ev->ev, TEVENT_TRACE_AFTER_WAIT);
402
403         if (ret == -1 && wait_errno == EINTR && epoll_ev->ev->signal_events) {
404                 if (tevent_common_check_signal(epoll_ev->ev)) {
405                         return 0;
406                 }
407         }
408
409         if (ret == -1 && wait_errno != EINTR) {
410                 epoll_panic(epoll_ev, "epoll_wait() failed", true);
411                 return -1;
412         }
413
414         if (ret == 0 && tvalp) {
415                 /* we don't care about a possible delay here */
416                 tevent_common_loop_timer_delay(epoll_ev->ev);
417                 return 0;
418         }
419
420         for (i=0;i<ret;i++) {
421                 struct tevent_fd *fde = talloc_get_type(events[i].data.ptr, 
422                                                        struct tevent_fd);
423                 uint16_t flags = 0;
424
425                 if (fde == NULL) {
426                         epoll_panic(epoll_ev, "epoll_wait() gave bad data", true);
427                         return -1;
428                 }
429                 if (events[i].events & (EPOLLHUP|EPOLLERR)) {
430                         fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR;
431                         /*
432                          * if we only wait for TEVENT_FD_WRITE, we should not tell the
433                          * event handler about it, and remove the epoll_event,
434                          * as we only report errors when waiting for read events,
435                          * to match the select() behavior
436                          */
437                         if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR)) {
438                                 epoll_del_event(epoll_ev, fde);
439                                 continue;
440                         }
441                         flags |= TEVENT_FD_READ;
442                 }
443                 if (events[i].events & EPOLLIN) flags |= TEVENT_FD_READ;
444                 if (events[i].events & EPOLLOUT) flags |= TEVENT_FD_WRITE;
445                 if (flags) {
446                         fde->handler(epoll_ev->ev, fde, flags, fde->private_data);
447                         break;
448                 }
449         }
450
451         return 0;
452 }
453
454 /*
455   create a epoll_event_context structure.
456 */
457 static int epoll_event_context_init(struct tevent_context *ev)
458 {
459         int ret;
460         struct epoll_event_context *epoll_ev;
461
462         /*
463          * We might be called during tevent_re_initialise()
464          * which means we need to free our old additional_data.
465          */
466         TALLOC_FREE(ev->additional_data);
467
468         epoll_ev = talloc_zero(ev, struct epoll_event_context);
469         if (!epoll_ev) return -1;
470         epoll_ev->ev = ev;
471         epoll_ev->epoll_fd = -1;
472
473         ret = epoll_init_ctx(epoll_ev);
474         if (ret != 0) {
475                 talloc_free(epoll_ev);
476                 return ret;
477         }
478
479         ev->additional_data = epoll_ev;
480         return 0;
481 }
482
483 /*
484   destroy an fd_event
485 */
486 static int epoll_event_fd_destructor(struct tevent_fd *fde)
487 {
488         struct tevent_context *ev = fde->event_ctx;
489         struct epoll_event_context *epoll_ev = NULL;
490         bool panic_triggered = false;
491
492         if (ev == NULL) {
493                 return tevent_common_fd_destructor(fde);
494         }
495
496         epoll_ev = talloc_get_type_abort(ev->additional_data,
497                                          struct epoll_event_context);
498
499         /*
500          * we must remove the event from the list
501          * otherwise a panic fallback handler may
502          * reuse invalid memory
503          */
504         DLIST_REMOVE(ev->fd_events, fde);
505
506         epoll_ev->panic_state = &panic_triggered;
507         epoll_check_reopen(epoll_ev);
508         if (panic_triggered) {
509                 return tevent_common_fd_destructor(fde);
510         }
511
512         epoll_del_event(epoll_ev, fde);
513         if (panic_triggered) {
514                 return tevent_common_fd_destructor(fde);
515         }
516         epoll_ev->panic_state = NULL;
517
518         return tevent_common_fd_destructor(fde);
519 }
520
521 /*
522   add a fd based event
523   return NULL on failure (memory allocation error)
524 */
525 static struct tevent_fd *epoll_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
526                                             int fd, uint16_t flags,
527                                             tevent_fd_handler_t handler,
528                                             void *private_data,
529                                             const char *handler_name,
530                                             const char *location)
531 {
532         struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data,
533                                                            struct epoll_event_context);
534         struct tevent_fd *fde;
535         bool panic_triggered = false;
536
537         fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
538                                    handler, private_data,
539                                    handler_name, location);
540         if (!fde) return NULL;
541
542         talloc_set_destructor(fde, epoll_event_fd_destructor);
543
544         epoll_ev->panic_state = &panic_triggered;
545         epoll_check_reopen(epoll_ev);
546         if (panic_triggered) {
547                 return fde;
548         }
549         epoll_ev->panic_state = NULL;
550
551         epoll_add_event(epoll_ev, fde);
552
553         return fde;
554 }
555
556 /*
557   set the fd event flags
558 */
559 static void epoll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
560 {
561         struct tevent_context *ev;
562         struct epoll_event_context *epoll_ev;
563         bool panic_triggered = false;
564
565         if (fde->flags == flags) return;
566
567         ev = fde->event_ctx;
568         epoll_ev = talloc_get_type(ev->additional_data, struct epoll_event_context);
569
570         fde->flags = flags;
571
572         epoll_ev->panic_state = &panic_triggered;
573         epoll_check_reopen(epoll_ev);
574         if (panic_triggered) {
575                 return;
576         }
577         epoll_ev->panic_state = NULL;
578
579         epoll_change_event(epoll_ev, fde);
580 }
581
582 /*
583   do a single event loop using the events defined in ev 
584 */
585 static int epoll_event_loop_once(struct tevent_context *ev, const char *location)
586 {
587         struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data,
588                                                            struct epoll_event_context);
589         struct timeval tval;
590         bool panic_triggered = false;
591
592         if (ev->signal_events &&
593             tevent_common_check_signal(ev)) {
594                 return 0;
595         }
596
597         if (ev->immediate_events &&
598             tevent_common_loop_immediate(ev)) {
599                 return 0;
600         }
601
602         tval = tevent_common_loop_timer_delay(ev);
603         if (tevent_timeval_is_zero(&tval)) {
604                 return 0;
605         }
606
607         epoll_ev->panic_state = &panic_triggered;
608         epoll_ev->panic_force_replay = true;
609         epoll_check_reopen(epoll_ev);
610         if (panic_triggered) {
611                 errno = EINVAL;
612                 return -1;
613         }
614         epoll_ev->panic_force_replay = false;
615         epoll_ev->panic_state = NULL;
616
617         return epoll_event_loop(epoll_ev, &tval);
618 }
619
620 static const struct tevent_ops epoll_event_ops = {
621         .context_init           = epoll_event_context_init,
622         .add_fd                 = epoll_event_add_fd,
623         .set_fd_close_fn        = tevent_common_fd_set_close_fn,
624         .get_fd_flags           = tevent_common_fd_get_flags,
625         .set_fd_flags           = epoll_event_set_fd_flags,
626         .add_timer              = tevent_common_add_timer,
627         .schedule_immediate     = tevent_common_schedule_immediate,
628         .add_signal             = tevent_common_add_signal,
629         .loop_once              = epoll_event_loop_once,
630         .loop_wait              = tevent_common_loop_wait,
631 };
632
633 _PRIVATE_ bool tevent_epoll_init(void)
634 {
635         return tevent_register_backend("epoll", &epoll_event_ops);
636 }