r4524: converted a few bits of samr.idl to use enum properly
[samba.git] / source4 / lib / events.c
1 /* 
2    Unix SMB/CIFS implementation.
3    main select loop and event handling
4    Copyright (C) Andrew Tridgell 2003
5    
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.
10    
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.
15    
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.
19 */
20
21 /*
22   PLEASE READ THIS BEFORE MODIFYING!
23
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.
28
29   There are 4 types of event handling that are handled in this module:
30
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)
38
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.
43
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.
48
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.
52
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.
56
57   After that you can add/remove events that you are interested in
58   using event_add_*() and event_remove_*().
59
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
63   handler functions.
64
65 */
66
67 #include "includes.h"
68 #include "system/time.h"
69 #include "system/select.h"
70 #include "dlinklist.h"
71 #include "events.h"
72
73 /*
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.
77 */
78 struct event_context *event_context_init(TALLOC_CTX *mem_ctx)
79 {
80         struct event_context *ev;
81
82         ev = talloc_p(mem_ctx, struct event_context);
83         if (!ev) return NULL;
84
85         /* start off with no events */
86         ZERO_STRUCTP(ev);
87
88         ev->events = talloc(ev, 0);
89
90         return ev;
91 }
92
93 /*
94   destroy an events context, also destroying any remaining events
95 */
96 void event_context_destroy(struct event_context *ev)
97 {
98         talloc_free(ev);
99 }
100
101
102 /*
103   recalculate the maxfd
104 */
105 static void calc_maxfd(struct event_context *ev)
106 {
107         struct fd_event *e;
108         ev->maxfd = 0;
109         for (e=ev->fd_events; e; e=e->next) {
110                 if (e->ref_count && 
111                     e->fd > ev->maxfd) {
112                         ev->maxfd = e->fd;
113                 }
114         }
115 }
116
117 /*
118   move the event structures from ev2 into ev, upping the reference
119   count on ev. The event context ev2 is then destroyed.
120
121   this is used by modules that need to call on the events of a lower module
122 */
123 struct event_context *event_context_merge(struct event_context *ev, struct event_context *ev2)
124 {
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 *);
128
129         ev2->fd_events = NULL;
130         ev2->timed_events = NULL;
131         ev2->loop_events = NULL;
132
133         talloc_steal(ev->events, ev2->events);
134
135         event_context_destroy(ev2);
136
137         calc_maxfd(ev);
138
139         return ev;
140 }
141
142
143 /*
144   add a fd based event
145   return NULL on failure (memory allocation error)
146 */
147 struct fd_event *event_add_fd(struct event_context *ev, struct fd_event *e) 
148 {
149         e = talloc_memdup(ev->events, e, sizeof(*e));
150         if (!e) return NULL;
151         DLIST_ADD(ev->fd_events, e);
152         e->ref_count = 1;
153         if (e->fd > ev->maxfd) {
154                 ev->maxfd = e->fd;
155         }
156         return e;
157 }
158
159
160 /* to mark the ev->maxfd invalid
161  * this means we need to recalculate it
162  */
163 #define EVENT_INVALID_MAXFD (-1)
164
165 /*
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)
170 */
171 BOOL event_remove_fd(struct event_context *ev, struct fd_event *e1)
172 {
173         struct fd_event *e;
174         for (e=ev->fd_events; e; e=e->next) {
175                 if (e->ref_count &&
176                     e->fd == e1->fd && 
177                     e->handler == e1->handler) {
178                         e->ref_count--;
179                         return True;
180                 }
181         }
182         return False;
183 }
184
185 /*
186   remove all fd based events that match a specified fd
187 */
188 void event_remove_fd_all(struct event_context *ev, int fd)
189 {
190         struct fd_event *e;
191         for (e=ev->fd_events; e; e=e->next) {
192                 if (e->ref_count && e->fd == fd) {
193                         e->ref_count--;
194                 }
195         }
196 }
197
198 /*
199   remove all fd based events that match a specified handler
200 */
201 void event_remove_fd_all_handler(struct event_context *ev, void *handler)
202 {
203         struct fd_event *e;
204         for (e=ev->fd_events; e; e=e->next) {
205                 if (e->ref_count &&
206                     handler == (void *)e->handler) {
207                         e->ref_count--;
208                 }
209         }
210 }
211
212
213 /*
214   add a timed event
215   return NULL on failure (memory allocation error)
216 */
217 struct timed_event *event_add_timed(struct event_context *ev, struct timed_event *e) 
218 {
219         e = talloc_memdup(ev->events, e, sizeof(*e));
220         if (!e) return NULL;
221         e->ref_count = 1;
222         DLIST_ADD(ev->timed_events, e);
223         return e;
224 }
225
226 /*
227   remove a timed event
228   return False on failure (event not found)
229 */
230 BOOL event_remove_timed(struct event_context *ev, struct timed_event *e1) 
231 {
232         struct timed_event *e;
233         for (e=ev->timed_events; e; e=e->next) {
234                 if (e->ref_count && e == e1) {
235                         e->ref_count--;
236                         return True;
237                 }
238         }
239         return False;
240 }
241
242 /*
243   add a loop event
244   return NULL on failure (memory allocation error)
245 */
246 struct loop_event *event_add_loop(struct event_context *ev, struct loop_event *e)
247 {
248         e = talloc_memdup(ev->events, e, sizeof(*e));
249         if (!e) return NULL;
250         e->ref_count = 1;
251         DLIST_ADD(ev->loop_events, e);
252         return e;
253 }
254
255 /*
256   remove a loop event
257   the event to remove is matched only on the handler function
258   return False on failure (memory allocation error)
259 */
260 BOOL event_remove_loop(struct event_context *ev, struct loop_event *e1) 
261 {
262         struct loop_event *e;
263         for (e=ev->loop_events; e; e=e->next) {
264                 if (e->ref_count &&
265                     e->handler == e1->handler) {
266                         e->ref_count--;
267                         return True;
268                 }
269         }
270         return False;
271 }
272
273
274 /*
275   tell the event loop to exit with the specified code
276 */
277 void event_loop_exit(struct event_context *ev, int code)
278 {
279         ev->exit.exit_now = True;
280         ev->exit.code = code;
281 }
282
283 /*
284   do a single event loop using the events defined in ev this function
285 */
286 int event_loop_once(struct event_context *ev)
287 {
288         fd_set r_fds, w_fds;
289         struct fd_event *fe;
290         struct loop_event *le;
291         struct timed_event *te;
292         int selrtn;
293         struct timeval tval, t;
294
295         t = timeval_current();
296
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);
303                         talloc_free(le);
304                 } else {
305                         le->ref_count++;
306                         le->handler(ev, le, t);
307                         le->ref_count--;
308                 }
309                 le = next;
310         }
311
312         FD_ZERO(&r_fds);
313         FD_ZERO(&w_fds);
314
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;
322                         }
323                         talloc_free(fe);
324                 } else {
325                         if (fe->flags & EVENT_FD_READ) {
326                                 FD_SET(fe->fd, &r_fds);
327                         }
328                         if (fe->flags & EVENT_FD_WRITE) {
329                                 FD_SET(fe->fd, &w_fds);
330                         }
331                 }
332                 fe = next;
333         }
334
335         /* start with a reasonable max timeout */
336         tval.tv_sec = 600;
337         tval.tv_usec = 0;
338                 
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);
343         }
344
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
349          */
350         if (ev->fd_events) {
351                 /* we maybe need to recalculate the maxfd */
352                 if (ev->maxfd == EVENT_INVALID_MAXFD) {
353                         calc_maxfd(ev);
354                 }
355                 
356                 /* TODO:
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() 
361                  */
362                 selrtn = select(ev->maxfd+1, &r_fds, &w_fds, NULL, &tval);
363                 
364                 t = timeval_current();
365                 
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
371                            fatal error. */
372                         DEBUG(0,("EBADF on event_loop_once - exiting\n"));
373                         ev->exit.code = EBADF;
374                         return -1;
375                 }
376                 
377                 if (selrtn > 0) {
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) {
382                                 uint16_t flags = 0;
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) {
386                                         fe->ref_count++;
387                                         fe->handler(ev, fe, t, flags);
388                                         fe->ref_count--;
389                                 }
390                         }
391                 }
392         }
393
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);
399                         talloc_free(te);
400                 } else if (timeval_compare(&te->next_event, &t) >= 0) {
401                         te->ref_count++;
402                         te->handler(ev, te, t);
403                         te->ref_count--;
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);
408                         }
409                 }
410                 te = next;
411         }               
412         
413         return 0;
414 }
415
416 /*
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
419   event_loop_exit()
420
421   also return (with code 0) if all fd events are removed
422 */
423 int event_loop_wait(struct event_context *ev)
424 {
425         ZERO_STRUCT(ev->exit);
426         ev->maxfd = EVENT_INVALID_MAXFD;
427
428         ev->exit.exit_now = False;
429
430         while (ev->fd_events && !ev->exit.exit_now) {
431                 if (event_loop_once(ev) != 0) {
432                         break;
433                 }
434         }
435
436         return ev->exit.code;
437 }