source: branches/samba-3.2.x/source/lib/events.c

Last change on this file was 232, checked in by Herwig Bauernfeind, 16 years ago

Update 3.2 branch to 3.2.8

File size: 9.7 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 const 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
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)
51
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)
56
57struct event_context {
58 struct timed_event *timed_events;
59 struct fd_event *fd_events;
60};
61
62static int timed_event_destructor(struct timed_event *te)
63{
64 DEBUG(10, ("Destroying timed event %lx \"%s\"\n", (unsigned long)te,
65 te->event_name));
66 if (te->event_ctx) {
67 DLIST_REMOVE(te->event_ctx->timed_events, te);
68 }
69 return 0;
70}
71
72/****************************************************************************
73 Add te by time.
74****************************************************************************/
75
76static void add_event_by_time(struct timed_event *te)
77{
78 struct event_context *ctx = te->event_ctx;
79 struct timed_event *last_te, *cur_te;
80
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;
88 }
89 last_te = cur_te;
90 }
91
92 DLIST_ADD_AFTER(ctx->timed_events, te, last_te);
93}
94
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****************************************************************************/
100
101struct 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)
110{
111 struct timed_event *te;
112
113 te = TALLOC_P(mem_ctx, struct timed_event);
114 if (te == NULL) {
115 DEBUG(0, ("talloc failed\n"));
116 return NULL;
117 }
118
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;
124
125 add_event_by_time(te);
126
127 talloc_set_destructor(te, timed_event_destructor);
128
129 DEBUG(10, ("Added timed event \"%s\": %lx\n", event_name,
130 (unsigned long)te));
131 return te;
132}
133
134static int fd_event_destructor(struct fd_event *fde)
135{
136 struct event_context *event_ctx = fde->event_ctx;
137
138 if (event_ctx) {
139 DLIST_REMOVE(event_ctx->fd_events, fde);
140 }
141 return 0;
142}
143
144struct fd_event *event_add_fd(struct event_context *event_ctx,
145 TALLOC_CTX *mem_ctx,
146 int fd, uint16_t flags,
147 void (*handler)(struct event_context *event_ctx,
148 struct fd_event *event,
149 uint16 flags,
150 void *private_data),
151 void *private_data)
152{
153 struct fd_event *fde;
154
155 if (!(fde = TALLOC_P(mem_ctx, struct fd_event))) {
156 return NULL;
157 }
158
159 fde->event_ctx = event_ctx;
160 fde->fd = fd;
161 fde->flags = flags;
162 fde->handler = handler;
163 fde->private_data = private_data;
164
165 DLIST_ADD(event_ctx->fd_events, fde);
166
167 talloc_set_destructor(fde, fd_event_destructor);
168 return fde;
169}
170
171void event_fd_set_writeable(struct fd_event *fde)
172{
173 fde->flags |= EVENT_FD_WRITE;
174}
175
176void event_fd_set_not_writeable(struct fd_event *fde)
177{
178 fde->flags &= ~EVENT_FD_WRITE;
179}
180
181void event_fd_set_readable(struct fd_event *fde)
182{
183 fde->flags |= EVENT_FD_READ;
184}
185
186void event_fd_set_not_readable(struct fd_event *fde)
187{
188 fde->flags &= ~EVENT_FD_READ;
189}
190
191/*
192 * Return if there's something in the queue
193 */
194
195bool event_add_to_select_args(struct event_context *event_ctx,
196 const struct timeval *now,
197 fd_set *read_fds, fd_set *write_fds,
198 struct timeval *timeout, int *maxfd)
199{
200 struct fd_event *fde;
201 struct timeval diff;
202 bool ret = False;
203
204 for (fde = event_ctx->fd_events; fde; fde = fde->next) {
205 if (fde->flags & EVENT_FD_READ) {
206 FD_SET(fde->fd, read_fds);
207 ret = True;
208 }
209 if (fde->flags & EVENT_FD_WRITE) {
210 FD_SET(fde->fd, write_fds);
211 ret = True;
212 }
213
214 if ((fde->flags & (EVENT_FD_READ|EVENT_FD_WRITE))
215 && (fde->fd > *maxfd)) {
216 *maxfd = fde->fd;
217 }
218 }
219
220 if (event_ctx->timed_events == NULL) {
221 return ret;
222 }
223
224 diff = timeval_until(now, &event_ctx->timed_events->when);
225 *timeout = timeval_min(timeout, &diff);
226
227 return True;
228}
229
230bool events_pending(struct event_context *event_ctx)
231{
232 struct fd_event *fde;
233
234 if (event_ctx->timed_events != NULL) {
235 return True;
236 }
237 for (fde = event_ctx->fd_events; fde; fde = fde->next) {
238 if (fde->flags & (EVENT_FD_READ|EVENT_FD_WRITE)) {
239 return True;
240 }
241 }
242 return False;
243}
244
245bool run_events(struct event_context *event_ctx,
246 int selrtn, fd_set *read_fds, fd_set *write_fds)
247{
248 struct fd_event *fde;
249 struct timeval now;
250
251 GetTimeOfDay(&now);
252
253 if ((event_ctx->timed_events != NULL)
254 && (timeval_compare(&now, &event_ctx->timed_events->when) >= 0)) {
255
256 DEBUG(10, ("Running event \"%s\" %lx\n",
257 event_ctx->timed_events->event_name,
258 (unsigned long)event_ctx->timed_events));
259
260 event_ctx->timed_events->handler(
261 event_ctx,
262 event_ctx->timed_events, &now,
263 event_ctx->timed_events->private_data);
264
265 return true;
266 }
267
268 if (selrtn == 0) {
269 /*
270 * No fd ready
271 */
272 return false;
273 }
274
275 for (fde = event_ctx->fd_events; fde; fde = fde->next) {
276 uint16 flags = 0;
277
278 if (FD_ISSET(fde->fd, read_fds)) flags |= EVENT_FD_READ;
279 if (FD_ISSET(fde->fd, write_fds)) flags |= EVENT_FD_WRITE;
280
281 if (flags) {
282 fde->handler(event_ctx, fde, flags, fde->private_data);
283 return true;
284 }
285 }
286
287 return false;
288}
289
290
291struct timeval *get_timed_events_timeout(struct event_context *event_ctx,
292 struct timeval *to_ret)
293{
294 struct timeval now;
295
296 if (event_ctx->timed_events == NULL) {
297 return NULL;
298 }
299
300 now = timeval_current();
301 *to_ret = timeval_until(&now, &event_ctx->timed_events->when);
302
303 DEBUG(10, ("timed_events_timeout: %d/%d\n", (int)to_ret->tv_sec,
304 (int)to_ret->tv_usec));
305
306 return to_ret;
307}
308
309int event_loop_once(struct event_context *ev)
310{
311 struct timeval now, to;
312 fd_set r_fds, w_fds;
313 int maxfd = 0;
314 int ret;
315
316 FD_ZERO(&r_fds);
317 FD_ZERO(&w_fds);
318
319 to.tv_sec = 9999; /* Max timeout */
320 to.tv_usec = 0;
321
322 GetTimeOfDay(&now);
323
324 if (!event_add_to_select_args(ev, &now, &r_fds, &w_fds, &to, &maxfd)) {
325 return -1;
326 }
327
328 if (timeval_is_zero(&to)) {
329 run_events(ev, 0, NULL, NULL);
330 return 0;
331 }
332
333 ret = sys_select(maxfd+1, &r_fds, &w_fds, NULL, &to);
334
335 if (ret == -1 && errno != EINTR) {
336 return -1;
337 }
338
339 run_events(ev, ret, &r_fds, &w_fds);
340 return 0;
341}
342
343static int event_context_destructor(struct event_context *ev)
344{
345 while (ev->fd_events != NULL) {
346 ev->fd_events->event_ctx = NULL;
347 DLIST_REMOVE(ev->fd_events, ev->fd_events);
348 }
349 while (ev->timed_events != NULL) {
350 ev->timed_events->event_ctx = NULL;
351 DLIST_REMOVE(ev->timed_events, ev->timed_events);
352 }
353 return 0;
354}
355
356void event_context_reinit(struct event_context *ev)
357{
358 event_context_destructor(ev);
359 return;
360}
361
362struct event_context *event_context_init(TALLOC_CTX *mem_ctx)
363{
364 struct event_context *result;
365
366 result = TALLOC_ZERO_P(mem_ctx, struct event_context);
367 if (result == NULL) {
368 return NULL;
369 }
370
371 talloc_set_destructor(result, event_context_destructor);
372 return result;
373}
374
375void dump_event_list(struct event_context *event_ctx)
376{
377 struct timed_event *te;
378 struct fd_event *fe;
379 struct timeval evt, now;
380
381 if (!event_ctx) {
382 return;
383 }
384
385 now = timeval_current();
386
387 DEBUG(10,("dump_event_list:\n"));
388
389 for (te = event_ctx->timed_events; te; te = te->next) {
390
391 evt = timeval_until(&now, &te->when);
392
393 DEBUGADD(10,("Timed Event \"%s\" %lx handled in %d seconds (at %s)\n",
394 te->event_name,
395 (unsigned long)te,
396 (int)evt.tv_sec,
397 http_timestring(te->when.tv_sec)));
398 }
399
400 for (fe = event_ctx->fd_events; fe; fe = fe->next) {
401
402 DEBUGADD(10,("FD Event %d %lx, flags: 0x%04x\n",
403 fe->fd,
404 (unsigned long)fe,
405 fe->flags));
406 }
407}
Note: See TracBrowser for help on using the repository browser.