source: branches/samba-3.3.x/source/lib/events.c@ 217

Last change on this file since 217 was 206, checked in by Herwig Bauernfeind, 16 years ago

Import Samba 3.3 branch at 3.0.0 level (psmedley's port)

File size: 8.9 KB
Line 
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
23struct 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 struct timeval now,
31 void *private_data);
32 void *private_data;
33};
34
35struct 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
47struct event_context {
48 struct timed_event *timed_events;
49 struct fd_event *fd_events;
50};
51
52static 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
66static 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
91struct 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 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
124static 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
132struct 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
159void event_fd_set_writeable(struct fd_event *fde)
160{
161 fde->flags |= EVENT_FD_WRITE;
162}
163
164void event_fd_set_not_writeable(struct fd_event *fde)
165{
166 fde->flags &= ~EVENT_FD_WRITE;
167}
168
169void event_fd_set_readable(struct fd_event *fde)
170{
171 fde->flags |= EVENT_FD_READ;
172}
173
174void 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
183bool 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
218bool 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
282struct 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
300int 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
334static 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
347void event_context_reinit(struct event_context *ev)
348{
349 event_context_destructor(ev);
350 return;
351}
352
353struct 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
366void dump_event_list(struct event_context *event_ctx)
367{
368 struct timed_event *te;
369 struct fd_event *fe;
370 struct timeval evt, now;
371
372 if (!event_ctx) {
373 return;
374 }
375
376 now = timeval_current();
377
378 DEBUG(10,("dump_event_list:\n"));
379
380 for (te = event_ctx->timed_events; te; te = te->next) {
381
382 evt = timeval_until(&now, &te->when);
383
384 DEBUGADD(10,("Timed Event \"%s\" %lx handled in %d seconds (at %s)\n",
385 te->event_name,
386 (unsigned long)te,
387 (int)evt.tv_sec,
388 http_timestring(te->when.tv_sec)));
389 }
390
391 for (fe = event_ctx->fd_events; fe; fe = fe->next) {
392
393 DEBUGADD(10,("FD Event %d %lx, flags: 0x%04x\n",
394 fe->fd,
395 (unsigned long)fe,
396 fe->flags));
397 }
398}
Note: See TracBrowser for help on using the repository browser.