tevent: Plumb in the panic fallback code into the epoll_panic() runtime call.
[obnox/samba/samba-obnox.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_fallback)(struct tevent_context *ev, bool replay);
44 };
45
46 /*
47   called to set the panic fallback function.
48 */
49 _PRIVATE_ bool tevent_epoll_set_panic_fallback(struct tevent_context *ev,
50                                 bool (*panic_fallback)(struct tevent_context *ev,
51                                                        bool replay))
52 {
53         struct epoll_event_context *epoll_ev;
54
55         if (ev->additional_data == NULL) {
56                 return false;
57         }
58
59         epoll_ev = talloc_get_type(ev->additional_data,
60                                 struct epoll_event_context);
61         if (epoll_ev == NULL) {
62                 return false;
63         }
64         epoll_ev->panic_fallback = panic_fallback;
65         return true;
66 }
67
68 /*
69   called when a epoll call fails
70 */
71 static void epoll_panic(struct epoll_event_context *epoll_ev,
72                         const char *reason, bool replay)
73 {
74         struct tevent_context *ev = epoll_ev->ev;
75
76         if (epoll_ev->panic_fallback == NULL) {
77                 tevent_debug(ev, TEVENT_DEBUG_FATAL,
78                         "%s (%s) replay[%u] - calling abort()\n",
79                         reason, strerror(errno), (unsigned)replay);
80                 abort();
81         }
82
83         tevent_debug(ev, TEVENT_DEBUG_WARNING,
84                      "%s (%s) replay[%u] - calling panic_fallback\n",
85                      reason, strerror(errno), (unsigned)replay);
86
87         if (!epoll_ev->panic_fallback(ev, replay)) {
88                 /* Fallback failed. */
89                 tevent_debug(ev, TEVENT_DEBUG_FATAL,
90                         "%s (%s) replay[%u] - calling abort()\n",
91                         reason, strerror(errno), (unsigned)replay);
92                 abort();
93         }
94 }
95
96 /*
97   map from TEVENT_FD_* to EPOLLIN/EPOLLOUT
98 */
99 static uint32_t epoll_map_flags(uint16_t flags)
100 {
101         uint32_t ret = 0;
102         if (flags & TEVENT_FD_READ) ret |= (EPOLLIN | EPOLLERR | EPOLLHUP);
103         if (flags & TEVENT_FD_WRITE) ret |= (EPOLLOUT | EPOLLERR | EPOLLHUP);
104         return ret;
105 }
106
107 /*
108  free the epoll fd
109 */
110 static int epoll_ctx_destructor(struct epoll_event_context *epoll_ev)
111 {
112         close(epoll_ev->epoll_fd);
113         epoll_ev->epoll_fd = -1;
114         return 0;
115 }
116
117 /*
118  init the epoll fd
119 */
120 static int epoll_init_ctx(struct epoll_event_context *epoll_ev)
121 {
122         epoll_ev->epoll_fd = epoll_create(64);
123         if (epoll_ev->epoll_fd == -1) {
124                 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
125                              "Failed to create epoll handle.\n");
126                 return -1;
127         }
128
129         if (!ev_set_close_on_exec(epoll_ev->epoll_fd)) {
130                 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_WARNING,
131                              "Failed to set close-on-exec, file descriptor may be leaked to children.\n");
132         }
133
134         epoll_ev->pid = getpid();
135         talloc_set_destructor(epoll_ev, epoll_ctx_destructor);
136
137         return 0;
138 }
139
140 static void epoll_add_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde);
141
142 /*
143   reopen the epoll handle when our pid changes
144   see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an 
145   demonstration of why this is needed
146  */
147 static void epoll_check_reopen(struct epoll_event_context *epoll_ev)
148 {
149         struct tevent_fd *fde;
150
151         if (epoll_ev->pid == getpid()) {
152                 return;
153         }
154
155         close(epoll_ev->epoll_fd);
156         epoll_ev->epoll_fd = epoll_create(64);
157         if (epoll_ev->epoll_fd == -1) {
158                 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
159                              "Failed to recreate epoll handle after fork\n");
160                 return;
161         }
162
163         if (!ev_set_close_on_exec(epoll_ev->epoll_fd)) {
164                 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_WARNING,
165                              "Failed to set close-on-exec, file descriptor may be leaked to children.\n");
166         }
167
168         epoll_ev->pid = getpid();
169         for (fde=epoll_ev->ev->fd_events;fde;fde=fde->next) {
170                 epoll_add_event(epoll_ev, fde);
171         }
172 }
173
174 #define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT      (1<<0)
175 #define EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR   (1<<1)
176 #define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR      (1<<2)
177
178 /*
179  add the epoll event to the given fd_event
180 */
181 static void epoll_add_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
182 {
183         struct epoll_event event;
184
185         if (epoll_ev->epoll_fd == -1) return;
186
187         fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
188
189         /* if we don't want events yet, don't add an epoll_event */
190         if (fde->flags == 0) return;
191
192         ZERO_STRUCT(event);
193         event.events = epoll_map_flags(fde->flags);
194         event.data.ptr = fde;
195         if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event) != 0) {
196                 epoll_panic(epoll_ev, "EPOLL_CTL_ADD failed", false);
197                 return;
198         }
199         fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
200
201         /* only if we want to read we want to tell the event handler about errors */
202         if (fde->flags & TEVENT_FD_READ) {
203                 fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
204         }
205 }
206
207 /*
208  delete the epoll event for given fd_event
209 */
210 static void epoll_del_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
211 {
212         struct epoll_event event;
213
214         if (epoll_ev->epoll_fd == -1) return;
215
216         fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
217
218         /* if there's no epoll_event, we don't need to delete it */
219         if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) return;
220
221         ZERO_STRUCT(event);
222         event.events = epoll_map_flags(fde->flags);
223         event.data.ptr = fde;
224         if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event) != 0) {
225                 tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
226                              "epoll_del_event failed! probable early close bug (%s)\n",
227                              strerror(errno));
228         }
229         fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
230 }
231
232 /*
233  change the epoll event to the given fd_event
234 */
235 static void epoll_mod_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
236 {
237         struct epoll_event event;
238         if (epoll_ev->epoll_fd == -1) return;
239
240         fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
241
242         ZERO_STRUCT(event);
243         event.events = epoll_map_flags(fde->flags);
244         event.data.ptr = fde;
245         if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) {
246                 epoll_panic(epoll_ev, "EPOLL_CTL_MOD failed", false);
247                 return;
248         }
249
250         /* only if we want to read we want to tell the event handler about errors */
251         if (fde->flags & TEVENT_FD_READ) {
252                 fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
253         }
254 }
255
256 static void epoll_change_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
257 {
258         bool got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR);
259         bool want_read = (fde->flags & TEVENT_FD_READ);
260         bool want_write= (fde->flags & TEVENT_FD_WRITE);
261
262         if (epoll_ev->epoll_fd == -1) return;
263
264         fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
265
266         /* there's already an event */
267         if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT) {
268                 if (want_read || (want_write && !got_error)) {
269                         epoll_mod_event(epoll_ev, fde);
270                         return;
271                 }
272                 /* 
273                  * if we want to match the select behavior, we need to remove the epoll_event
274                  * when the caller isn't interested in events.
275                  *
276                  * this is because epoll reports EPOLLERR and EPOLLHUP, even without asking for them
277                  */
278                 epoll_del_event(epoll_ev, fde);
279                 return;
280         }
281
282         /* there's no epoll_event attached to the fde */
283         if (want_read || (want_write && !got_error)) {
284                 epoll_add_event(epoll_ev, fde);
285                 return;
286         }
287 }
288
289 /*
290   event loop handling using epoll
291 */
292 static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval *tvalp)
293 {
294         int ret, i;
295 #define MAXEVENTS 1
296         struct epoll_event events[MAXEVENTS];
297         int timeout = -1;
298
299         if (epoll_ev->epoll_fd == -1) return -1;
300
301         if (tvalp) {
302                 /* it's better to trigger timed events a bit later than to early */
303                 timeout = ((tvalp->tv_usec+999) / 1000) + (tvalp->tv_sec*1000);
304         }
305
306         if (epoll_ev->ev->signal_events &&
307             tevent_common_check_signal(epoll_ev->ev)) {
308                 return 0;
309         }
310
311         tevent_trace_point_callback(epoll_ev->ev, TEVENT_TRACE_BEFORE_WAIT);
312         ret = epoll_wait(epoll_ev->epoll_fd, events, MAXEVENTS, timeout);
313         tevent_trace_point_callback(epoll_ev->ev, TEVENT_TRACE_AFTER_WAIT);
314
315         if (ret == -1 && errno == EINTR && epoll_ev->ev->signal_events) {
316                 if (tevent_common_check_signal(epoll_ev->ev)) {
317                         return 0;
318                 }
319         }
320
321         if (ret == -1 && errno != EINTR) {
322                 epoll_panic(epoll_ev, "epoll_wait() failed", true);
323                 return -1;
324         }
325
326         if (ret == 0 && tvalp) {
327                 /* we don't care about a possible delay here */
328                 tevent_common_loop_timer_delay(epoll_ev->ev);
329                 return 0;
330         }
331
332         for (i=0;i<ret;i++) {
333                 struct tevent_fd *fde = talloc_get_type(events[i].data.ptr, 
334                                                        struct tevent_fd);
335                 uint16_t flags = 0;
336
337                 if (fde == NULL) {
338                         epoll_panic(epoll_ev, "epoll_wait() gave bad data", true);
339                         return -1;
340                 }
341                 if (events[i].events & (EPOLLHUP|EPOLLERR)) {
342                         fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR;
343                         /*
344                          * if we only wait for TEVENT_FD_WRITE, we should not tell the
345                          * event handler about it, and remove the epoll_event,
346                          * as we only report errors when waiting for read events,
347                          * to match the select() behavior
348                          */
349                         if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR)) {
350                                 epoll_del_event(epoll_ev, fde);
351                                 continue;
352                         }
353                         flags |= TEVENT_FD_READ;
354                 }
355                 if (events[i].events & EPOLLIN) flags |= TEVENT_FD_READ;
356                 if (events[i].events & EPOLLOUT) flags |= TEVENT_FD_WRITE;
357                 if (flags) {
358                         fde->handler(epoll_ev->ev, fde, flags, fde->private_data);
359                         break;
360                 }
361         }
362
363         return 0;
364 }
365
366 /*
367   create a epoll_event_context structure.
368 */
369 static int epoll_event_context_init(struct tevent_context *ev)
370 {
371         int ret;
372         struct epoll_event_context *epoll_ev;
373
374         epoll_ev = talloc_zero(ev, struct epoll_event_context);
375         if (!epoll_ev) return -1;
376         epoll_ev->ev = ev;
377         epoll_ev->epoll_fd = -1;
378
379         ret = epoll_init_ctx(epoll_ev);
380         if (ret != 0) {
381                 talloc_free(epoll_ev);
382                 return ret;
383         }
384
385         ev->additional_data = epoll_ev;
386         return 0;
387 }
388
389 /*
390   destroy an fd_event
391 */
392 static int epoll_event_fd_destructor(struct tevent_fd *fde)
393 {
394         struct tevent_context *ev = fde->event_ctx;
395         struct epoll_event_context *epoll_ev = NULL;
396
397         if (ev) {
398                 epoll_ev = talloc_get_type(ev->additional_data,
399                                            struct epoll_event_context);
400
401                 epoll_check_reopen(epoll_ev);
402
403                 epoll_del_event(epoll_ev, fde);
404         }
405
406         return tevent_common_fd_destructor(fde);
407 }
408
409 /*
410   add a fd based event
411   return NULL on failure (memory allocation error)
412 */
413 static struct tevent_fd *epoll_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
414                                             int fd, uint16_t flags,
415                                             tevent_fd_handler_t handler,
416                                             void *private_data,
417                                             const char *handler_name,
418                                             const char *location)
419 {
420         struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data,
421                                                            struct epoll_event_context);
422         struct tevent_fd *fde;
423
424         epoll_check_reopen(epoll_ev);
425
426         fde = tevent_common_add_fd(ev, mem_ctx, fd, flags,
427                                    handler, private_data,
428                                    handler_name, location);
429         if (!fde) return NULL;
430
431         talloc_set_destructor(fde, epoll_event_fd_destructor);
432
433         epoll_add_event(epoll_ev, fde);
434
435         return fde;
436 }
437
438 /*
439   set the fd event flags
440 */
441 static void epoll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
442 {
443         struct tevent_context *ev;
444         struct epoll_event_context *epoll_ev;
445
446         if (fde->flags == flags) return;
447
448         ev = fde->event_ctx;
449         epoll_ev = talloc_get_type(ev->additional_data, struct epoll_event_context);
450
451         fde->flags = flags;
452
453         epoll_check_reopen(epoll_ev);
454
455         epoll_change_event(epoll_ev, fde);
456 }
457
458 /*
459   do a single event loop using the events defined in ev 
460 */
461 static int epoll_event_loop_once(struct tevent_context *ev, const char *location)
462 {
463         struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data,
464                                                            struct epoll_event_context);
465         struct timeval tval;
466
467         if (ev->signal_events &&
468             tevent_common_check_signal(ev)) {
469                 return 0;
470         }
471
472         if (ev->immediate_events &&
473             tevent_common_loop_immediate(ev)) {
474                 return 0;
475         }
476
477         tval = tevent_common_loop_timer_delay(ev);
478         if (tevent_timeval_is_zero(&tval)) {
479                 return 0;
480         }
481
482         epoll_check_reopen(epoll_ev);
483
484         return epoll_event_loop(epoll_ev, &tval);
485 }
486
487 static const struct tevent_ops epoll_event_ops = {
488         .context_init           = epoll_event_context_init,
489         .add_fd                 = epoll_event_add_fd,
490         .set_fd_close_fn        = tevent_common_fd_set_close_fn,
491         .get_fd_flags           = tevent_common_fd_get_flags,
492         .set_fd_flags           = epoll_event_set_fd_flags,
493         .add_timer              = tevent_common_add_timer,
494         .schedule_immediate     = tevent_common_schedule_immediate,
495         .add_signal             = tevent_common_add_signal,
496         .loop_once              = epoll_event_loop_once,
497         .loop_wait              = tevent_common_loop_wait,
498 };
499
500 _PRIVATE_ bool tevent_epoll_init(void)
501 {
502         return tevent_register_backend("epoll", &epoll_event_ops);
503 }