r20913: Fix the build.
[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 2 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, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 struct timed_event {
25         struct timed_event *next, *prev;
26         struct event_context *event_ctx;
27         struct timeval when;
28         const char *event_name;
29         void (*handler)(struct event_context *event_ctx,
30                         struct timed_event *te,
31                         const struct timeval *now,
32                         void *private_data);
33         void *private_data;
34 };
35
36 struct fd_event {
37         struct fd_event *prev, *next;
38         struct event_context *event_ctx;
39         int fd;
40         uint16_t flags; /* see EVENT_FD_* flags */
41         void (*handler)(struct event_context *event_ctx,
42                         struct fd_event *event,
43                         uint16 flags,
44                         void *private_data);
45         void *private_data;
46 };
47
48 #define EVENT_FD_WRITEABLE(fde) \
49         event_set_fd_flags(fde, event_get_fd_flags(fde) | EVENT_FD_WRITE)
50 #define EVENT_FD_READABLE(fde) \
51         event_set_fd_flags(fde, event_get_fd_flags(fde) | EVENT_FD_READ)
52
53 #define EVENT_FD_NOT_WRITEABLE(fde) \
54         event_set_fd_flags(fde, event_get_fd_flags(fde) & ~EVENT_FD_WRITE)
55 #define EVENT_FD_NOT_READABLE(fde) \
56         event_set_fd_flags(fde, event_get_fd_flags(fde) & ~EVENT_FD_READ)
57
58 struct event_context {
59         struct timed_event *timed_events;
60         struct fd_event *fd_events;
61 };
62
63 static int timed_event_destructor(struct timed_event *te)
64 {
65         DEBUG(10, ("Destroying timed event %lx \"%s\"\n", (unsigned long)te,
66                 te->event_name));
67         DLIST_REMOVE(te->event_ctx->timed_events, te);
68         return 0;
69 }
70
71 /****************************************************************************
72  Add te by time.
73 ****************************************************************************/
74
75 static void add_event_by_time(struct timed_event *te)
76 {
77         struct event_context *ctx = te->event_ctx;
78         struct timed_event *last_te, *cur_te;
79
80         /* Keep the list ordered by time. We must preserve this. */
81         last_te = NULL;
82         for (cur_te = ctx->timed_events; cur_te; cur_te = cur_te->next) {
83                 /* if the new event comes before the current one break */
84                 if (!timeval_is_zero(&cur_te->when) &&
85                                 timeval_compare(&te->when, &cur_te->when) < 0) {
86                         break;
87                 }
88                 last_te = cur_te;
89         }
90
91         DLIST_ADD_AFTER(ctx->timed_events, te, last_te);
92 }
93
94 /****************************************************************************
95  Schedule a function for future calling, cancel with TALLOC_FREE().
96  It's the responsibility of the handler to call TALLOC_FREE() on the event
97  handed to it.
98 ****************************************************************************/
99
100 struct timed_event *event_add_timed(struct event_context *event_ctx,
101                                 TALLOC_CTX *mem_ctx,
102                                 struct timeval when,
103                                 const char *event_name,
104                                 void (*handler)(struct event_context *event_ctx,
105                                                 struct timed_event *te,
106                                                 const struct timeval *now,
107                                                 void *private_data),
108                                 void *private_data)
109 {
110         struct timed_event *te;
111
112         te = TALLOC_P(mem_ctx, struct timed_event);
113         if (te == NULL) {
114                 DEBUG(0, ("talloc failed\n"));
115                 return NULL;
116         }
117
118         te->event_ctx = event_ctx;
119         te->when = when;
120         te->event_name = event_name;
121         te->handler = handler;
122         te->private_data = private_data;
123
124         add_event_by_time(te);
125
126         talloc_set_destructor(te, timed_event_destructor);
127
128         DEBUG(10, ("Added timed event \"%s\": %lx\n", event_name,
129                         (unsigned long)te));
130         return te;
131 }
132
133 static int fd_event_destructor(struct fd_event *fde)
134 {
135         struct event_context *event_ctx = fde->event_ctx;
136
137         DLIST_REMOVE(event_ctx->fd_events, fde);
138         return 0;
139 }
140
141 struct fd_event *event_add_fd(struct event_context *event_ctx,
142                               TALLOC_CTX *mem_ctx,
143                               int fd, uint16_t flags,
144                               void (*handler)(struct event_context *event_ctx,
145                                               struct fd_event *event,
146                                               uint16 flags,
147                                               void *private_data),
148                               void *private_data)
149 {
150         struct fd_event *fde;
151
152         if (!(fde = TALLOC_P(mem_ctx, struct fd_event))) {
153                 return NULL;
154         }
155
156         fde->event_ctx = event_ctx;
157         fde->fd = fd;
158         fde->flags = flags;
159         fde->handler = handler;
160         fde->private_data = private_data;
161
162         DLIST_ADD(event_ctx->fd_events, fde);
163
164         talloc_set_destructor(fde, fd_event_destructor);
165         return fde;
166 }
167
168 void event_fd_set_writeable(struct fd_event *fde)
169 {
170         fde->flags |= EVENT_FD_WRITE;
171 }
172
173 void event_fd_set_not_writeable(struct fd_event *fde)
174 {
175         fde->flags &= ~EVENT_FD_WRITE;
176 }
177
178 void event_fd_set_readable(struct fd_event *fde)
179 {
180         fde->flags |= EVENT_FD_READ;
181 }
182
183 void event_fd_set_not_readable(struct fd_event *fde)
184 {
185         fde->flags &= ~EVENT_FD_READ;
186 }
187
188 void event_add_to_select_args(struct event_context *event_ctx,
189                               const struct timeval *now,
190                               fd_set *read_fds, fd_set *write_fds,
191                               struct timeval *timeout, int *maxfd)
192 {
193         struct fd_event *fde;
194         struct timeval diff;
195
196         for (fde = event_ctx->fd_events; fde; fde = fde->next) {
197                 if (fde->flags & EVENT_FD_READ) {
198                         FD_SET(fde->fd, read_fds);
199                 }
200                 if (fde->flags & EVENT_FD_WRITE) {
201                         FD_SET(fde->fd, write_fds);
202                 }
203
204                 if ((fde->flags & (EVENT_FD_READ|EVENT_FD_WRITE))
205                     && (fde->fd > *maxfd)) {
206                         *maxfd = fde->fd;
207                 }
208         }
209
210         if (event_ctx->timed_events == NULL) {
211                 return;
212         }
213
214         diff = timeval_until(now, &event_ctx->timed_events->when);
215         *timeout = timeval_min(timeout, &diff);
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) {
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 struct event_context *event_context_init(TALLOC_CTX *mem_ctx)
301 {
302         return TALLOC_ZERO_P(NULL, struct event_context);
303 }
304
305 int set_event_dispatch_time(struct event_context *event_ctx,
306                             const char *event_name, struct timeval when)
307 {
308         struct timed_event *te;
309
310         for (te = event_ctx->timed_events; te; te = te->next) {
311                 if (strcmp(event_name, te->event_name) == 0) {
312                         DLIST_REMOVE(event_ctx->timed_events, te);
313                         te->when = when;
314                         add_event_by_time(te);
315                         return 1;
316                 }
317         }
318         return 0;
319 }
320
321 /* Returns 1 if event was found and cancelled, 0 otherwise. */
322
323 int cancel_named_event(struct event_context *event_ctx,
324                        const char *event_name)
325 {
326         struct timed_event *te;
327
328         for (te = event_ctx->timed_events; te; te = te->next) {
329                 if (strcmp(event_name, te->event_name) == 0) {
330                         TALLOC_FREE(te);
331                         return 1;
332                 }
333         }
334         return 0;
335 }