r25027: Fix more warnings.
[samba.git] / source4 / lib / events / events_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 "includes.h"
24 #include "system/filesys.h"
25 #include "system/network.h"
26 #include "lib/util/dlinklist.h"
27 #include "lib/events/events.h"
28 #include "lib/events/events_internal.h"
29 #include <sys/epoll.h>
30
31 struct epoll_event_context {
32         /* a pointer back to the generic event_context */
33         struct event_context *ev;
34
35         /* list of filedescriptor events */
36         struct fd_event *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 _NORETURN_ static void epoll_panic(struct epoll_event_context *epoll_ev, const char *reason)
60 {
61         DEBUG(0,("%s (%s) - calling abort()\n", reason, strerror(errno)));
62         abort();
63 }
64
65 /*
66   map from EVENT_FD_* to EPOLLIN/EPOLLOUT
67 */
68 static uint32_t epoll_map_flags(uint16_t flags)
69 {
70         uint32_t ret = 0;
71         if (flags & EVENT_FD_READ) ret |= (EPOLLIN | EPOLLERR | EPOLLHUP);
72         if (flags & EVENT_FD_WRITE) ret |= (EPOLLOUT | EPOLLERR | EPOLLHUP);
73         return ret;
74 }
75
76 /*
77  free the epoll fd
78 */
79 static int epoll_ctx_destructor(struct epoll_event_context *epoll_ev)
80 {
81         close(epoll_ev->epoll_fd);
82         epoll_ev->epoll_fd = -1;
83         return 0;
84 }
85
86 /*
87  init the epoll fd
88 */
89 static int epoll_init_ctx(struct epoll_event_context *epoll_ev)
90 {
91         epoll_ev->epoll_fd = epoll_create(64);
92         epoll_ev->pid = getpid();
93         talloc_set_destructor(epoll_ev, epoll_ctx_destructor);
94         if (epoll_ev->epoll_fd == -1) {
95                 return -1;
96         }
97         return 0;
98 }
99
100 static void epoll_add_event(struct epoll_event_context *epoll_ev, struct fd_event *fde);
101
102 /*
103   reopen the epoll handle when our pid changes
104   see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an 
105   demonstration of why this is needed
106  */
107 static void epoll_check_reopen(struct epoll_event_context *epoll_ev)
108 {
109         struct fd_event *fde;
110
111         if (epoll_ev->pid == getpid()) {
112                 return;
113         }
114
115         close(epoll_ev->epoll_fd);
116         epoll_ev->epoll_fd = epoll_create(64);
117         if (epoll_ev->epoll_fd == -1) {
118                 DEBUG(0,("Failed to recreate epoll handle after fork\n"));
119                 return;
120         }
121         epoll_ev->pid = getpid();
122         for (fde=epoll_ev->fd_events;fde;fde=fde->next) {
123                 epoll_add_event(epoll_ev, fde);
124         }
125 }
126
127 #define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT      (1<<0)
128 #define EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR   (1<<1)
129 #define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR      (1<<2)
130
131 /*
132  add the epoll event to the given fd_event
133 */
134 static void epoll_add_event(struct epoll_event_context *epoll_ev, struct fd_event *fde)
135 {
136         struct epoll_event event;
137
138         if (epoll_ev->epoll_fd == -1) return;
139
140         fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
141
142         /* if we don't want events yet, don't add an epoll_event */
143         if (fde->flags == 0) return;
144
145         ZERO_STRUCT(event);
146         event.events = epoll_map_flags(fde->flags);
147         event.data.ptr = fde;
148         if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event) != 0) {
149                 epoll_panic(epoll_ev, "EPOLL_CTL_ADD failed");
150         }
151         fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
152
153         /* only if we want to read we want to tell the event handler about errors */
154         if (fde->flags & EVENT_FD_READ) {
155                 fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
156         }
157 }
158
159 /*
160  delete the epoll event for given fd_event
161 */
162 static void epoll_del_event(struct epoll_event_context *epoll_ev, struct fd_event *fde)
163 {
164         struct epoll_event event;
165
166         DLIST_REMOVE(epoll_ev->fd_events, fde);
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                 DEBUG(0,("epoll_del_event failed! probable early close bug (%s)\n", strerror(errno)));
180         }
181         fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
182 }
183
184 /*
185  change the epoll event to the given fd_event
186 */
187 static void epoll_mod_event(struct epoll_event_context *epoll_ev, struct fd_event *fde)
188 {
189         struct epoll_event event;
190         if (epoll_ev->epoll_fd == -1) return;
191
192         fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
193
194         ZERO_STRUCT(event);
195         event.events = epoll_map_flags(fde->flags);
196         event.data.ptr = fde;
197         if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) {
198                 epoll_panic(epoll_ev, "EPOLL_CTL_MOD failed");
199         }
200
201         /* only if we want to read we want to tell the event handler about errors */
202         if (fde->flags & EVENT_FD_READ) {
203                 fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
204         }
205 }
206
207 static void epoll_change_event(struct epoll_event_context *epoll_ev, struct fd_event *fde)
208 {
209         bool got_error = (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR);
210         bool want_read = (fde->flags & EVENT_FD_READ);
211         bool want_write= (fde->flags & EVENT_FD_WRITE);
212
213         if (epoll_ev->epoll_fd == -1) return;
214
215         fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;
216
217         /* there's already an event */
218         if (fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT) {
219                 if (want_read || (want_write && !got_error)) {
220                         epoll_mod_event(epoll_ev, fde);
221                         return;
222                 }
223                 /* 
224                  * if we want to match the select behavior, we need to remove the epoll_event
225                  * when the caller isn't interested in events.
226                  *
227                  * this is because epoll reports EPOLLERR and EPOLLHUP, even without asking for them
228                  */
229                 epoll_del_event(epoll_ev, fde);
230                 return;
231         }
232
233         /* there's no epoll_event attached to the fde */
234         if (want_read || (want_write && !got_error)) {
235                 DLIST_ADD(epoll_ev->fd_events, fde);
236                 epoll_add_event(epoll_ev, fde);
237                 return;
238         }
239 }
240
241 /*
242   event loop handling using epoll
243 */
244 static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval *tvalp)
245 {
246         int ret, i;
247 #define MAXEVENTS 32
248         struct epoll_event events[MAXEVENTS];
249         uint32_t destruction_count = ++epoll_ev->destruction_count;
250         int timeout = -1;
251
252         if (epoll_ev->epoll_fd == -1) return -1;
253
254         if (tvalp) {
255                 /* it's better to trigger timed events a bit later than to early */
256                 timeout = ((tvalp->tv_usec+999) / 1000) + (tvalp->tv_sec*1000);
257         }
258
259         if (epoll_ev->ev->num_signal_handlers && 
260             common_event_check_signal(epoll_ev->ev)) {
261                 return 0;
262         }
263
264         ret = epoll_wait(epoll_ev->epoll_fd, events, MAXEVENTS, timeout);
265
266         if (ret == -1 && errno == EINTR && epoll_ev->ev->num_signal_handlers) {
267                 if (common_event_check_signal(epoll_ev->ev)) {
268                         return 0;
269                 }
270         }
271
272         if (ret == -1 && errno != EINTR) {
273                 epoll_panic(epoll_ev, "epoll_wait() failed");
274                 return -1;
275         }
276
277         if (ret == 0 && tvalp) {
278                 /* we don't care about a possible delay here */
279                 common_event_loop_timer_delay(epoll_ev->ev);
280                 return 0;
281         }
282
283         for (i=0;i<ret;i++) {
284                 struct fd_event *fde = talloc_get_type(events[i].data.ptr, 
285                                                        struct fd_event);
286                 uint16_t flags = 0;
287
288                 if (fde == NULL) {
289                         epoll_panic(epoll_ev, "epoll_wait() gave bad data");
290                         return -1;
291                 }
292                 if (events[i].events & (EPOLLHUP|EPOLLERR)) {
293                         fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR;
294                         /*
295                          * if we only wait for EVENT_FD_WRITE, we should not tell the
296                          * event handler about it, and remove the epoll_event,
297                          * as we only report errors when waiting for read events,
298                          * to match the select() behavior
299                          */
300                         if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR)) {
301                                 epoll_del_event(epoll_ev, fde);
302                                 continue;
303                         }
304                         flags |= EVENT_FD_READ;
305                 }
306                 if (events[i].events & EPOLLIN) flags |= EVENT_FD_READ;
307                 if (events[i].events & EPOLLOUT) flags |= EVENT_FD_WRITE;
308                 if (flags) {
309                         fde->handler(epoll_ev->ev, fde, flags, fde->private_data);
310                         if (destruction_count != epoll_ev->destruction_count) {
311                                 break;
312                         }
313                 }
314         }
315
316         return 0;
317 }
318
319 /*
320   create a epoll_event_context structure.
321 */
322 static int epoll_event_context_init(struct event_context *ev)
323 {
324         int ret;
325         struct epoll_event_context *epoll_ev;
326
327         epoll_ev = talloc_zero(ev, struct epoll_event_context);
328         if (!epoll_ev) return -1;
329         epoll_ev->ev = ev;
330         epoll_ev->epoll_fd = -1;
331
332         ret = epoll_init_ctx(epoll_ev);
333         if (ret != 0) {
334                 talloc_free(epoll_ev);
335                 return ret;
336         }
337
338         ev->additional_data = epoll_ev;
339         return 0;
340 }
341
342 /*
343   destroy an fd_event
344 */
345 static int epoll_event_fd_destructor(struct fd_event *fde)
346 {
347         struct event_context *ev = fde->event_ctx;
348         struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data,
349                                                            struct epoll_event_context);
350
351         epoll_check_reopen(epoll_ev);
352
353         epoll_ev->num_fd_events--;
354         epoll_ev->destruction_count++;
355
356         epoll_del_event(epoll_ev, fde);
357
358         if (fde->flags & EVENT_FD_AUTOCLOSE) {
359                 close(fde->fd);
360                 fde->fd = -1;
361         }
362
363         return 0;
364 }
365
366 /*
367   add a fd based event
368   return NULL on failure (memory allocation error)
369 */
370 static struct fd_event *epoll_event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx,
371                                          int fd, uint16_t flags,
372                                          event_fd_handler_t handler,
373                                          void *private_data)
374 {
375         struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data,
376                                                            struct epoll_event_context);
377         struct fd_event *fde;
378
379         epoll_check_reopen(epoll_ev);
380
381         fde = talloc(mem_ctx?mem_ctx:ev, struct fd_event);
382         if (!fde) return NULL;
383
384         fde->event_ctx          = ev;
385         fde->fd                 = fd;
386         fde->flags              = flags;
387         fde->handler            = handler;
388         fde->private_data       = private_data;
389         fde->additional_flags   = 0;
390         fde->additional_data    = NULL;
391
392         epoll_ev->num_fd_events++;
393         talloc_set_destructor(fde, epoll_event_fd_destructor);
394
395         DLIST_ADD(epoll_ev->fd_events, fde);
396         epoll_add_event(epoll_ev, fde);
397
398         return fde;
399 }
400
401
402 /*
403   return the fd event flags
404 */
405 static uint16_t epoll_event_get_fd_flags(struct fd_event *fde)
406 {
407         return fde->flags;
408 }
409
410 /*
411   set the fd event flags
412 */
413 static void epoll_event_set_fd_flags(struct fd_event *fde, uint16_t flags)
414 {
415         struct event_context *ev;
416         struct epoll_event_context *epoll_ev;
417
418         if (fde->flags == flags) return;
419
420         ev = fde->event_ctx;
421         epoll_ev = talloc_get_type(ev->additional_data, struct epoll_event_context);
422
423         fde->flags = flags;
424
425         epoll_check_reopen(epoll_ev);
426
427         epoll_change_event(epoll_ev, fde);
428 }
429
430 /*
431   do a single event loop using the events defined in ev 
432 */
433 static int epoll_event_loop_once(struct event_context *ev)
434 {
435         struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data,
436                                                            struct epoll_event_context);
437         struct timeval tval;
438
439         tval = common_event_loop_timer_delay(ev);
440         if (timeval_is_zero(&tval)) {
441                 return 0;
442         }
443
444         epoll_check_reopen(epoll_ev);
445
446         return epoll_event_loop(epoll_ev, &tval);
447 }
448
449 /*
450   return on failure or (with 0) if all fd events are removed
451 */
452 static int epoll_event_loop_wait(struct event_context *ev)
453 {
454         struct epoll_event_context *epoll_ev = talloc_get_type(ev->additional_data,
455                                                            struct epoll_event_context);
456         while (epoll_ev->num_fd_events) {
457                 if (epoll_event_loop_once(ev) != 0) {
458                         break;
459                 }
460         }
461
462         return 0;
463 }
464
465 static const struct event_ops epoll_event_ops = {
466         .context_init   = epoll_event_context_init,
467         .add_fd         = epoll_event_add_fd,
468         .get_fd_flags   = epoll_event_get_fd_flags,
469         .set_fd_flags   = epoll_event_set_fd_flags,
470         .add_timed      = common_event_add_timed,
471         .add_signal     = common_event_add_signal,
472         .loop_once      = epoll_event_loop_once,
473         .loop_wait      = epoll_event_loop_wait,
474 };
475
476 bool events_epoll_init(void)
477 {
478         return event_register_backend("epoll", &epoll_event_ops);
479 }
480
481 #if _SAMBA_BUILD_
482 NTSTATUS s4_events_epoll_init(void)
483 {
484         if (!events_epoll_init()) {
485                 return NT_STATUS_INTERNAL_ERROR;
486         }
487         return NT_STATUS_OK;
488 }
489 #endif