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

Last change on this file since 457 was 165, checked in by Paul Smedley, 16 years ago

Add 'missing' 3.0.34 diffs

File size: 8.0 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 if (te->event_ctx) {
68 DLIST_REMOVE(te->event_ctx->timed_events, te);
69 }
70 return 0;
71}
72
73/****************************************************************************
74 Add te by time.
75****************************************************************************/
76
77static void add_event_by_time(struct timed_event *te)
78{
79 struct event_context *ctx = te->event_ctx;
80 struct timed_event *last_te, *cur_te;
81
82 /* Keep the list ordered by time. We must preserve this. */
83 last_te = NULL;
84 for (cur_te = ctx->timed_events; cur_te; cur_te = cur_te->next) {
85 /* if the new event comes before the current one break */
86 if (!timeval_is_zero(&cur_te->when) &&
87 timeval_compare(&te->when, &cur_te->when) < 0) {
88 break;
89 }
90 last_te = cur_te;
91 }
92
93 DLIST_ADD_AFTER(ctx->timed_events, te, last_te);
94}
95
96/****************************************************************************
97 Schedule a function for future calling, cancel with TALLOC_FREE().
98 It's the responsibility of the handler to call TALLOC_FREE() on the event
99 handed to it.
100****************************************************************************/
101
102struct timed_event *event_add_timed(struct event_context *event_ctx,
103 TALLOC_CTX *mem_ctx,
104 struct timeval when,
105 const char *event_name,
106 void (*handler)(struct event_context *event_ctx,
107 struct timed_event *te,
108 const struct timeval *now,
109 void *private_data),
110 void *private_data)
111{
112 struct timed_event *te;
113
114 te = TALLOC_P(mem_ctx, struct timed_event);
115 if (te == NULL) {
116 DEBUG(0, ("talloc failed\n"));
117 return NULL;
118 }
119
120 te->event_ctx = event_ctx;
121 te->when = when;
122 te->event_name = event_name;
123 te->handler = handler;
124 te->private_data = private_data;
125
126 add_event_by_time(te);
127
128 talloc_set_destructor(te, timed_event_destructor);
129
130 DEBUG(10, ("Added timed event \"%s\": %lx\n", event_name,
131 (unsigned long)te));
132 return te;
133}
134
135static int fd_event_destructor(struct fd_event *fde)
136{
137 struct event_context *event_ctx = fde->event_ctx;
138
139 if (event_ctx) {
140 DLIST_REMOVE(event_ctx->fd_events, fde);
141 }
142 return 0;
143}
144
145struct fd_event *event_add_fd(struct event_context *event_ctx,
146 TALLOC_CTX *mem_ctx,
147 int fd, uint16_t flags,
148 void (*handler)(struct event_context *event_ctx,
149 struct fd_event *event,
150 uint16 flags,
151 void *private_data),
152 void *private_data)
153{
154 struct fd_event *fde;
155
156 if (!(fde = TALLOC_P(mem_ctx, struct fd_event))) {
157 return NULL;
158 }
159
160 fde->event_ctx = event_ctx;
161 fde->fd = fd;
162 fde->flags = flags;
163 fde->handler = handler;
164 fde->private_data = private_data;
165
166 DLIST_ADD(event_ctx->fd_events, fde);
167
168 talloc_set_destructor(fde, fd_event_destructor);
169 return fde;
170}
171
172void event_fd_set_writeable(struct fd_event *fde)
173{
174 fde->flags |= EVENT_FD_WRITE;
175}
176
177void event_fd_set_not_writeable(struct fd_event *fde)
178{
179 fde->flags &= ~EVENT_FD_WRITE;
180}
181
182void event_fd_set_readable(struct fd_event *fde)
183{
184 fde->flags |= EVENT_FD_READ;
185}
186
187void event_fd_set_not_readable(struct fd_event *fde)
188{
189 fde->flags &= ~EVENT_FD_READ;
190}
191
192void event_add_to_select_args(struct event_context *event_ctx,
193 const struct timeval *now,
194 fd_set *read_fds, fd_set *write_fds,
195 struct timeval *timeout, int *maxfd)
196{
197 struct fd_event *fde;
198 struct timeval diff;
199
200 for (fde = event_ctx->fd_events; fde; fde = fde->next) {
201 if (fde->flags & EVENT_FD_READ) {
202 FD_SET(fde->fd, read_fds);
203 }
204 if (fde->flags & EVENT_FD_WRITE) {
205 FD_SET(fde->fd, write_fds);
206 }
207
208 if ((fde->flags & (EVENT_FD_READ|EVENT_FD_WRITE))
209 && (fde->fd > *maxfd)) {
210 *maxfd = fde->fd;
211 }
212 }
213
214 if (event_ctx->timed_events == NULL) {
215 return;
216 }
217
218 diff = timeval_until(now, &event_ctx->timed_events->when);
219 *timeout = timeval_min(timeout, &diff);
220}
221
222BOOL run_events(struct event_context *event_ctx,
223 int selrtn, fd_set *read_fds, fd_set *write_fds)
224{
225 BOOL fired = False;
226 struct fd_event *fde, *next;
227
228 /* Run all events that are pending, not just one (as we
229 did previously. */
230
231 while (event_ctx->timed_events) {
232 struct timeval now;
233 GetTimeOfDay(&now);
234
235 if (timeval_compare(
236 &now, &event_ctx->timed_events->when) < 0) {
237 /* Nothing to do yet */
238 DEBUG(11, ("run_events: Nothing to do\n"));
239 break;
240 }
241
242 DEBUG(10, ("Running event \"%s\" %lx\n",
243 event_ctx->timed_events->event_name,
244 (unsigned long)event_ctx->timed_events));
245
246 event_ctx->timed_events->handler(
247 event_ctx,
248 event_ctx->timed_events, &now,
249 event_ctx->timed_events->private_data);
250
251 fired = True;
252 }
253
254 if (fired) {
255 /*
256 * We might have changed the socket status during the timed
257 * events, return to run select again.
258 */
259 return True;
260 }
261
262 if (selrtn == 0) {
263 /*
264 * No fd ready
265 */
266 return fired;
267 }
268
269 for (fde = event_ctx->fd_events; fde; fde = next) {
270 uint16 flags = 0;
271
272 next = fde->next;
273 if (FD_ISSET(fde->fd, read_fds)) flags |= EVENT_FD_READ;
274 if (FD_ISSET(fde->fd, write_fds)) flags |= EVENT_FD_WRITE;
275
276 if (flags) {
277 fde->handler(event_ctx, fde, flags, fde->private_data);
278 fired = True;
279 }
280 }
281
282 return fired;
283}
284
285
286struct timeval *get_timed_events_timeout(struct event_context *event_ctx,
287 struct timeval *to_ret)
288{
289 struct timeval now;
290
291 if (event_ctx->timed_events == NULL) {
292 return NULL;
293 }
294
295 now = timeval_current();
296 *to_ret = timeval_until(&now, &event_ctx->timed_events->when);
297
298 DEBUG(10, ("timed_events_timeout: %d/%d\n", (int)to_ret->tv_sec,
299 (int)to_ret->tv_usec));
300
301 return to_ret;
302}
303
304static int event_context_destructor(struct event_context *ev)
305{
306 while (ev->fd_events != NULL) {
307 ev->fd_events->event_ctx = NULL;
308 DLIST_REMOVE(ev->fd_events, ev->fd_events);
309 }
310 while (ev->timed_events != NULL) {
311 ev->timed_events->event_ctx = NULL;
312 DLIST_REMOVE(ev->timed_events, ev->timed_events);
313 }
314 return 0;
315}
316
317void event_context_reinit(struct event_context *ev)
318{
319 event_context_destructor(ev);
320 return;
321}
322
323struct event_context *event_context_init(TALLOC_CTX *mem_ctx)
324{
325 struct event_context *result;
326
327 result = TALLOC_ZERO_P(mem_ctx, struct event_context);
328 if (result == NULL) {
329 return NULL;
330 }
331
332 talloc_set_destructor(result, event_context_destructor);
333 return result;
334}
Note: See TracBrowser for help on using the repository browser.