create-tarball: Adapt script to changed directory structure.
[Samba/gbeck.git] / source3 / lib / events.c
blobf03138708bacc0bcfe37b3e6bbe776bfee670618
1 /*
2 Unix SMB/CIFS implementation.
3 Timed event library.
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Volker Lendecke 2005
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
23 struct timed_event {
24 struct timed_event *next, *prev;
25 struct event_context *event_ctx;
26 struct timeval when;
27 const char *event_name;
28 void (*handler)(struct event_context *event_ctx,
29 struct timed_event *te,
30 const struct timeval *now,
31 void *private_data);
32 void *private_data;
35 struct fd_event {
36 struct fd_event *prev, *next;
37 struct event_context *event_ctx;
38 int fd;
39 uint16_t flags; /* see EVENT_FD_* flags */
40 void (*handler)(struct event_context *event_ctx,
41 struct fd_event *event,
42 uint16 flags,
43 void *private_data);
44 void *private_data;
47 #define EVENT_FD_WRITEABLE(fde) \
48 event_set_fd_flags(fde, event_get_fd_flags(fde) | EVENT_FD_WRITE)
49 #define EVENT_FD_READABLE(fde) \
50 event_set_fd_flags(fde, event_get_fd_flags(fde) | EVENT_FD_READ)
52 #define EVENT_FD_NOT_WRITEABLE(fde) \
53 event_set_fd_flags(fde, event_get_fd_flags(fde) & ~EVENT_FD_WRITE)
54 #define EVENT_FD_NOT_READABLE(fde) \
55 event_set_fd_flags(fde, event_get_fd_flags(fde) & ~EVENT_FD_READ)
57 struct event_context {
58 struct timed_event *timed_events;
59 struct fd_event *fd_events;
62 static int timed_event_destructor(struct timed_event *te)
64 DEBUG(10, ("Destroying timed event %lx \"%s\"\n", (unsigned long)te,
65 te->event_name));
66 if (te->event_ctx != NULL) {
67 DLIST_REMOVE(te->event_ctx->timed_events, te);
69 return 0;
72 /****************************************************************************
73 Add te by time.
74 ****************************************************************************/
76 static void add_event_by_time(struct timed_event *te)
78 struct event_context *ctx = te->event_ctx;
79 struct timed_event *last_te, *cur_te;
81 /* Keep the list ordered by time. We must preserve this. */
82 last_te = NULL;
83 for (cur_te = ctx->timed_events; cur_te; cur_te = cur_te->next) {
84 /* if the new event comes before the current one break */
85 if (!timeval_is_zero(&cur_te->when) &&
86 timeval_compare(&te->when, &cur_te->when) < 0) {
87 break;
89 last_te = cur_te;
92 DLIST_ADD_AFTER(ctx->timed_events, te, last_te);
95 /****************************************************************************
96 Schedule a function for future calling, cancel with TALLOC_FREE().
97 It's the responsibility of the handler to call TALLOC_FREE() on the event
98 handed to it.
99 ****************************************************************************/
101 struct timed_event *event_add_timed(struct event_context *event_ctx,
102 TALLOC_CTX *mem_ctx,
103 struct timeval when,
104 const char *event_name,
105 void (*handler)(struct event_context *event_ctx,
106 struct timed_event *te,
107 const struct timeval *now,
108 void *private_data),
109 void *private_data)
111 struct timed_event *te;
113 te = TALLOC_P(mem_ctx, struct timed_event);
114 if (te == NULL) {
115 DEBUG(0, ("talloc failed\n"));
116 return NULL;
119 te->event_ctx = event_ctx;
120 te->when = when;
121 te->event_name = event_name;
122 te->handler = handler;
123 te->private_data = private_data;
125 add_event_by_time(te);
127 talloc_set_destructor(te, timed_event_destructor);
129 DEBUG(10, ("Added timed event \"%s\": %lx\n", event_name,
130 (unsigned long)te));
131 return te;
134 static int fd_event_destructor(struct fd_event *fde)
136 if (fde->event_ctx != NULL) {
137 DLIST_REMOVE(fde->event_ctx->fd_events, fde);
139 return 0;
142 struct fd_event *event_add_fd(struct event_context *event_ctx,
143 TALLOC_CTX *mem_ctx,
144 int fd, uint16_t flags,
145 void (*handler)(struct event_context *event_ctx,
146 struct fd_event *event,
147 uint16 flags,
148 void *private_data),
149 void *private_data)
151 struct fd_event *fde;
153 if (!(fde = TALLOC_P(mem_ctx, struct fd_event))) {
154 return NULL;
157 fde->event_ctx = event_ctx;
158 fde->fd = fd;
159 fde->flags = flags;
160 fde->handler = handler;
161 fde->private_data = private_data;
163 DLIST_ADD(event_ctx->fd_events, fde);
165 talloc_set_destructor(fde, fd_event_destructor);
166 return fde;
169 void event_fd_set_writeable(struct fd_event *fde)
171 fde->flags |= EVENT_FD_WRITE;
174 void event_fd_set_not_writeable(struct fd_event *fde)
176 fde->flags &= ~EVENT_FD_WRITE;
179 void event_fd_set_readable(struct fd_event *fde)
181 fde->flags |= EVENT_FD_READ;
184 void event_fd_set_not_readable(struct fd_event *fde)
186 fde->flags &= ~EVENT_FD_READ;
190 * Return if there's something in the queue
193 bool event_add_to_select_args(struct event_context *event_ctx,
194 const struct timeval *now,
195 fd_set *read_fds, fd_set *write_fds,
196 struct timeval *timeout, int *maxfd)
198 struct fd_event *fde;
199 struct timeval diff;
200 bool ret = False;
202 for (fde = event_ctx->fd_events; fde; fde = fde->next) {
203 if (fde->flags & EVENT_FD_READ) {
204 FD_SET(fde->fd, read_fds);
205 ret = True;
207 if (fde->flags & EVENT_FD_WRITE) {
208 FD_SET(fde->fd, write_fds);
209 ret = True;
212 if ((fde->flags & (EVENT_FD_READ|EVENT_FD_WRITE))
213 && (fde->fd > *maxfd)) {
214 *maxfd = fde->fd;
218 if (event_ctx->timed_events == NULL) {
219 return ret;
222 diff = timeval_until(now, &event_ctx->timed_events->when);
223 *timeout = timeval_min(timeout, &diff);
225 return True;
228 bool events_pending(struct event_context *event_ctx)
230 struct fd_event *fde;
232 if (event_ctx->timed_events != NULL) {
233 return True;
235 for (fde = event_ctx->fd_events; fde; fde = fde->next) {
236 if (fde->flags & (EVENT_FD_READ|EVENT_FD_WRITE)) {
237 return True;
240 return False;
243 bool run_events(struct event_context *event_ctx,
244 int selrtn, fd_set *read_fds, fd_set *write_fds)
246 bool fired = False;
247 struct fd_event *fde, *next;
249 /* Run all events that are pending, not just one (as we
250 did previously. */
252 while (event_ctx->timed_events) {
253 struct timeval now;
254 GetTimeOfDay(&now);
256 if (timeval_compare(
257 &now, &event_ctx->timed_events->when) < 0) {
258 /* Nothing to do yet */
259 DEBUG(11, ("run_events: Nothing to do\n"));
260 break;
263 DEBUG(10, ("Running event \"%s\" %lx\n",
264 event_ctx->timed_events->event_name,
265 (unsigned long)event_ctx->timed_events));
267 event_ctx->timed_events->handler(
268 event_ctx,
269 event_ctx->timed_events, &now,
270 event_ctx->timed_events->private_data);
272 fired = True;
275 if (fired) {
277 * We might have changed the socket status during the timed
278 * events, return to run select again.
280 return True;
283 if (selrtn == 0) {
285 * No fd ready
287 return fired;
290 for (fde = event_ctx->fd_events; fde; fde = next) {
291 uint16 flags = 0;
293 next = fde->next;
294 if (FD_ISSET(fde->fd, read_fds)) flags |= EVENT_FD_READ;
295 if (FD_ISSET(fde->fd, write_fds)) flags |= EVENT_FD_WRITE;
297 if (flags & fde->flags) {
298 fde->handler(event_ctx, fde, flags, fde->private_data);
299 fired = True;
303 return fired;
307 struct timeval *get_timed_events_timeout(struct event_context *event_ctx,
308 struct timeval *to_ret)
310 struct timeval now;
312 if (event_ctx->timed_events == NULL) {
313 return NULL;
316 now = timeval_current();
317 *to_ret = timeval_until(&now, &event_ctx->timed_events->when);
319 DEBUG(10, ("timed_events_timeout: %d/%d\n", (int)to_ret->tv_sec,
320 (int)to_ret->tv_usec));
322 return to_ret;
325 int event_loop_once(struct event_context *ev)
327 struct timeval now, to;
328 fd_set r_fds, w_fds;
329 int maxfd = 0;
330 int ret;
332 FD_ZERO(&r_fds);
333 FD_ZERO(&w_fds);
335 to.tv_sec = 9999; /* Max timeout */
336 to.tv_usec = 0;
338 GetTimeOfDay(&now);
340 if (!event_add_to_select_args(ev, &now, &r_fds, &w_fds, &to, &maxfd)) {
341 return -1;
344 if (timeval_is_zero(&to)) {
345 run_events(ev, 0, NULL, NULL);
346 return 0;
349 ret = sys_select(maxfd+1, &r_fds, &w_fds, NULL, &to);
351 if (ret == -1 && errno != EINTR) {
352 return -1;
355 run_events(ev, ret, &r_fds, &w_fds);
356 return 0;
359 static int event_context_destructor(struct event_context *ev)
361 while (ev->fd_events != NULL) {
362 ev->fd_events->event_ctx = NULL;
363 DLIST_REMOVE(ev->fd_events, ev->fd_events);
365 while (ev->timed_events != NULL) {
366 ev->timed_events->event_ctx = NULL;
367 DLIST_REMOVE(ev->timed_events, ev->timed_events);
369 return 0;
372 struct event_context *event_context_init(TALLOC_CTX *mem_ctx)
374 struct event_context *result;
376 result = TALLOC_ZERO_P(mem_ctx, struct event_context);
377 if (result == NULL) {
378 return NULL;
381 talloc_set_destructor(result, event_context_destructor);
382 return result;
385 int set_event_dispatch_time(struct event_context *event_ctx,
386 const char *event_name, struct timeval when)
388 struct timed_event *te;
390 for (te = event_ctx->timed_events; te; te = te->next) {
391 if (strcmp(event_name, te->event_name) == 0) {
392 DLIST_REMOVE(event_ctx->timed_events, te);
393 te->when = when;
394 add_event_by_time(te);
395 return 1;
398 return 0;
401 /* Returns 1 if event was found and cancelled, 0 otherwise. */
403 int cancel_named_event(struct event_context *event_ctx,
404 const char *event_name)
406 struct timed_event *te;
408 for (te = event_ctx->timed_events; te; te = te->next) {
409 if (strcmp(event_name, te->event_name) == 0) {
410 TALLOC_FREE(te);
411 return 1;
414 return 0;
417 void dump_event_list(struct event_context *event_ctx)
419 struct timed_event *te;
420 struct fd_event *fe;
421 struct timeval evt, now;
423 if (!event_ctx) {
424 return;
427 now = timeval_current();
429 DEBUG(10,("dump_event_list:\n"));
431 for (te = event_ctx->timed_events; te; te = te->next) {
433 evt = timeval_until(&now, &te->when);
435 DEBUGADD(10,("Timed Event \"%s\" %lx handled in %d seconds (at %s)\n",
436 te->event_name,
437 (unsigned long)te,
438 (int)evt.tv_sec,
439 http_timestring(te->when.tv_sec)));
442 for (fe = event_ctx->fd_events; fe; fe = fe->next) {
444 DEBUGADD(10,("FD Event %d %lx, flags: 0x%04x\n",
445 fe->fd,
446 (unsigned long)fe,
447 fe->flags));