]> git.samba.org - metze/samba/wip.git/blob - source3/lib/events.c
s3:events: remove unused stuff
[metze/samba/wip.git] / source3 / lib / events.c
1 /*
2    Unix SMB/CIFS implementation.
3    Timed event library.
4    Copyright (C) Andrew Tridgell 1992-1998
5    Copyright (C) Volker Lendecke 2005
6
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.
11
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.
16
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/>.
19 */
20
21 #include "includes.h"
22
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;
33 };
34
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;
45 };
46
47 struct event_context {
48         struct timed_event *timed_events;
49         struct fd_event *fd_events;
50 };
51
52 static int timed_event_destructor(struct timed_event *te)
53 {
54         DEBUG(10, ("Destroying timed event %lx \"%s\"\n", (unsigned long)te,
55                 te->event_name));
56         if (te->event_ctx != NULL) {
57                 DLIST_REMOVE(te->event_ctx->timed_events, te);
58         }
59         return 0;
60 }
61
62 /****************************************************************************
63  Add te by time.
64 ****************************************************************************/
65
66 static void add_event_by_time(struct timed_event *te)
67 {
68         struct event_context *ctx = te->event_ctx;
69         struct timed_event *last_te, *cur_te;
70
71         /* Keep the list ordered by time. We must preserve this. */
72         last_te = NULL;
73         for (cur_te = ctx->timed_events; cur_te; cur_te = cur_te->next) {
74                 /* if the new event comes before the current one break */
75                 if (!timeval_is_zero(&cur_te->when) &&
76                                 timeval_compare(&te->when, &cur_te->when) < 0) {
77                         break;
78                 }
79                 last_te = cur_te;
80         }
81
82         DLIST_ADD_AFTER(ctx->timed_events, te, last_te);
83 }
84
85 /****************************************************************************
86  Schedule a function for future calling, cancel with TALLOC_FREE().
87  It's the responsibility of the handler to call TALLOC_FREE() on the event
88  handed to it.
89 ****************************************************************************/
90
91 struct timed_event *event_add_timed(struct event_context *event_ctx,
92                                 TALLOC_CTX *mem_ctx,
93                                 struct timeval when,
94                                 const char *event_name,
95                                 void (*handler)(struct event_context *event_ctx,
96                                                 struct timed_event *te,
97                                                 const struct timeval *now,
98                                                 void *private_data),
99                                 void *private_data)
100 {
101         struct timed_event *te;
102
103         te = TALLOC_P(mem_ctx, struct timed_event);
104         if (te == NULL) {
105                 DEBUG(0, ("talloc failed\n"));
106                 return NULL;
107         }
108
109         te->event_ctx = event_ctx;
110         te->when = when;
111         te->event_name = event_name;
112         te->handler = handler;
113         te->private_data = private_data;
114
115         add_event_by_time(te);
116
117         talloc_set_destructor(te, timed_event_destructor);
118
119         DEBUG(10, ("Added timed event \"%s\": %lx\n", event_name,
120                         (unsigned long)te));
121         return te;
122 }
123
124 static int fd_event_destructor(struct fd_event *fde)
125 {
126         if (fde->event_ctx != NULL) {
127                 DLIST_REMOVE(fde->event_ctx->fd_events, fde);
128         }
129         return 0;
130 }
131
132 struct fd_event *event_add_fd(struct event_context *event_ctx,
133                               TALLOC_CTX *mem_ctx,
134                               int fd, uint16_t flags,
135                               void (*handler)(struct event_context *event_ctx,
136                                               struct fd_event *event,
137                                               uint16 flags,
138                                               void *private_data),
139                               void *private_data)
140 {
141         struct fd_event *fde;
142
143         if (!(fde = TALLOC_P(mem_ctx, struct fd_event))) {
144                 return NULL;
145         }
146
147         fde->event_ctx = event_ctx;
148         fde->fd = fd;
149         fde->flags = flags;
150         fde->handler = handler;
151         fde->private_data = private_data;
152
153         DLIST_ADD(event_ctx->fd_events, fde);
154
155         talloc_set_destructor(fde, fd_event_destructor);
156         return fde;
157 }
158
159 void event_fd_set_writeable(struct fd_event *fde)
160 {
161         fde->flags |= EVENT_FD_WRITE;
162 }
163
164 void event_fd_set_not_writeable(struct fd_event *fde)
165 {
166         fde->flags &= ~EVENT_FD_WRITE;
167 }
168
169 void event_fd_set_readable(struct fd_event *fde)
170 {
171         fde->flags |= EVENT_FD_READ;
172 }
173
174 void event_fd_set_not_readable(struct fd_event *fde)
175 {
176         fde->flags &= ~EVENT_FD_READ;
177 }
178
179 /*
180  * Return if there's something in the queue
181  */
182
183 bool event_add_to_select_args(struct event_context *event_ctx,
184                               const struct timeval *now,
185                               fd_set *read_fds, fd_set *write_fds,
186                               struct timeval *timeout, int *maxfd)
187 {
188         struct fd_event *fde;
189         struct timeval diff;
190         bool ret = False;
191
192         for (fde = event_ctx->fd_events; fde; fde = fde->next) {
193                 if (fde->flags & EVENT_FD_READ) {
194                         FD_SET(fde->fd, read_fds);
195                         ret = True;
196                 }
197                 if (fde->flags & EVENT_FD_WRITE) {
198                         FD_SET(fde->fd, write_fds);
199                         ret = True;
200                 }
201
202                 if ((fde->flags & (EVENT_FD_READ|EVENT_FD_WRITE))
203                     && (fde->fd > *maxfd)) {
204                         *maxfd = fde->fd;
205                 }
206         }
207
208         if (event_ctx->timed_events == NULL) {
209                 return ret;
210         }
211
212         diff = timeval_until(now, &event_ctx->timed_events->when);
213         *timeout = timeval_min(timeout, &diff);
214
215         return True;
216 }
217
218 bool run_events(struct event_context *event_ctx,
219                 int selrtn, fd_set *read_fds, fd_set *write_fds)
220 {
221         bool fired = False;
222         struct fd_event *fde, *next;
223
224         /* Run all events that are pending, not just one (as we
225            did previously. */
226
227         while (event_ctx->timed_events) {
228                 struct timeval now;
229                 GetTimeOfDay(&now);
230
231                 if (timeval_compare(
232                             &now, &event_ctx->timed_events->when) < 0) {
233                         /* Nothing to do yet */
234                         DEBUG(11, ("run_events: Nothing to do\n"));
235                         break;
236                 }
237
238                 DEBUG(10, ("Running event \"%s\" %lx\n",
239                            event_ctx->timed_events->event_name,
240                            (unsigned long)event_ctx->timed_events));
241
242                 event_ctx->timed_events->handler(
243                         event_ctx,
244                         event_ctx->timed_events, &now,
245                         event_ctx->timed_events->private_data);
246
247                 fired = True;
248         }
249
250         if (fired) {
251                 /*
252                  * We might have changed the socket status during the timed
253                  * events, return to run select again.
254                  */
255                 return True;
256         }
257
258         if (selrtn == 0) {
259                 /*
260                  * No fd ready
261                  */
262                 return fired;
263         }
264
265         for (fde = event_ctx->fd_events; fde; fde = next) {
266                 uint16 flags = 0;
267
268                 next = fde->next;
269                 if (FD_ISSET(fde->fd, read_fds)) flags |= EVENT_FD_READ;
270                 if (FD_ISSET(fde->fd, write_fds)) flags |= EVENT_FD_WRITE;
271
272                 if (flags & fde->flags) {
273                         fde->handler(event_ctx, fde, flags, fde->private_data);
274                         fired = True;
275                 }
276         }
277
278         return fired;
279 }
280
281
282 struct timeval *get_timed_events_timeout(struct event_context *event_ctx,
283                                          struct timeval *to_ret)
284 {
285         struct timeval now;
286
287         if (event_ctx->timed_events == NULL) {
288                 return NULL;
289         }
290
291         now = timeval_current();
292         *to_ret = timeval_until(&now, &event_ctx->timed_events->when);
293
294         DEBUG(10, ("timed_events_timeout: %d/%d\n", (int)to_ret->tv_sec,
295                 (int)to_ret->tv_usec));
296
297         return to_ret;
298 }
299
300 int event_loop_once(struct event_context *ev)
301 {
302         struct timeval now, to;
303         fd_set r_fds, w_fds;
304         int maxfd = 0;
305         int ret;
306
307         FD_ZERO(&r_fds);
308         FD_ZERO(&w_fds);
309
310         to.tv_sec = 9999;       /* Max timeout */
311         to.tv_usec = 0;
312
313         GetTimeOfDay(&now);
314
315         if (!event_add_to_select_args(ev, &now, &r_fds, &w_fds, &to, &maxfd)) {
316                 return -1;
317         }
318
319         if (timeval_is_zero(&to)) {
320                 run_events(ev, 0, NULL, NULL);
321                 return 0;
322         }
323
324         ret = sys_select(maxfd+1, &r_fds, &w_fds, NULL, &to);
325
326         if (ret == -1 && errno != EINTR) {
327                 return -1;
328         }
329
330         run_events(ev, ret, &r_fds, &w_fds);
331         return 0;
332 }
333
334 static int event_context_destructor(struct event_context *ev)
335 {
336         while (ev->fd_events != NULL) {
337                 ev->fd_events->event_ctx = NULL;
338                 DLIST_REMOVE(ev->fd_events, ev->fd_events);
339         }
340         while (ev->timed_events != NULL) {
341                 ev->timed_events->event_ctx = NULL;
342                 DLIST_REMOVE(ev->timed_events, ev->timed_events);
343         }
344         return 0;
345 }
346
347 void event_context_reinit(struct event_context *ev)
348 {
349         event_context_destructor(ev);
350         return;
351 }
352
353 struct event_context *event_context_init(TALLOC_CTX *mem_ctx)
354 {
355         struct event_context *result;
356
357         result = TALLOC_ZERO_P(mem_ctx, struct event_context);
358         if (result == NULL) {
359                 return NULL;
360         }
361
362         talloc_set_destructor(result, event_context_destructor);
363         return result;
364 }
365
366 int set_event_dispatch_time(struct event_context *event_ctx,
367                             const char *event_name, struct timeval when)
368 {
369         struct timed_event *te;
370
371         for (te = event_ctx->timed_events; te; te = te->next) {
372                 if (strcmp(event_name, te->event_name) == 0) {
373                         DLIST_REMOVE(event_ctx->timed_events, te);
374                         te->when = when;
375                         add_event_by_time(te);
376                         return 1;
377                 }
378         }
379         return 0;
380 }
381
382 /* Returns 1 if event was found and cancelled, 0 otherwise. */
383
384 int cancel_named_event(struct event_context *event_ctx,
385                        const char *event_name)
386 {
387         struct timed_event *te;
388
389         for (te = event_ctx->timed_events; te; te = te->next) {
390                 if (strcmp(event_name, te->event_name) == 0) {
391                         TALLOC_FREE(te);
392                         return 1;
393                 }
394         }
395         return 0;
396 }
397
398 void dump_event_list(struct event_context *event_ctx)
399 {
400         struct timed_event *te;
401         struct fd_event *fe;
402         struct timeval evt, now;
403
404         if (!event_ctx) {
405                 return;
406         }
407
408         now = timeval_current();
409
410         DEBUG(10,("dump_event_list:\n"));
411
412         for (te = event_ctx->timed_events; te; te = te->next) {
413
414                 evt = timeval_until(&now, &te->when);
415
416                 DEBUGADD(10,("Timed Event \"%s\" %lx handled in %d seconds (at %s)\n",
417                            te->event_name,
418                            (unsigned long)te,
419                            (int)evt.tv_sec,
420                            http_timestring(talloc_tos(), te->when.tv_sec)));
421         }
422
423         for (fe = event_ctx->fd_events; fe; fe = fe->next) {
424
425                 DEBUGADD(10,("FD Event %d %lx, flags: 0x%04x\n",
426                            fe->fd,
427                            (unsigned long)fe,
428                            fe->flags));
429         }
430 }