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
70 create a event_context structure. This must be the first events
71 call, and all subsequent calls pass this event_context as the first
72 element. Event handlers also receive this as their first argument.
74 struct event_context *event_context_init(void)
76 struct event_context *ev;
78 ev = malloc(sizeof(*ev));
81 /* start off with no events */
91 return NULL on failure (memory allocation error)
93 struct fd_event *event_add_fd(struct event_context *ev, struct fd_event *e)
95 e = memdup(e, sizeof(*e));
97 DLIST_ADD(ev->fd_events, e);
99 if (e->fd > ev->maxfd) {
107 recalculate the maxfd
109 static void calc_maxfd(struct event_context *ev)
113 for (e=ev->fd_events; e; e=e->next) {
121 /* to mark the ev->maxfd invalid
122 * this means we need to recalculate it
124 #define EVENT_INVALID_MAXFD (-1)
127 remove a fd based event
128 the event to remove is matched by looking at the handler
129 function and the file descriptor
130 return False on failure (event not found)
132 BOOL event_remove_fd(struct event_context *ev, struct fd_event *e1)
135 for (e=ev->fd_events; e; e=e->next) {
138 e->handler == e1->handler) {
147 remove all fd based events that match a specified fd
149 void event_remove_fd_all(struct event_context *ev, int fd)
152 for (e=ev->fd_events; e; e=e->next) {
153 if (e->ref_count && e->fd == fd) {
160 remove all fd based events that match a specified handler
162 void event_remove_fd_all_handler(struct event_context *ev, void *handler)
165 for (e=ev->fd_events; e; e=e->next) {
167 handler == (void *)e->handler) {
176 return NULL on failure (memory allocation error)
178 struct timed_event *event_add_timed(struct event_context *ev, struct timed_event *e)
180 e = memdup(e, sizeof(*e));
183 DLIST_ADD(ev->timed_events, e);
189 the event to remove is matched only on the handler function
190 return False on failure (event not found)
192 BOOL event_remove_timed(struct event_context *ev, struct timed_event *e1)
194 struct timed_event *e;
195 for (e=ev->timed_events; e; e=e->next) {
197 e->handler == e1->handler) {
207 return NULL on failure (memory allocation error)
209 struct loop_event *event_add_loop(struct event_context *ev, struct loop_event *e)
211 e = memdup(e, sizeof(*e));
214 DLIST_ADD(ev->loop_events, e);
220 the event to remove is matched only on the handler function
221 return False on failure (memory allocation error)
223 BOOL event_remove_loop(struct event_context *ev, struct loop_event *e1)
225 struct loop_event *e;
226 for (e=ev->loop_events; e; e=e->next) {
228 e->handler == e1->handler) {
238 tell the event loop to exit with the specified code
240 void event_loop_exit(struct event_context *ev, int code)
242 ev->exit.exit_now = True;
243 ev->exit.code = code;
247 go into an event loop using the events defined in ev this function
248 will return with the specified code if one of the handlers calls
251 also return (with code 0) if all fd events are removed
253 int event_loop_wait(struct event_context *ev)
257 ZERO_STRUCT(ev->exit);
258 ev->maxfd = EVENT_INVALID_MAXFD;
262 while (ev->fd_events && !ev->exit.exit_now) {
265 struct loop_event *le;
266 struct timed_event *te;
270 /* the loop events are called on each loop. Be careful to allow the
271 event to remove itself */
272 for (le=ev->loop_events;le;) {
273 struct loop_event *next = le->next;
274 if (le->ref_count == 0) {
275 DLIST_REMOVE(ev->loop_events, le);
279 le->handler(ev, le, t);
289 /* setup any fd events */
290 for (fe=ev->fd_events; fe; ) {
291 struct fd_event *next = fe->next;
292 if (fe->ref_count == 0) {
293 DLIST_REMOVE(ev->fd_events, fe);
294 if (ev->maxfd == fe->fd) {
295 ev->maxfd = EVENT_INVALID_MAXFD;
299 if (fe->flags & EVENT_FD_READ) {
300 FD_SET(fe->fd, &r_fds);
302 if (fe->flags & EVENT_FD_WRITE) {
303 FD_SET(fe->fd, &w_fds);
309 /* start with a reasonable max timeout */
312 /* work out the right timeout for all timed events */
313 for (te=ev->timed_events;te;te=te->next) {
314 int timeout = te->next_event - t;
319 timeout < tval.tv_sec) {
320 tval.tv_sec = timeout;
324 /* only do a select() if there're fd_events
325 * otherwise we would block for a the time in tval,
326 * and if there're no fd_events present anymore we want to
327 * leave the event loop directly
330 /* we maybe need to recalculate the maxfd */
331 if (ev->maxfd == EVENT_INVALID_MAXFD) {
336 * we don't use sys_select() as it isn't thread
337 * safe. We need to replace the magic pipe handling in
338 * sys_select() with something in the events
339 * structure - for now just use select()
341 selrtn = select(ev->maxfd+1, &r_fds, &w_fds, NULL, &tval);
345 if (selrtn == -1 && errno == EBADF) {
346 /* the socket is dead! this should never
347 happen as the socket should have first been
348 made readable and that should have removed
349 the event, so this must be a bug. This is a
351 DEBUG(0,("EBADF on event_loop_wait - exiting\n"));
356 /* at least one file descriptor is ready - check
357 which ones and call the handler, being careful to allow
358 the handler to remove itself when called */
359 for (fe=ev->fd_events; fe; fe=fe->next) {
361 if (FD_ISSET(fe->fd, &r_fds)) flags |= EVENT_FD_READ;
362 if (FD_ISSET(fe->fd, &w_fds)) flags |= EVENT_FD_WRITE;
363 if (fe->ref_count && flags) {
365 fe->handler(ev, fe, t, flags);
372 /* call any timed events that are now due */
373 for (te=ev->timed_events;te;) {
374 struct timed_event *next = te->next;
375 if (te->ref_count == 0) {
376 DLIST_REMOVE(ev->timed_events, te);
378 } else if (te->next_event <= t) {
380 te->handler(ev, te, t);
382 if (te->next_event <= t) {
383 /* the handler didn't set a time for the
384 next event - remove the event */
385 event_remove_timed(ev, te);
393 return ev->exit.code;