r5373: prepare infrastructure for maing different events
[Samba/gebeck_regimport.git] / source4 / lib / events / events_standard.c
blob97836037593e239a2bb823ee0a525fec7552b565
1 /*
2 Unix SMB/CIFS implementation.
3 main select loop and event handling
4 Copyright (C) Andrew Tridgell 2003
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 PLEASE READ THIS BEFORE MODIFYING!
24 This module is a general abstraction for the main select loop and
25 event handling. Do not ever put any localised hacks in here, instead
26 register one of the possible event types and implement that event
27 somewhere else.
29 There are 2 types of event handling that are handled in this module:
31 1) a file descriptor becoming readable or writeable. This is mostly
32 used for network sockets, but can be used for any type of file
33 descriptor. You may only register one handler for each file
34 descriptor/io combination or you will get unpredictable results
35 (this means that you can have a handler for read events, and a
36 separate handler for write events, but not two handlers that are
37 both handling read events)
39 2) a timed event. You can register an event that happens at a
40 specific time. You can register as many of these as you
41 like. They are single shot - add a new timed event in the event
42 handler to get another event.
44 To setup a set of events you first need to create a event_context
45 structure using the function event_context_init(); This returns a
46 'struct event_context' that you use in all subsequent calls.
48 After that you can add/remove events that you are interested in
49 using event_add_*() and talloc_free()
51 Finally, you call event_loop_wait() to block waiting for one of the
52 events to occor. In normal operation event_loop_wait() will loop
53 forever.
57 #include "includes.h"
58 #include "system/time.h"
59 #include "system/select.h"
60 #include "system/filesys.h"
61 #include "dlinklist.h"
62 #include "lib/events/events.h"
64 /* use epoll if it is available */
65 #if defined(HAVE_EPOLL_CREATE) && defined(HAVE_SYS_EPOLL_H)
66 #define WITH_EPOLL 1
67 #endif
69 #if WITH_EPOLL
70 #include <sys/epoll.h>
71 #endif
73 struct event_context {
74 /* list of filedescriptor events */
75 struct fd_event {
76 struct event_context *event_ctx;
77 struct fd_event *next, *prev;
78 int fd;
79 uint16_t flags; /* see EVENT_FD_* flags */
80 event_fd_handler_t handler;
81 void *private;
82 } *fd_events;
84 /* list of timed events */
85 struct timed_event {
86 struct event_context *event_ctx;
87 struct timed_event *next, *prev;
88 struct timeval next_event;
89 event_timed_handler_t handler;
90 void *private;
91 } *timed_events;
93 /* the maximum file descriptor number in fd_events */
94 int maxfd;
96 /* information for exiting from the event loop */
97 int exit_code;
99 /* this is changed by the destructors for the fd event
100 type. It is used to detect event destruction by event
101 handlers, which means the code that is calling the event
102 handler needs to assume that the linked list is no longer
103 valid
105 uint32_t destruction_count;
107 #if WITH_EPOLL
108 /* when using epoll this is the handle from epoll_create */
109 int epoll_fd;
110 #endif
115 destroy an event context
117 static int event_context_destructor(void *ptr)
119 #if WITH_EPOLL
120 struct event_context *ev = talloc_get_type(ptr, struct event_context);
121 if (ev->epoll_fd != -1) {
122 close(ev->epoll_fd);
123 ev->epoll_fd = -1;
125 #endif
126 return 0;
130 create a event_context structure. This must be the first events
131 call, and all subsequent calls pass this event_context as the first
132 element. Event handlers also receive this as their first argument.
134 struct event_context *event_context_init(TALLOC_CTX *mem_ctx)
136 struct event_context *ev;
138 ev = talloc_zero(mem_ctx, struct event_context);
139 if (!ev) return NULL;
141 #if WITH_EPOLL
142 ev->epoll_fd = epoll_create(64);
143 #endif
145 talloc_set_destructor(ev, event_context_destructor);
147 return ev;
152 recalculate the maxfd
154 static void calc_maxfd(struct event_context *ev)
156 struct fd_event *e;
157 ev->maxfd = 0;
158 for (e=ev->fd_events; e; e=e->next) {
159 if (e->fd > ev->maxfd) {
160 ev->maxfd = e->fd;
166 /* to mark the ev->maxfd invalid
167 * this means we need to recalculate it
169 #define EVENT_INVALID_MAXFD (-1)
172 #if WITH_EPOLL
174 called when a epoll call fails, and we should fallback
175 to using select
177 static void epoll_fallback_to_select(struct event_context *ev, const char *reason)
179 DEBUG(0,("%s (%s) - falling back to select()\n", reason, strerror(errno)));
180 close(ev->epoll_fd);
181 ev->epoll_fd = -1;
183 #endif
186 #if WITH_EPOLL
188 map from EVENT_FD_* to EPOLLIN/EPOLLOUT
190 static uint32_t epoll_map_flags(uint16_t flags)
192 uint32_t ret = 0;
193 if (flags & EVENT_FD_READ) ret |= EPOLLIN;
194 if (flags & EVENT_FD_WRITE) ret |= EPOLLOUT;
195 return ret;
197 #endif
200 destroy an fd_event
202 static int event_fd_destructor(void *ptr)
204 struct fd_event *fde = talloc_get_type(ptr, struct fd_event);
205 struct event_context *ev = fde->event_ctx;
207 if (ev->maxfd == fde->fd) {
208 ev->maxfd = EVENT_INVALID_MAXFD;
210 DLIST_REMOVE(ev->fd_events, fde);
211 ev->destruction_count++;
212 #if WITH_EPOLL
213 if (ev->epoll_fd != -1) {
214 struct epoll_event event;
215 ZERO_STRUCT(event);
216 event.events = epoll_map_flags(fde->flags);
217 event.data.ptr = fde;
218 epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event);
220 #endif
221 return 0;
225 add a fd based event
226 return NULL on failure (memory allocation error)
228 struct fd_event *event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx,
229 int fd, uint16_t flags, event_fd_handler_t handler,
230 void *private)
232 struct fd_event *e = talloc(ev, struct fd_event);
233 if (!e) return NULL;
235 e->event_ctx = ev;
236 e->fd = fd;
237 e->flags = flags;
238 e->handler = handler;
239 e->private = private;
241 DLIST_ADD(ev->fd_events, e);
243 if (e->fd > ev->maxfd) {
244 ev->maxfd = e->fd;
247 talloc_set_destructor(e, event_fd_destructor);
248 if (mem_ctx) {
249 talloc_steal(mem_ctx, e);
252 #if WITH_EPOLL
253 if (ev->epoll_fd != -1) {
254 struct epoll_event event;
255 ZERO_STRUCT(event);
256 event.events = epoll_map_flags(flags);
257 event.data.ptr = e;
258 if (epoll_ctl(ev->epoll_fd, EPOLL_CTL_ADD, e->fd, &event) != 0) {
259 epoll_fallback_to_select(ev, "EPOLL_CTL_ADD failed");
262 #endif
264 return e;
269 return the fd event flags
271 uint16_t event_fd_flags(struct fd_event *fde)
273 return fde?fde->flags:0;
277 set the fd event flags
279 void event_fd_setflags(struct fd_event *fde, uint16_t flags)
281 #if WITH_EPOLL
282 struct event_context *ev;
283 if (fde == NULL ||
284 fde->flags == flags) {
285 return;
287 ev = fde->event_ctx;
288 if (ev->epoll_fd != -1) {
289 struct epoll_event event;
290 ZERO_STRUCT(event);
291 event.events = epoll_map_flags(flags);
292 event.data.ptr = fde;
293 if (epoll_ctl(ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) {
294 epoll_fallback_to_select(ev, "EPOLL_CTL_MOD failed");
297 #endif
298 if (fde) {
299 fde->flags = flags;
304 destroy a timed event
306 static int event_timed_destructor(void *ptr)
308 struct timed_event *te = talloc_get_type(ptr, struct timed_event);
309 DLIST_REMOVE(te->event_ctx->timed_events, te);
310 return 0;
314 add a timed event
315 return NULL on failure (memory allocation error)
317 struct timed_event *event_add_timed(struct event_context *ev, TALLOC_CTX *mem_ctx,
318 struct timeval next_event,
319 event_timed_handler_t handler,
320 void *private)
322 struct timed_event *te, *e;
324 e = talloc(mem_ctx?mem_ctx:ev, struct timed_event);
325 if (e == NULL) return NULL;
327 e->event_ctx = ev;
328 e->next_event = next_event;
329 e->handler = handler;
330 e->private = private;
332 /* keep the list ordered */
333 if (ev->timed_events == NULL ||
334 timeval_compare(&e->next_event, &ev->timed_events->next_event) > 0) {
335 DLIST_ADD(ev->timed_events, e);
336 } else {
337 for (te=ev->timed_events;te && te->next;te=te->next) {
338 if (!timeval_is_zero(&te->next->next_event) &&
339 timeval_compare(&te->next->next_event, &e->next_event) < 0) {
340 break;
343 DLIST_ADD_AFTER(ev->timed_events, e, te);
346 talloc_set_destructor(e, event_timed_destructor);
348 return e;
352 a timer has gone off - call it
354 static void event_loop_timer(struct event_context *ev)
356 struct timeval t = timeval_current();
357 struct timed_event *te = ev->timed_events;
359 te->next_event = timeval_zero();
361 te->handler(ev, te, t, te->private);
363 /* note the care taken to prevent referencing a event
364 that could have been freed by the handler */
365 if (ev->timed_events && timeval_is_zero(&ev->timed_events->next_event)) {
366 talloc_free(ev->timed_events);
370 #if WITH_EPOLL
372 event loop handling using epoll
374 static int event_loop_epoll(struct event_context *ev, struct timeval *tvalp)
376 int ret, i;
377 const int maxevents = 8;
378 struct epoll_event events[maxevents];
379 uint32_t destruction_count = ev->destruction_count;
380 int timeout = -1;
382 if (tvalp) {
383 timeout = (tvalp->tv_usec / 1000) + (tvalp->tv_sec*1000);
386 ret = epoll_wait(ev->epoll_fd, events, maxevents, timeout);
388 if (ret == -1 && errno != EINTR) {
389 epoll_fallback_to_select(ev, "epoll_wait() failed");
390 return -1;
393 if (ret == 0 && tvalp) {
394 event_loop_timer(ev);
395 return 0;
398 for (i=0;i<ret;i++) {
399 struct fd_event *fde = talloc_get_type(events[i].data.ptr,
400 struct fd_event);
401 uint16_t flags = 0;
403 if (fde == NULL) {
404 epoll_fallback_to_select(ev, "epoll_wait() gave bad data");
405 return -1;
407 if (events[i].events & (EPOLLIN|EPOLLHUP|EPOLLERR))
408 flags |= EVENT_FD_READ;
409 if (events[i].events & EPOLLOUT) flags |= EVENT_FD_WRITE;
410 if (flags) {
411 fde->handler(ev, fde, flags, fde->private);
412 if (destruction_count != ev->destruction_count) {
413 break;
418 return 0;
420 #endif
423 event loop handling using select()
425 static int event_loop_select(struct event_context *ev, struct timeval *tvalp)
427 fd_set r_fds, w_fds;
428 int selrtn;
429 uint32_t destruction_count = ev->destruction_count;
430 struct fd_event *fe;
432 /* we maybe need to recalculate the maxfd */
433 if (ev->maxfd == EVENT_INVALID_MAXFD) {
434 calc_maxfd(ev);
437 FD_ZERO(&r_fds);
438 FD_ZERO(&w_fds);
440 /* setup any fd events */
441 for (fe=ev->fd_events; fe; ) {
442 struct fd_event *next = fe->next;
443 if (fe->flags & EVENT_FD_READ) {
444 FD_SET(fe->fd, &r_fds);
446 if (fe->flags & EVENT_FD_WRITE) {
447 FD_SET(fe->fd, &w_fds);
449 fe = next;
452 selrtn = select(ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
454 if (selrtn == -1 && errno == EBADF) {
455 /* the socket is dead! this should never
456 happen as the socket should have first been
457 made readable and that should have removed
458 the event, so this must be a bug. This is a
459 fatal error. */
460 DEBUG(0,("ERROR: EBADF on event_loop_once\n"));
461 ev->exit_code = EBADF;
462 return -1;
465 if (selrtn == 0 && tvalp) {
466 event_loop_timer(ev);
467 return 0;
470 if (selrtn > 0) {
471 /* at least one file descriptor is ready - check
472 which ones and call the handler, being careful to allow
473 the handler to remove itself when called */
474 for (fe=ev->fd_events; fe; fe=fe->next) {
475 uint16_t flags = 0;
476 if (FD_ISSET(fe->fd, &r_fds)) flags |= EVENT_FD_READ;
477 if (FD_ISSET(fe->fd, &w_fds)) flags |= EVENT_FD_WRITE;
478 if (flags) {
479 fe->handler(ev, fe, flags, fe->private);
480 if (destruction_count != ev->destruction_count) {
481 break;
487 return 0;
491 do a single event loop using the events defined in ev
493 int event_loop_once(struct event_context *ev)
495 struct timeval tval, *tvalp;
497 tvalp = NULL;
499 /* work out the right timeout for all timed events */
500 if (ev->timed_events) {
501 struct timeval t = timeval_current();
502 tval = timeval_diff(&ev->timed_events->next_event, &t);
503 tvalp = &tval;
504 if (timeval_is_zero(tvalp)) {
505 event_loop_timer(ev);
506 return 0;
510 #if WITH_EPOLL
511 if (ev->epoll_fd != -1) {
512 if (event_loop_epoll(ev, tvalp) == 0) {
513 return 0;
516 #endif
518 return event_loop_select(ev, tvalp);
522 go into an event loop using the events defined in ev this function
523 will return with the specified code if one of the handlers calls
524 event_loop_exit()
526 also return (with code 0) if all fd events are removed
528 int event_loop_wait(struct event_context *ev)
530 ev->exit_code = 0;
531 ev->maxfd = EVENT_INVALID_MAXFD;
533 while (ev->fd_events && ev->exit_code == 0) {
534 if (event_loop_once(ev) != 0) {
535 break;
539 return ev->exit_code;