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