0a8039ac6ea8c3d1ab8cb136f0e96343583bbccd
[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-2007
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 #include "lib/tevent/tevent_internal.h"
23 #include "../lib/util/select.h"
24 #include "system/select.h"
25
26 struct tevent_poll_private {
27         /*
28          * Index from file descriptor into the pollfd array
29          */
30         int *pollfd_idx;
31
32         /*
33          * Cache for s3_event_loop_once to avoid reallocs
34          */
35         struct pollfd *pfds;
36 };
37
38 static struct tevent_poll_private *tevent_get_poll_private(
39         struct tevent_context *ev)
40 {
41         struct tevent_poll_private *state;
42
43         state = (struct tevent_poll_private *)ev->additional_data;
44         if (state == NULL) {
45                 state = talloc_zero(ev, struct tevent_poll_private);
46                 ev->additional_data = (void *)state;
47                 if (state == NULL) {
48                         DEBUG(10, ("talloc failed\n"));
49                 }
50         }
51         return state;
52 }
53
54 static void count_fds(struct tevent_context *ev,
55                       int *pnum_fds, int *pmax_fd)
56 {
57         struct tevent_fd *fde;
58         int num_fds = 0;
59         int max_fd = 0;
60
61         for (fde = ev->fd_events; fde != NULL; fde = fde->next) {
62                 if (fde->flags & (TEVENT_FD_READ|TEVENT_FD_WRITE)) {
63                         num_fds += 1;
64                         if (fde->fd > max_fd) {
65                                 max_fd = fde->fd;
66                         }
67                 }
68         }
69         *pnum_fds = num_fds;
70         *pmax_fd = max_fd;
71 }
72
73 bool event_add_to_poll_args(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
74                             struct pollfd **pfds, int *pnum_pfds,
75                             int *ptimeout)
76 {
77         struct tevent_poll_private *state;
78         struct tevent_fd *fde;
79         int i, num_fds, max_fd, num_pollfds, idx_len;
80         struct pollfd *fds;
81         struct timeval now, diff;
82         int timeout;
83
84         state = tevent_get_poll_private(ev);
85         if (state == NULL) {
86                 return false;
87         }
88         count_fds(ev, &num_fds, &max_fd);
89
90         idx_len = max_fd+1;
91
92         if (talloc_array_length(state->pollfd_idx) < idx_len) {
93                 state->pollfd_idx = talloc_realloc(
94                         state, state->pollfd_idx, int, idx_len);
95                 if (state->pollfd_idx == NULL) {
96                         DEBUG(10, ("talloc_realloc failed\n"));
97                         return false;
98                 }
99         }
100
101         fds = *pfds;
102         num_pollfds = *pnum_pfds;
103
104         if (talloc_array_length(fds) < num_pollfds + num_fds) {
105                 fds = talloc_realloc(mem_ctx, fds, struct pollfd,
106                                            num_pollfds + num_fds);
107                 if (fds == NULL) {
108                         DEBUG(10, ("talloc_realloc failed\n"));
109                         return false;
110                 }
111         }
112
113         memset(&fds[num_pollfds], 0, sizeof(struct pollfd) * num_fds);
114
115         /*
116          * This needs tuning. We need to cope with multiple fde's for a file
117          * descriptor. The problem is that we need to re-use pollfd_idx across
118          * calls for efficiency. One way would be a direct bitmask that might
119          * be initialized quicker, but our bitmap_init implementation is
120          * pretty heavy-weight as well.
121          */
122         for (i=0; i<idx_len; i++) {
123                 state->pollfd_idx[i] = -1;
124         }
125
126         for (fde = ev->fd_events; fde; fde = fde->next) {
127                 struct pollfd *pfd;
128
129                 if ((fde->flags & (TEVENT_FD_READ|TEVENT_FD_WRITE)) == 0) {
130                         continue;
131                 }
132
133                 if (state->pollfd_idx[fde->fd] == -1) {
134                         /*
135                          * We haven't seen this fd yet. Allocate a new pollfd.
136                          */
137                         state->pollfd_idx[fde->fd] = num_pollfds;
138                         pfd = &fds[num_pollfds];
139                         num_pollfds += 1;
140                 } else {
141                         /*
142                          * We have already seen this fd. OR in the flags.
143                          */
144                         pfd = &fds[state->pollfd_idx[fde->fd]];
145                 }
146
147                 pfd->fd = fde->fd;
148
149                 if (fde->flags & TEVENT_FD_READ) {
150                         pfd->events |= (POLLIN|POLLHUP);
151                 }
152                 if (fde->flags & TEVENT_FD_WRITE) {
153                         pfd->events |= POLLOUT;
154                 }
155         }
156         *pfds = fds;
157         *pnum_pfds = num_pollfds;
158
159         if (ev->immediate_events != NULL) {
160                 *ptimeout = 0;
161                 return true;
162         }
163         if (ev->timer_events == NULL) {
164                 *ptimeout = MIN(*ptimeout, INT_MAX);
165                 return true;
166         }
167
168         now = timeval_current();
169         diff = timeval_until(&now, &ev->timer_events->next_event);
170         timeout = timeval_to_msec(diff);
171
172         if (timeout < *ptimeout) {
173                 *ptimeout = timeout;
174         }
175
176         return true;
177 }
178
179 bool run_events_poll(struct tevent_context *ev, int pollrtn,
180                      struct pollfd *pfds, int num_pfds)
181 {
182         struct tevent_poll_private *state;
183         int *pollfd_idx;
184         struct tevent_fd *fde;
185         struct timeval now;
186
187         if (ev->signal_events &&
188             tevent_common_check_signal(ev)) {
189                 return true;
190         }
191
192         if (ev->immediate_events &&
193             tevent_common_loop_immediate(ev)) {
194                 return true;
195         }
196
197         GetTimeOfDay(&now);
198
199         if ((ev->timer_events != NULL)
200             && (timeval_compare(&now, &ev->timer_events->next_event) >= 0)) {
201                 /* this older events system did not auto-free timed
202                    events on running them, and had a race condition
203                    where the event could be called twice if the
204                    talloc_free of the te happened after the callback
205                    made a call which invoked the event loop. To avoid
206                    this while still allowing old code which frees the
207                    te, we need to create a temporary context which
208                    will be used to ensure the te is freed. We also
209                    remove the te from the timed event list before we
210                    call the handler, to ensure we can't loop */
211
212                 struct tevent_timer *te = ev->timer_events;
213                 TALLOC_CTX *tmp_ctx = talloc_new(ev);
214
215                 DEBUG(10, ("Running timed event \"%s\" %p\n",
216                            ev->timer_events->handler_name, ev->timer_events));
217
218                 DLIST_REMOVE(ev->timer_events, te);
219                 talloc_steal(tmp_ctx, te);
220
221                 te->handler(ev, te, now, te->private_data);
222
223                 talloc_free(tmp_ctx);
224                 return true;
225         }
226
227         if (pollrtn <= 0) {
228                 /*
229                  * No fd ready
230                  */
231                 return false;
232         }
233
234         state = (struct tevent_poll_private *)ev->additional_data;
235         pollfd_idx = state->pollfd_idx;
236
237         for (fde = ev->fd_events; fde; fde = fde->next) {
238                 struct pollfd *pfd;
239                 uint16 flags = 0;
240
241                 if ((fde->flags & (TEVENT_FD_READ|TEVENT_FD_WRITE)) == 0) {
242                         continue;
243                 }
244
245                 if (pollfd_idx[fde->fd] >= num_pfds) {
246                         DEBUG(1, ("internal error: pollfd_idx[fde->fd] (%d) "
247                                   ">= num_pfds (%d)\n", pollfd_idx[fde->fd],
248                                   num_pfds));
249                         return false;
250                 }
251                 pfd = &pfds[pollfd_idx[fde->fd]];
252
253                 if (pfd->fd != fde->fd) {
254                         DEBUG(1, ("internal error: pfd->fd (%d) "
255                                   "!= fde->fd (%d)\n", pollfd_idx[fde->fd],
256                                   num_pfds));
257                         return false;
258                 }
259
260                 if (pfd->revents & (POLLHUP|POLLERR)) {
261                         /* If we only wait for TEVENT_FD_WRITE, we
262                            should not tell the event handler about it,
263                            and remove the writable flag, as we only
264                            report errors when waiting for read events
265                            to match the select behavior. */
266                         if (!(fde->flags & TEVENT_FD_READ)) {
267                                 TEVENT_FD_NOT_WRITEABLE(fde);
268                                 continue;
269                         }
270                         flags |= TEVENT_FD_READ;
271                 }
272
273                 if (pfd->revents & POLLIN) {
274                         flags |= TEVENT_FD_READ;
275                 }
276                 if (pfd->revents & POLLOUT) {
277                         flags |= TEVENT_FD_WRITE;
278                 }
279                 if (flags & fde->flags) {
280                         DLIST_DEMOTE(ev->fd_events, fde, struct tevent_fd);
281                         fde->handler(ev, fde, flags, fde->private_data);
282                         return true;
283                 }
284         }
285
286         return false;
287 }
288
289 struct timeval *get_timed_events_timeout(struct tevent_context *ev,
290                                          struct timeval *to_ret)
291 {
292         struct timeval now;
293
294         if ((ev->timer_events == NULL) && (ev->immediate_events == NULL)) {
295                 return NULL;
296         }
297         if (ev->immediate_events != NULL) {
298                 *to_ret = timeval_zero();
299                 return to_ret;
300         }
301
302         now = timeval_current();
303         *to_ret = timeval_until(&now, &ev->timer_events->next_event);
304
305         DEBUG(10, ("timed_events_timeout: %d/%d\n", (int)to_ret->tv_sec,
306                 (int)to_ret->tv_usec));
307
308         return to_ret;
309 }
310
311 static int s3_event_loop_once(struct tevent_context *ev, const char *location)
312 {
313         struct tevent_poll_private *state;
314         int timeout;
315         int num_pfds;
316         int ret;
317         int poll_errno;
318
319         timeout = INT_MAX;
320
321         state = tevent_get_poll_private(ev);
322         if (state == NULL) {
323                 errno = ENOMEM;
324                 return -1;
325         }
326
327         if (run_events_poll(ev, 0, NULL, 0)) {
328                 return 0;
329         }
330
331         num_pfds = 0;
332         if (!event_add_to_poll_args(ev, state,
333                                     &state->pfds, &num_pfds, &timeout)) {
334                 return -1;
335         }
336
337         tevent_trace_point_callback(ev, TEVENT_TRACE_BEFORE_WAIT);
338         ret = poll(state->pfds, num_pfds, timeout);
339         poll_errno = errno;
340         tevent_trace_point_callback(ev, TEVENT_TRACE_AFTER_WAIT);
341         errno = poll_errno;
342
343         if (ret == -1 && errno != EINTR) {
344                 tevent_debug(ev, TEVENT_DEBUG_FATAL,
345                              "poll() failed: %d:%s\n",
346                              errno, strerror(errno));
347                 return -1;
348         }
349
350         run_events_poll(ev, ret, state->pfds, num_pfds);
351         return 0;
352 }
353
354 static int s3_event_context_init(struct tevent_context *ev)
355 {
356         return 0;
357 }
358
359 void dump_event_list(struct tevent_context *ev)
360 {
361         struct tevent_timer *te;
362         struct tevent_fd *fe;
363         struct timeval evt, now;
364
365         if (!ev) {
366                 return;
367         }
368
369         now = timeval_current();
370
371         DEBUG(10,("dump_event_list:\n"));
372
373         for (te = ev->timer_events; te; te = te->next) {
374
375                 evt = timeval_until(&now, &te->next_event);
376
377                 DEBUGADD(10,("Timed Event \"%s\" %p handled in %d seconds (at %s)\n",
378                            te->handler_name,
379                            te,
380                            (int)evt.tv_sec,
381                            http_timestring(talloc_tos(), te->next_event.tv_sec)));
382         }
383
384         for (fe = ev->fd_events; fe; fe = fe->next) {
385
386                 DEBUGADD(10,("FD Event %d %p, flags: 0x%04x\n",
387                            fe->fd,
388                            fe,
389                            fe->flags));
390         }
391 }
392
393 static const struct tevent_ops s3_event_ops = {
394         .context_init           = s3_event_context_init,
395         .add_fd                 = tevent_common_add_fd,
396         .set_fd_close_fn        = tevent_common_fd_set_close_fn,
397         .get_fd_flags           = tevent_common_fd_get_flags,
398         .set_fd_flags           = tevent_common_fd_set_flags,
399         .add_timer              = tevent_common_add_timer,
400         .schedule_immediate     = tevent_common_schedule_immediate,
401         .add_signal             = tevent_common_add_signal,
402         .loop_once              = s3_event_loop_once,
403         .loop_wait              = tevent_common_loop_wait,
404 };
405
406 static bool s3_tevent_init(void)
407 {
408         static bool initialized;
409         if (initialized) {
410                 return true;
411         }
412         initialized = tevent_register_backend("s3", &s3_event_ops);
413         tevent_set_default_backend("s3");
414         return initialized;
415 }
416
417 struct tevent_context *s3_tevent_context_init(TALLOC_CTX *mem_ctx)
418 {
419         struct tevent_context *ev;
420
421         s3_tevent_init();
422
423         ev = tevent_context_init_byname(mem_ctx, "s3");
424         if (ev) {
425                 samba_tevent_set_debug(ev, "s3_tevent");
426         }
427
428         return ev;
429 }
430
431 struct idle_event {
432         struct tevent_timer *te;
433         struct timeval interval;
434         char *name;
435         bool (*handler)(const struct timeval *now, void *private_data);
436         void *private_data;
437 };
438
439 static void smbd_idle_event_handler(struct tevent_context *ctx,
440                                     struct tevent_timer *te,
441                                     struct timeval now,
442                                     void *private_data)
443 {
444         struct idle_event *event =
445                 talloc_get_type_abort(private_data, struct idle_event);
446
447         TALLOC_FREE(event->te);
448
449         DEBUG(10,("smbd_idle_event_handler: %s %p called\n",
450                   event->name, event->te));
451
452         if (!event->handler(&now, event->private_data)) {
453                 DEBUG(10,("smbd_idle_event_handler: %s %p stopped\n",
454                           event->name, event->te));
455                 /* Don't repeat, delete ourselves */
456                 TALLOC_FREE(event);
457                 return;
458         }
459
460         DEBUG(10,("smbd_idle_event_handler: %s %p rescheduled\n",
461                   event->name, event->te));
462
463         event->te = tevent_add_timer(ctx, event,
464                                      timeval_sum(&now, &event->interval),
465                                      smbd_idle_event_handler, event);
466
467         /* We can't do much but fail here. */
468         SMB_ASSERT(event->te != NULL);
469 }
470
471 struct idle_event *event_add_idle(struct tevent_context *event_ctx,
472                                   TALLOC_CTX *mem_ctx,
473                                   struct timeval interval,
474                                   const char *name,
475                                   bool (*handler)(const struct timeval *now,
476                                                   void *private_data),
477                                   void *private_data)
478 {
479         struct idle_event *result;
480         struct timeval now = timeval_current();
481
482         result = talloc(mem_ctx, struct idle_event);
483         if (result == NULL) {
484                 DEBUG(0, ("talloc failed\n"));
485                 return NULL;
486         }
487
488         result->interval = interval;
489         result->handler = handler;
490         result->private_data = private_data;
491
492         if (!(result->name = talloc_asprintf(result, "idle_evt(%s)", name))) {
493                 DEBUG(0, ("talloc failed\n"));
494                 TALLOC_FREE(result);
495                 return NULL;
496         }
497
498         result->te = tevent_add_timer(event_ctx, result,
499                                       timeval_sum(&now, &interval),
500                                       smbd_idle_event_handler, result);
501         if (result->te == NULL) {
502                 DEBUG(0, ("event_add_timed failed\n"));
503                 TALLOC_FREE(result);
504                 return NULL;
505         }
506
507         DEBUG(10,("event_add_idle: %s %p\n", result->name, result->te));
508         return result;
509 }
510