3b7794b0ddeccc1bd3c645637be9d316366ff12e
[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 /*
418   this is used to catch debug messages from events
419 */
420 static void s3_event_debug(void *context, enum tevent_debug_level level,
421                            const char *fmt, va_list ap)  PRINTF_ATTRIBUTE(3,0);
422
423 static void s3_event_debug(void *context, enum tevent_debug_level level,
424                            const char *fmt, va_list ap)
425 {
426         int samba_level = -1;
427         char *s = NULL;
428         switch (level) {
429         case TEVENT_DEBUG_FATAL:
430                 samba_level = 0;
431                 break;
432         case TEVENT_DEBUG_ERROR:
433                 samba_level = 1;
434                 break;
435         case TEVENT_DEBUG_WARNING:
436                 samba_level = 2;
437                 break;
438         case TEVENT_DEBUG_TRACE:
439                 samba_level = 11;
440                 break;
441
442         };
443         if (CHECK_DEBUGLVL(samba_level)) {
444                 if (vasprintf(&s, fmt, ap) == -1) {
445                         return;
446                 }
447                 DEBUG(samba_level, ("s3_event: %s", s));
448                 free(s);
449         }
450 }
451
452 struct tevent_context *s3_tevent_context_init(TALLOC_CTX *mem_ctx)
453 {
454         struct tevent_context *ev;
455
456         s3_tevent_init();
457
458         ev = tevent_context_init_byname(mem_ctx, "s3");
459         if (ev) {
460                 tevent_set_debug(ev, s3_event_debug, NULL);
461         }
462
463         return ev;
464 }
465
466 struct idle_event {
467         struct tevent_timer *te;
468         struct timeval interval;
469         char *name;
470         bool (*handler)(const struct timeval *now, void *private_data);
471         void *private_data;
472 };
473
474 static void smbd_idle_event_handler(struct tevent_context *ctx,
475                                     struct tevent_timer *te,
476                                     struct timeval now,
477                                     void *private_data)
478 {
479         struct idle_event *event =
480                 talloc_get_type_abort(private_data, struct idle_event);
481
482         TALLOC_FREE(event->te);
483
484         DEBUG(10,("smbd_idle_event_handler: %s %p called\n",
485                   event->name, event->te));
486
487         if (!event->handler(&now, event->private_data)) {
488                 DEBUG(10,("smbd_idle_event_handler: %s %p stopped\n",
489                           event->name, event->te));
490                 /* Don't repeat, delete ourselves */
491                 TALLOC_FREE(event);
492                 return;
493         }
494
495         DEBUG(10,("smbd_idle_event_handler: %s %p rescheduled\n",
496                   event->name, event->te));
497
498         event->te = tevent_add_timer(ctx, event,
499                                      timeval_sum(&now, &event->interval),
500                                      smbd_idle_event_handler, event);
501
502         /* We can't do much but fail here. */
503         SMB_ASSERT(event->te != NULL);
504 }
505
506 struct idle_event *event_add_idle(struct tevent_context *event_ctx,
507                                   TALLOC_CTX *mem_ctx,
508                                   struct timeval interval,
509                                   const char *name,
510                                   bool (*handler)(const struct timeval *now,
511                                                   void *private_data),
512                                   void *private_data)
513 {
514         struct idle_event *result;
515         struct timeval now = timeval_current();
516
517         result = talloc(mem_ctx, struct idle_event);
518         if (result == NULL) {
519                 DEBUG(0, ("talloc failed\n"));
520                 return NULL;
521         }
522
523         result->interval = interval;
524         result->handler = handler;
525         result->private_data = private_data;
526
527         if (!(result->name = talloc_asprintf(result, "idle_evt(%s)", name))) {
528                 DEBUG(0, ("talloc failed\n"));
529                 TALLOC_FREE(result);
530                 return NULL;
531         }
532
533         result->te = tevent_add_timer(event_ctx, result,
534                                       timeval_sum(&now, &interval),
535                                       smbd_idle_event_handler, result);
536         if (result->te == NULL) {
537                 DEBUG(0, ("event_add_timed failed\n"));
538                 TALLOC_FREE(result);
539                 return NULL;
540         }
541
542         DEBUG(10,("event_add_idle: %s %p\n", result->name, result->te));
543         return result;
544 }
545