HACK epoll TEST_PANIC_FALLBACK
[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-2013
8    Copyright (C) Jeremy Allison         2013
9
10      ** NOTE! The following LGPL license applies to the tevent
11      ** library. This does NOT imply that all of Samba is released
12      ** under the LGPL
13
14    This library is free software; you can redistribute it and/or
15    modify it under the terms of the GNU Lesser General Public
16    License as published by the Free Software Foundation; either
17    version 3 of the License, or (at your option) any later version.
18
19    This library is distributed in the hope that it will be useful,
20    but WITHOUT ANY WARRANTY; without even the implied warranty of
21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22    Lesser General Public License for more details.
23
24    You should have received a copy of the GNU Lesser General Public
25    License along with this library; if not, see <http://www.gnu.org/licenses/>.
26 */
27
28 #include "replace.h"
29 #include "system/filesys.h"
30 #include "system/select.h"
31 #include "tevent.h"
32 #include "tevent_internal.h"
33 #include "tevent_util.h"
34
35 #define TEST_PANIC_FALLBACK
36
37 struct epoll_event_context {
38         /* a pointer back to the generic event_context */
39         struct tevent_context *ev;
40
41         /* when using epoll this is the handle from epoll_create */
42         int epoll_fd;
43
44         pid_t pid;
45
46         bool panic_force_replay;
47         bool *panic_state;
48         bool (*panic_fallback)(struct tevent_context *ev, bool replay);
49 };
50
51 #define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT      (1<<0)
52 #define EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR   (1<<1)
53 #define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR      (1<<2)
54 #define EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX        (1<<3)
55
56 #ifdef TEST_PANIC_FALLBACK
57
58 static int epoll_create_panic_fallback(struct epoll_event_context *epoll_ev,
59                                        int size)
60 {
61         if (epoll_ev->panic_fallback == NULL) {
62                 return epoll_create(size);
63         }
64
65         /* 50% of the time, fail... */
66         if ((random() % 2) == 0) {
67                 errno = EINVAL;
68                 return -1;
69         }
70
71         return epoll_create(size);
72 }
73
74 static int epoll_ctl_panic_fallback(struct epoll_event_context *epoll_ev,
75                                     int epfd, int op, int fd,
76                                     struct epoll_event *event)
77 {
78         if (epoll_ev->panic_fallback == NULL) {
79                 return epoll_ctl(epfd, op, fd, event);
80         }
81
82         /* 50% of the time, fail... */
83         if ((random() % 2) == 0) {
84                 errno = EINVAL;
85                 return -1;
86         }
87
88         return epoll_ctl(epfd, op, fd, event);
89 }
90
91 static int epoll_wait_panic_fallback(struct epoll_event_context *epoll_ev,
92                                      int epfd,
93                                      struct epoll_event *events,
94                                      int maxevents,
95                                      int timeout)
96 {
97         if (epoll_ev->panic_fallback == NULL) {
98                 return epoll_wait(epfd, events, maxevents, timeout);
99         }
100
101         /* 50% of the time, fail... */
102         if ((random() % 2) == 0) {
103                 errno = EINVAL;
104                 return -1;
105         }
106
107         return epoll_wait(epfd, events, maxevents, timeout);
108 }
109
110 #define epoll_create(_size) \
111         epoll_create_panic_fallback(epoll_ev, _size)
112 #define epoll_ctl(_epfd, _op, _fd, _event) \
113         epoll_ctl_panic_fallback(epoll_ev,_epfd, _op, _fd, _event)
114 #define epoll_wait(_epfd, _events, _maxevents, _timeout) \
115         epoll_wait_panic_fallback(epoll_ev, _epfd, _events, _maxevents, _timeout)
116 #endif
117
118 /*
119   called to set the panic fallback function.
120 */
121 _PRIVATE_ bool tevent_epoll_set_panic_fallback(struct tevent_context *ev,
122                                 bool (*panic_fallback)(struct tevent_context *ev,
123                                                        bool replay))
124 {
125         struct epoll_event_context *epoll_ev;
126
127         if (ev->additional_data == NULL) {
128                 return false;
129         }
130
131         epoll_ev = talloc_get_type(ev->additional_data,
132                                 struct epoll_event_context);
133         if (epoll_ev == NULL) {
134                 return false;
135         }
136         epoll_ev->panic_fallback = panic_fallback;
137         return true;
138 }
139
140 /*
141   called when a epoll call fails
142 */
143 static void epoll_panic(struct epoll_event_context *epoll_ev,
144                         const char *reason, bool replay)
145 {
146         struct tevent_context *ev = epoll_ev->ev;
147         bool (*panic_fallback)(struct tevent_context *ev, bool replay);
148
149         panic_fallback = epoll_ev->panic_fallback;
150
151         if (epoll_ev->panic_state != NULL) {
152                 *epoll_ev->panic_state = true;
153         }
154
155         if (epoll_ev->panic_force_replay) {
156                 replay = true;
157         }
158
159         TALLOC_FREE(ev->additional_data);
160
161         if (panic_fallback == NULL) {
162                 tevent_debug(ev, TEVENT_DEBUG_FATAL,
163                         "%s (%s) replay[%u] - calling abort()\n",
164                         reason, strerror(errno), (unsigned)replay);
165                 abort();
166         }
167
168         tevent_debug(ev, TEVENT_DEBUG_ERROR,
169                      "%s (%s) replay[%u] - calling panic_fallback\n",
170                      reason, strerror(errno), (unsigned)replay);
171
172         if (!panic_fallback(ev, replay)) {
173                 /* Fallback failed. */
174                 tevent_debug(ev, TEVENT_DEBUG_FATAL,
175                         "%s (%s) replay[%u] - calling abort()\n",
176                         reason, strerror(errno), (unsigned)replay);
177                 abort();
178         }
179 }
180
181 /*
182   map from TEVENT_FD_* to EPOLLIN/EPOLLOUT
183 */
184 static uint32_t epoll_map_flags(uint16_t flags)
185 {
186         uint32_t ret = 0;
187         if (flags & TEVENT_FD_READ) ret |= (EPOLLIN | EPOLLERR | EPOLLHUP);
188         if (flags & TEVENT_FD_WRITE) ret |= (EPOLLOUT | EPOLLERR | EPOLLHUP);
189         return ret;
190 }
191
192 /*
193  free the epoll fd
194 */
195 static int epoll_ctx_destructor(struct epoll_event_context *epoll_ev)
196 {
197         close(epoll_ev->epoll_fd);
198         epoll_ev->epoll_fd = -1;
199         return 0;
200 }
201
202 /*
203  init the epoll fd
204 */
205 static int epoll_init_ctx(struct epoll_event_context *epoll_ev)
206 {
207         epoll_ev->epoll_fd = epoll_create(64);
208         if (epoll_ev->epoll_fd == -1) {
209                 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
210                              "Failed to create epoll handle.\n");
211                 return -1;
212         }
213
214         if (!ev_set_close_on_exec(epoll_ev->epoll_fd)) {
215                 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_WARNING,
216                              "Failed to set close-on-exec, file descriptor may be leaked to children.\n");
217         }
218
219         epoll_ev->pid = getpid();
220         talloc_set_destructor(epoll_ev, epoll_ctx_destructor);
221
222         return 0;
223 }
224
225 static void epoll_update_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde);
226
227 /*
228   reopen the epoll handle when our pid changes
229   see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an 
230   demonstration of why this is needed
231  */
232 static void epoll_check_reopen(struct epoll_event_context *epoll_ev)
233 {
234         struct tevent_fd *fde;
235         bool *caller_panic_state = epoll_ev->panic_state;
236         bool panic_triggered = false;
237
238         if (epoll_ev->pid == getpid()) {
239                 return;
240         }
241
242         close(epoll_ev->epoll_fd);
243         epoll_ev->epoll_fd = epoll_create(64);
244         if (epoll_ev->epoll_fd == -1) {
245                 epoll_panic(epoll_ev, "epoll_create() failed", false);
246                 return;
247         }
248
249         if (!ev_set_close_on_exec(epoll_ev->epoll_fd)) {
250                 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_WARNING,
251                              "Failed to set close-on-exec, file descriptor may be leaked to children.\n");
252         }
253
254         epoll_ev->pid = getpid();
255         epoll_ev->panic_state = &panic_triggered;
256         for (fde=epoll_ev->ev->fd_events;fde;fde=fde->next) {
257                 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
258                 epoll_update_event(epoll_ev, fde);
259
260                 if (panic_triggered) {
261                         if (caller_panic_state != NULL) {
262                                 *caller_panic_state = true;
263                         }
264                         return;
265                 }
266         }
267         epoll_ev->panic_state = NULL;
268 }
269
270 /*
271  epoll cannot add the same file descriptor twice, once
272  with read, once with write which is allowed by the
273  tevent backend. Multiplex the existing fde, flag it
274  as such so we can search for the correct fde on
275  event triggering.
276 */
277
278 static int epoll_add_multiplex_fd(struct epoll_event_context *epoll_ev,
279                                   struct tevent_fd *add_fde)
280 {
281         struct epoll_event event;
282         struct tevent_fd *mpx_fde;
283         int ret;
284
285         /* Find the existing fde that caused the EEXIST error. */
286         for (mpx_fde = epoll_ev->ev->fd_events; mpx_fde; mpx_fde = mpx_fde->next) {
287                 if (mpx_fde->fd != add_fde->fd) {
288                         continue;
289                 }
290
291                 if (mpx_fde == add_fde) {
292                         continue;
293                 }
294
295                 break;
296         }
297         if (mpx_fde == NULL) {
298                 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
299                              "can't find multiplex fde for fd[%d]",
300                              add_fde->fd);
301                 return -1;
302         }
303
304         if (mpx_fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) {
305                 /* Logic error. Can't have more than 2 multiplexed fde's. */
306                 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
307                              "multiplex fde for fd[%d] is already multiplexed\n",
308                              mpx_fde->fd);
309                 return -1;
310         }
311
312         /*
313          * The multiplex fde must have the same fd, and also
314          * already have an epoll event attached.
315          */
316         if (!(mpx_fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) {
317                 /* Logic error. Can't have more than 2 multiplexed fde's. */
318                 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
319                              "multiplex fde for fd[%d] has no event\n",
320                              mpx_fde->fd);
321                 return -1;
322         }
323
324         /* Modify the orig_fde to add in the new flags. */
325         ZERO_STRUCT(event);
326         event.events = epoll_map_flags(mpx_fde->flags);
327         event.events |= epoll_map_flags(add_fde->flags);
328         event.data.ptr = mpx_fde;
329         ret = epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_MOD, mpx_fde->fd, &event);
330         if (ret != 0 && errno == EBADF) {
331                 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_ERROR,
332                              "EPOLL_CTL_MOD EBADF for "
333                              "add_fde[%p] mpx_fde[%p] fd[%d] - disabling\n",
334                              add_fde, mpx_fde, add_fde->fd);
335                 DLIST_REMOVE(epoll_ev->ev->fd_events, mpx_fde);
336                 mpx_fde->event_ctx = NULL;
337                 DLIST_REMOVE(epoll_ev->ev->fd_events, add_fde);
338                 add_fde->event_ctx = NULL;
339                 return 0;
340         } else if (ret != 0) {
341                 return ret;
342         }
343
344         /*
345          * Make each fde->additional_data pointers point at each other
346          * so we can look them up from each other. They are now paired.
347          */
348         mpx_fde->additional_data = (struct tevent_fd *)add_fde;
349         add_fde->additional_data = (struct tevent_fd *)mpx_fde;
350
351         /* Now flag both fde's as being multiplexed. */
352         mpx_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX;
353         add_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX;
354
355         /* we need to keep the GOT_ERROR flag */
356         if (mpx_fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR) {
357                 add_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR;
358         }
359
360         return 0;
361 }
362
363 /*
364  add the epoll event to the given fd_event
365 */
366 static void epoll_add_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
367 {
368         struct epoll_event event;
369         int ret;
370         struct tevent_fd *mpx_fde = NULL;
371
372         fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
373         fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
374
375         if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) {
376                 /*
377                  * This is a multiplexed fde, we need to include both
378                  * flags in the modified event.
379                  */
380                 mpx_fde = talloc_get_type_abort(fde->additional_data,
381                                                 struct tevent_fd);
382
383                 mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
384                 mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
385         }
386
387         ZERO_STRUCT(event);
388         event.events = epoll_map_flags(fde->flags);
389         if (mpx_fde != NULL) {
390                 event.events |= epoll_map_flags(mpx_fde->flags);
391         }
392         event.data.ptr = fde;
393         ret = epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event);
394         if (ret != 0 && errno == EBADF) {
395                 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_ERROR,
396                              "EPOLL_CTL_ADD EBADF for "
397                              "fde[%p] mpx_fde[%p] fd[%d] - disabling\n",
398                              fde, mpx_fde, fde->fd);
399                 DLIST_REMOVE(epoll_ev->ev->fd_events, fde);
400                 fde->event_ctx = NULL;
401                 if (mpx_fde != NULL) {
402                         DLIST_REMOVE(epoll_ev->ev->fd_events, mpx_fde);
403                         mpx_fde->event_ctx = NULL;
404                 }
405                 return;
406         } else if (ret != 0 && errno == EEXIST && mpx_fde == NULL) {
407                 ret = epoll_add_multiplex_fd(epoll_ev, fde);
408                 if (ret != 0) {
409                         epoll_panic(epoll_ev, "epoll_add_multiplex_fd failed",
410                                     false);
411                         return;
412                 }
413         } else if (ret != 0) {
414                 epoll_panic(epoll_ev, "EPOLL_CTL_ADD failed", false);
415                 return;
416         }
417
418         fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
419         /* only if we want to read we want to tell the event handler about errors */
420         if (fde->flags & TEVENT_FD_READ) {
421                 fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
422         }
423
424         if (mpx_fde == NULL) {
425                 return;
426         }
427
428         mpx_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
429         /* only if we want to read we want to tell the event handler about errors */
430         if (mpx_fde->flags & TEVENT_FD_READ) {
431                 mpx_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
432         }
433 }
434
435 /*
436  delete the epoll event for given fd_event
437 */
438 static void epoll_del_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
439 {
440         struct epoll_event event;
441         int ret;
442         struct tevent_fd *mpx_fde = NULL;
443
444         fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
445         fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
446
447         if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) {
448                 /*
449                  * This is a multiplexed fde, we need to modify both events.
450                  */
451                 mpx_fde = talloc_get_type_abort(fde->additional_data,
452                                                 struct tevent_fd);
453
454                 mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
455                 mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
456         }
457
458         ZERO_STRUCT(event);
459         ret = epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event);
460         if (ret != 0 && errno == ENOENT) {
461                 /*
462                  * This can happen after a epoll_check_reopen
463                  * within epoll_event_fd_destructor.
464                  */
465                 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_TRACE,
466                              "EPOLL_CTL_DEL ignoring ENOENT for fd[%d]\n",
467                              fde->fd);
468                 return;
469         } else if (ret != 0 && errno == EBADF) {
470                 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_WARNING,
471                              "EPOLL_CTL_DEL EBADF for "
472                              "fde[%p] mpx_fde[%p] fd[%d] - disabling\n",
473                              fde, mpx_fde, fde->fd);
474                 DLIST_REMOVE(epoll_ev->ev->fd_events, fde);
475                 fde->event_ctx = NULL;
476                 if (mpx_fde != NULL) {
477                         DLIST_REMOVE(epoll_ev->ev->fd_events, mpx_fde);
478                         mpx_fde->event_ctx = NULL;
479                 }
480                 return;
481         } else if (ret != 0) {
482                 epoll_panic(epoll_ev, "EPOLL_CTL_DEL failed", false);
483                 return;
484         }
485 }
486
487 /*
488  change the epoll event to the given fd_event
489 */
490 static void epoll_mod_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
491 {
492         struct tevent_fd *mpx_fde = NULL;
493         struct epoll_event event;
494         int ret;
495
496         fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
497         fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
498
499         if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) {
500                 /*
501                  * This is a multiplexed fde, we need to include both
502                  * flags in the modified event.
503                  */
504                 mpx_fde = talloc_get_type_abort(fde->additional_data,
505                                                 struct tevent_fd);
506
507                 mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
508                 mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
509         }
510
511         ZERO_STRUCT(event);
512         event.events = epoll_map_flags(fde->flags);
513         if (mpx_fde != NULL) {
514                 event.events |= epoll_map_flags(mpx_fde->flags);
515         }
516         event.data.ptr = fde;
517         ret = epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event);
518         if (ret != 0 && errno == EBADF) {
519                 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_ERROR,
520                              "EPOLL_CTL_MOD EBADF for "
521                              "fde[%p] mpx_fde[%p] fd[%d] - disabling\n",
522                              fde, mpx_fde, fde->fd);
523                 DLIST_REMOVE(epoll_ev->ev->fd_events, fde);
524                 fde->event_ctx = NULL;
525                 if (mpx_fde != NULL) {
526                         DLIST_REMOVE(epoll_ev->ev->fd_events, mpx_fde);
527                         mpx_fde->event_ctx = NULL;
528                 }
529                 return;
530         } else if (ret != 0) {
531                 epoll_panic(epoll_ev, "EPOLL_CTL_MOD failed", false);
532                 return;
533         }
534
535         fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
536         /* only if we want to read we want to tell the event handler about errors */
537         if (fde->flags & TEVENT_FD_READ) {
538                 fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
539         }
540
541         if (mpx_fde == NULL) {
542                 return;
543         }
544
545         mpx_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
546         /* only if we want to read we want to tell the event handler about errors */
547         if (mpx_fde->flags & TEVENT_FD_READ) {
548                 mpx_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
549         }
550 }
551
552 static void epoll_update_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
553 {
554         bool got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR);
555         bool want_read = (fde->flags & TEVENT_FD_READ);
556         bool want_write= (fde->flags & TEVENT_FD_WRITE);
557         struct tevent_fd *mpx_fde = NULL;
558
559         if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) {
560                 /*
561                  * work out what the multiplexed fde wants.
562                  */
563                 mpx_fde = talloc_get_type_abort(fde->additional_data,
564                                                 struct tevent_fd);
565
566                 if (mpx_fde->flags & TEVENT_FD_READ) {
567                         want_read = true;
568                 }
569
570                 if (mpx_fde->flags & TEVENT_FD_WRITE) {
571                         want_write = true;
572                 }
573         }
574
575         /* there's already an event */
576         if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT) {
577                 if (want_read || (want_write && !got_error)) {
578                         epoll_mod_event(epoll_ev, fde);
579                         return;
580                 }
581                 /* 
582                  * if we want to match the select behavior, we need to remove the epoll_event
583                  * when the caller isn't interested in events.
584                  *
585                  * this is because epoll reports EPOLLERR and EPOLLHUP, even without asking for them
586                  */
587                 epoll_del_event(epoll_ev, fde);
588                 return;
589         }
590
591         /* there's no epoll_event attached to the fde */
592         if (want_read || (want_write && !got_error)) {
593                 epoll_add_event(epoll_ev, fde);
594                 return;
595         }
596 }
597
598 /*
599   Cope with epoll returning EPOLLHUP|EPOLLERR on an event.
600   Return true if there's nothing else to do, false if
601   this event needs further handling.
602 */
603 static bool epoll_handle_hup_or_err(struct epoll_event_context *epoll_ev,
604                                 struct tevent_fd *fde)
605 {
606         if (fde == NULL) {
607                 /* Nothing to do if no event. */
608                 return true;
609         }
610
611         fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR;
612         /*
613          * if we only wait for TEVENT_FD_WRITE, we should not tell the
614          * event handler about it, and remove the epoll_event,
615          * as we only report errors when waiting for read events,
616          * to match the select() behavior
617          */
618         if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR)) {
619                 /*
620                  * Do the same as the poll backend and
621                  * remove the writeable flag.
622                  */
623                 fde->flags &= ~TEVENT_FD_WRITE;
624                 return true;
625         }
626         /* This has TEVENT_FD_READ set, we're not finished. */
627         return false;
628 }
629
630 /*
631   event loop handling using epoll
632 */
633 static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval *tvalp)
634 {
635         int ret, i;
636 #define MAXEVENTS 1
637         struct epoll_event events[MAXEVENTS];
638         int timeout = -1;
639         int wait_errno;
640
641         if (tvalp) {
642                 /* it's better to trigger timed events a bit later than too early */
643                 timeout = ((tvalp->tv_usec+999) / 1000) + (tvalp->tv_sec*1000);
644         }
645
646         if (epoll_ev->ev->signal_events &&
647             tevent_common_check_signal(epoll_ev->ev)) {
648                 return 0;
649         }
650
651         tevent_trace_point_callback(epoll_ev->ev, TEVENT_TRACE_BEFORE_WAIT);
652         ret = epoll_wait(epoll_ev->epoll_fd, events, MAXEVENTS, timeout);
653         wait_errno = errno;
654         tevent_trace_point_callback(epoll_ev->ev, TEVENT_TRACE_AFTER_WAIT);
655
656         if (ret == -1 && wait_errno == EINTR && epoll_ev->ev->signal_events) {
657                 if (tevent_common_check_signal(epoll_ev->ev)) {
658                         return 0;
659                 }
660         }
661
662         if (ret == -1 && wait_errno != EINTR) {
663                 epoll_panic(epoll_ev, "epoll_wait() failed", true);
664                 return -1;
665         }
666
667         if (ret == 0 && tvalp) {
668                 /* we don't care about a possible delay here */
669                 tevent_common_loop_timer_delay(epoll_ev->ev);
670                 return 0;
671         }
672
673         for (i=0;i<ret;i++) {
674                 struct tevent_fd *fde = talloc_get_type(events[i].data.ptr, 
675                                                        struct tevent_fd);
676                 uint16_t flags = 0;
677                 struct tevent_fd *mpx_fde = NULL;
678
679                 if (fde == NULL) {
680                         epoll_panic(epoll_ev, "epoll_wait() gave bad data", true);
681                         return -1;
682                 }
683                 if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) {
684                         /*
685                          * Save off the multiplexed event in case we need
686                          * to use it to call the handler function.
687                          */
688                         mpx_fde = talloc_get_type_abort(fde->additional_data,
689                                                         struct tevent_fd);
690                 }
691                 if (events[i].events & (EPOLLHUP|EPOLLERR)) {
692                         bool handled_fde = epoll_handle_hup_or_err(epoll_ev, fde);
693                         bool handled_mpx = epoll_handle_hup_or_err(epoll_ev, mpx_fde);
694
695                         if (handled_fde && handled_mpx) {
696                                 epoll_update_event(epoll_ev, fde);
697                                 continue;
698                         }
699
700                         if (!handled_mpx) {
701                                 /*
702                                  * If the mpx event was the one that needs
703                                  * further handling, it's the TEVENT_FD_READ
704                                  * event so switch over and call that handler.
705                                  */
706                                 fde = mpx_fde;
707                                 mpx_fde = NULL;
708                         }
709                         flags |= TEVENT_FD_READ;
710                 }
711                 if (events[i].events & EPOLLIN) flags |= TEVENT_FD_READ;
712                 if (events[i].events & EPOLLOUT) flags |= TEVENT_FD_WRITE;
713
714                 if (flags & TEVENT_FD_WRITE) {
715                         if (fde->flags & TEVENT_FD_WRITE) {
716                                 mpx_fde = NULL;
717                         }
718                         if (mpx_fde && mpx_fde->flags & TEVENT_FD_WRITE) {
719                                 fde = mpx_fde;
720                                 mpx_fde = NULL;
721                         }
722                 }
723
724                 if (mpx_fde) {
725                         /* Ensure we got the right fde. */
726                         if ((flags & fde->flags) == 0) {
727                                 fde = mpx_fde;
728                                 mpx_fde = NULL;
729                         }
730                 }
731
732                 /*
733                  * make sure we only pass the flags
734                  * the handler is expecting.
735                  */
736                 flags &= fde->flags;
737                 if (flags) {
738                         fde->handler(epoll_ev->ev, fde, flags, fde->private_data);
739                         break;
740                 }
741         }
742
743         return 0;
744 }
745
746 /*
747   create a epoll_event_context structure.
748 */
749 static int epoll_event_context_init(struct tevent_context *ev)
750 {
751         int ret;
752         struct epoll_event_context *epoll_ev;
753
754         /*
755          * We might be called during tevent_re_initialise()
756          * which means we need to free our old additional_data.
757          */
758         TALLOC_FREE(ev->additional_data);
759
760         epoll_ev = talloc_zero(ev, struct epoll_event_context);
761         if (!epoll_ev) return -1;
762         epoll_ev->ev = ev;
763         epoll_ev->epoll_fd = -1;
764
765         ret = epoll_init_ctx(epoll_ev);
766         if (ret != 0) {
767                 talloc_free(epoll_ev);
768                 return ret;
769         }
770
771         ev->additional_data = epoll_ev;
772         return 0;
773 }
774
775 /*
776   destroy an fd_event
777 */
778 static int epoll_event_fd_destructor(struct tevent_fd *fde)
779 {
780         struct tevent_context *ev = fde->event_ctx;
781         struct epoll_event_context *epoll_ev = NULL;
782         bool panic_triggered = false;
783         struct tevent_fd *mpx_fde = NULL;
784         int flags = fde->flags;
785
786         if (ev == NULL) {
787                 return tevent_common_fd_destructor(fde);
788         }
789
790         epoll_ev = talloc_get_type_abort(ev->additional_data,
791                                          struct epoll_event_context);
792
793         /*
794          * we must remove the event from the list
795          * otherwise a panic fallback handler may
796          * reuse invalid memory
797          */
798         DLIST_REMOVE(ev->fd_events, fde);
799
800         if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) {
801                 mpx_fde = talloc_get_type_abort(fde->additional_data,
802                                                 struct tevent_fd);
803
804                 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX;
805                 mpx_fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX;
806
807                 fde->additional_data = NULL;
808                 mpx_fde->additional_data = NULL;
809
810                 fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
811         }
812
813         epoll_ev->panic_state = &panic_triggered;
814         epoll_check_reopen(epoll_ev);
815         if (panic_triggered) {
816                 return tevent_common_fd_destructor(fde);
817         }
818
819         if (mpx_fde != NULL) {
820                 epoll_update_event(epoll_ev, mpx_fde);
821                 if (panic_triggered) {
822                         return tevent_common_fd_destructor(fde);
823                 }
824         }
825
826         fde->flags = 0;
827         epoll_update_event(epoll_ev, fde);
828         fde->flags = flags;
829         if (panic_triggered) {
830                 return tevent_common_fd_destructor(fde);
831         }
832         epoll_ev->panic_state = NULL;
833
834         return tevent_common_fd_destructor(fde);
835 }
836
837 /*
838   add a fd based event
839   return NULL on failure (memory allocation error)
840 */
841 static struct tevent_fd *epoll_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
842                                             int fd, uint16_t flags,
843                                             tevent_fd_handler_t handler,
844                                             void *private_data,
845                                             const char *handler_name,
846                                             const char *location)
847 {
848         struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data,
849                                                            struct epoll_event_context);
850         struct tevent_fd *fde;
851         bool panic_triggered = false;
852
853         fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
854                                    handler, private_data,
855                                    handler_name, location);
856         if (!fde) return NULL;
857
858         talloc_set_destructor(fde, epoll_event_fd_destructor);
859
860         epoll_ev->panic_state = &panic_triggered;
861         epoll_check_reopen(epoll_ev);
862         if (panic_triggered) {
863                 return fde;
864         }
865         epoll_ev->panic_state = NULL;
866
867         epoll_update_event(epoll_ev, fde);
868
869         return fde;
870 }
871
872 /*
873   set the fd event flags
874 */
875 static void epoll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
876 {
877         struct tevent_context *ev;
878         struct epoll_event_context *epoll_ev;
879         bool panic_triggered = false;
880
881         if (fde->flags == flags) return;
882
883         ev = fde->event_ctx;
884         epoll_ev = talloc_get_type(ev->additional_data, struct epoll_event_context);
885
886         fde->flags = flags;
887
888         epoll_ev->panic_state = &panic_triggered;
889         epoll_check_reopen(epoll_ev);
890         if (panic_triggered) {
891                 return;
892         }
893         epoll_ev->panic_state = NULL;
894
895         epoll_update_event(epoll_ev, fde);
896 }
897
898 /*
899   do a single event loop using the events defined in ev 
900 */
901 static int epoll_event_loop_once(struct tevent_context *ev, const char *location)
902 {
903         struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data,
904                                                            struct epoll_event_context);
905         struct timeval tval;
906         bool panic_triggered = false;
907
908         if (ev->signal_events &&
909             tevent_common_check_signal(ev)) {
910                 return 0;
911         }
912
913         if (ev->immediate_events &&
914             tevent_common_loop_immediate(ev)) {
915                 return 0;
916         }
917
918         tval = tevent_common_loop_timer_delay(ev);
919         if (tevent_timeval_is_zero(&tval)) {
920                 return 0;
921         }
922
923         epoll_ev->panic_state = &panic_triggered;
924         epoll_ev->panic_force_replay = true;
925         epoll_check_reopen(epoll_ev);
926         if (panic_triggered) {
927                 errno = EINVAL;
928                 return -1;
929         }
930         epoll_ev->panic_force_replay = false;
931         epoll_ev->panic_state = NULL;
932
933         return epoll_event_loop(epoll_ev, &tval);
934 }
935
936 static const struct tevent_ops epoll_event_ops = {
937         .context_init           = epoll_event_context_init,
938         .add_fd                 = epoll_event_add_fd,
939         .set_fd_close_fn        = tevent_common_fd_set_close_fn,
940         .get_fd_flags           = tevent_common_fd_get_flags,
941         .set_fd_flags           = epoll_event_set_fd_flags,
942         .add_timer              = tevent_common_add_timer_v2,
943         .schedule_immediate     = tevent_common_schedule_immediate,
944         .add_signal             = tevent_common_add_signal,
945         .loop_once              = epoll_event_loop_once,
946         .loop_wait              = tevent_common_loop_wait,
947 };
948
949 _PRIVATE_ bool tevent_epoll_init(void)
950 {
951         return tevent_register_backend("epoll", &epoll_event_ops);
952 }