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