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
29 There are 4 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. When they are called the handler can choose to set the time
42 for the next event. If next_event is not set then the event is removed.
44 3) an event that happens every time through the select loop. These
45 sorts of events should be very fast, as they will occur a
46 lot. Mostly used for things like destroying a talloc context or
47 checking a signal flag.
49 4) an event triggered by a signal. These can be one shot or
50 repeated. You can have more than one handler registered for a
51 single signal if you want to.
53 To setup a set of events you first need to create a event_context
54 structure using the function event_context_init(); This returns a
55 'struct event_context' that you use in all subsequent calls.
57 After that you can add/remove events that you are interested in
58 using event_add_*() and event_remove_*().
60 Finally, you call event_loop_wait() to block waiting for one of the
61 events to occor. In normal operation event_loop_wait() will loop
62 forever, unless you call event_loop_exit() from inside one of your
68 #include "system/time.h"
69 #include "system/select.h"
70 #include "dlinklist.h"
74 create a event_context structure. This must be the first events
75 call, and all subsequent calls pass this event_context as the first
76 element. Event handlers also receive this as their first argument.
78 struct event_context *event_context_init(TALLOC_CTX *mem_ctx)
80 struct event_context *ev;
82 ev = talloc_p(mem_ctx, struct event_context);
85 /* start off with no events */
88 ev->events = talloc(ev, 0);
94 destroy an events context, also destroying any remaining events
96 void event_context_destroy(struct event_context *ev)
103 recalculate the maxfd
105 static void calc_maxfd(struct event_context *ev)
109 for (e=ev->fd_events; e; e=e->next) {
118 move the event structures from ev2 into ev, upping the reference
119 count on ev. The event context ev2 is then destroyed.
121 this is used by modules that need to call on the events of a lower module
123 struct event_context *event_context_merge(struct event_context *ev, struct event_context *ev2)
125 DLIST_CONCATENATE(ev->fd_events, ev2->fd_events, struct fd_event *);
126 DLIST_CONCATENATE(ev->timed_events, ev2->timed_events, struct timed_event *);
127 DLIST_CONCATENATE(ev->loop_events, ev2->loop_events, struct loop_event *);
129 ev2->fd_events = NULL;
130 ev2->timed_events = NULL;
131 ev2->loop_events = NULL;
133 talloc_steal(ev->events, ev2->events);
135 event_context_destroy(ev2);
145 return NULL on failure (memory allocation error)
147 struct fd_event *event_add_fd(struct event_context *ev, struct fd_event *e)
149 e = talloc_memdup(ev->events, e, sizeof(*e));
151 DLIST_ADD(ev->fd_events, e);
153 if (e->fd > ev->maxfd) {
160 /* to mark the ev->maxfd invalid
161 * this means we need to recalculate it
163 #define EVENT_INVALID_MAXFD (-1)
166 remove a fd based event
167 the event to remove is matched by looking at the handler
168 function and the file descriptor
169 return False on failure (event not found)
171 BOOL event_remove_fd(struct event_context *ev, struct fd_event *e1)
174 for (e=ev->fd_events; e; e=e->next) {
177 e->handler == e1->handler) {
186 remove all fd based events that match a specified fd
188 void event_remove_fd_all(struct event_context *ev, int fd)
191 for (e=ev->fd_events; e; e=e->next) {
192 if (e->ref_count && e->fd == fd) {
199 remove all fd based events that match a specified handler
201 void event_remove_fd_all_handler(struct event_context *ev, void *handler)
204 for (e=ev->fd_events; e; e=e->next) {
206 handler == (void *)e->handler) {
215 return NULL on failure (memory allocation error)
217 struct timed_event *event_add_timed(struct event_context *ev, struct timed_event *e)
219 e = talloc_memdup(ev->events, e, sizeof(*e));
222 DLIST_ADD(ev->timed_events, e);
228 return False on failure (event not found)
230 BOOL event_remove_timed(struct event_context *ev, struct timed_event *e1)
232 struct timed_event *e;
233 for (e=ev->timed_events; e; e=e->next) {
234 if (e->ref_count && e == e1) {
244 return NULL on failure (memory allocation error)
246 struct loop_event *event_add_loop(struct event_context *ev, struct loop_event *e)
248 e = talloc_memdup(ev->events, e, sizeof(*e));
251 DLIST_ADD(ev->loop_events, e);
257 the event to remove is matched only on the handler function
258 return False on failure (memory allocation error)
260 BOOL event_remove_loop(struct event_context *ev, struct loop_event *e1)
262 struct loop_event *e;
263 for (e=ev->loop_events; e; e=e->next) {
265 e->handler == e1->handler) {
275 tell the event loop to exit with the specified code
277 void event_loop_exit(struct event_context *ev, int code)
279 ev->exit.exit_now = True;
280 ev->exit.code = code;
284 do a single event loop using the events defined in ev this function
286 int event_loop_once(struct event_context *ev)
290 struct loop_event *le;
291 struct timed_event *te;
293 struct timeval tval, t;
295 t = timeval_current();
297 /* the loop events are called on each loop. Be careful to allow the
298 event to remove itself */
299 for (le=ev->loop_events;le;) {
300 struct loop_event *next = le->next;
301 if (le->ref_count == 0) {
302 DLIST_REMOVE(ev->loop_events, le);
306 le->handler(ev, le, t);
315 /* setup any fd events */
316 for (fe=ev->fd_events; fe; ) {
317 struct fd_event *next = fe->next;
318 if (fe->ref_count == 0) {
319 DLIST_REMOVE(ev->fd_events, fe);
320 if (ev->maxfd == fe->fd) {
321 ev->maxfd = EVENT_INVALID_MAXFD;
325 if (fe->flags & EVENT_FD_READ) {
326 FD_SET(fe->fd, &r_fds);
328 if (fe->flags & EVENT_FD_WRITE) {
329 FD_SET(fe->fd, &w_fds);
335 /* start with a reasonable max timeout */
339 /* work out the right timeout for all timed events */
340 for (te=ev->timed_events;te;te=te->next) {
341 struct timeval tv = timeval_diff(&te->next_event, &t);
342 tval = timeval_min(&tv, &tval);
345 /* only do a select() if there're fd_events
346 * otherwise we would block for a the time in tval,
347 * and if there're no fd_events present anymore we want to
348 * leave the event loop directly
351 /* we maybe need to recalculate the maxfd */
352 if (ev->maxfd == EVENT_INVALID_MAXFD) {
357 * we don't use sys_select() as it isn't thread
358 * safe. We need to replace the magic pipe handling in
359 * sys_select() with something in the events
360 * structure - for now just use select()
362 selrtn = select(ev->maxfd+1, &r_fds, &w_fds, NULL, &tval);
364 t = timeval_current();
366 if (selrtn == -1 && errno == EBADF) {
367 /* the socket is dead! this should never
368 happen as the socket should have first been
369 made readable and that should have removed
370 the event, so this must be a bug. This is a
372 DEBUG(0,("EBADF on event_loop_once - exiting\n"));
373 ev->exit.code = EBADF;
378 /* at least one file descriptor is ready - check
379 which ones and call the handler, being careful to allow
380 the handler to remove itself when called */
381 for (fe=ev->fd_events; fe; fe=fe->next) {
383 if (FD_ISSET(fe->fd, &r_fds)) flags |= EVENT_FD_READ;
384 if (FD_ISSET(fe->fd, &w_fds)) flags |= EVENT_FD_WRITE;
385 if (fe->ref_count && flags) {
387 fe->handler(ev, fe, t, flags);
394 /* call any timed events that are now due */
395 for (te=ev->timed_events;te;) {
396 struct timed_event *next = te->next;
397 if (te->ref_count == 0) {
398 DLIST_REMOVE(ev->timed_events, te);
400 } else if (timeval_compare(&te->next_event, &t) >= 0) {
402 te->handler(ev, te, t);
404 if (timeval_compare(&te->next_event, &t) >= 0) {
405 /* the handler didn't set a time for the
406 next event - remove the event */
407 event_remove_timed(ev, te);
417 go into an event loop using the events defined in ev this function
418 will return with the specified code if one of the handlers calls
421 also return (with code 0) if all fd events are removed
423 int event_loop_wait(struct event_context *ev)
425 ZERO_STRUCT(ev->exit);
426 ev->maxfd = EVENT_INVALID_MAXFD;
428 ev->exit.exit_now = False;
430 while (ev->fd_events && !ev->exit.exit_now) {
431 if (event_loop_once(ev) != 0) {
436 return ev->exit.code;