source: branches/samba-3.0/source/lib/events.c@ 134

Last change on this file since 134 was 1, checked in by Paul Smedley, 18 years ago

Initial code import

File size: 8.1 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 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
24struct 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
36struct 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
58struct event_context {
59 struct timed_event *timed_events;
60 struct fd_event *fd_events;
61};
62
63static 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
75static 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
100struct 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
133static 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
141struct 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
168void event_fd_set_writeable(struct fd_event *fde)
169{
170 fde->flags |= EVENT_FD_WRITE;
171}
172
173void event_fd_set_not_writeable(struct fd_event *fde)
174{
175 fde->flags &= ~EVENT_FD_WRITE;
176}
177
178void event_fd_set_readable(struct fd_event *fde)
179{
180 fde->flags |= EVENT_FD_READ;
181}
182
183void event_fd_set_not_readable(struct fd_event *fde)
184{
185 fde->flags &= ~EVENT_FD_READ;
186}
187
188void 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
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) {
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
300struct event_context *event_context_init(TALLOC_CTX *mem_ctx)
301{
302 return TALLOC_ZERO_P(NULL, struct event_context);
303}
304
305int 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
323int 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}
Note: See TracBrowser for help on using the repository browser.