fc7f1d493a35d0684721b974cad253462f2bead1
[samba.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
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_P(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 & (EVENT_FD_READ|EVENT_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         /*
105          * The +1 is for the sys_poll calling convention. It expects
106          * an array 1 longer for the signal pipe
107          */
108
109         if (talloc_array_length(fds) < num_pollfds + num_fds + 1) {
110                 fds = talloc_realloc(mem_ctx, fds, struct pollfd,
111                                            num_pollfds + num_fds + 1);
112                 if (fds == NULL) {
113                         DEBUG(10, ("talloc_realloc failed\n"));
114                         return false;
115                 }
116         }
117
118         memset(&fds[num_pollfds], 0, sizeof(struct pollfd) * num_fds);
119
120         /*
121          * This needs tuning. We need to cope with multiple fde's for a file
122          * descriptor. The problem is that we need to re-use pollfd_idx across
123          * calls for efficiency. One way would be a direct bitmask that might
124          * be initialized quicker, but our bitmap_init implementation is
125          * pretty heavy-weight as well.
126          */
127         for (i=0; i<idx_len; i++) {
128                 state->pollfd_idx[i] = -1;
129         }
130
131         for (fde = ev->fd_events; fde; fde = fde->next) {
132                 struct pollfd *pfd;
133
134                 if ((fde->flags & (EVENT_FD_READ|EVENT_FD_WRITE)) == 0) {
135                         continue;
136                 }
137
138                 if (state->pollfd_idx[fde->fd] == -1) {
139                         /*
140                          * We haven't seen this fd yet. Allocate a new pollfd.
141                          */
142                         state->pollfd_idx[fde->fd] = num_pollfds;
143                         pfd = &fds[num_pollfds];
144                         num_pollfds += 1;
145                 } else {
146                         /*
147                          * We have already seen this fd. OR in the flags.
148                          */
149                         pfd = &fds[state->pollfd_idx[fde->fd]];
150                 }
151
152                 pfd->fd = fde->fd;
153
154                 if (fde->flags & EVENT_FD_READ) {
155                         pfd->events |= (POLLIN|POLLHUP);
156                 }
157                 if (fde->flags & EVENT_FD_WRITE) {
158                         pfd->events |= POLLOUT;
159                 }
160         }
161         *pfds = fds;
162         *pnum_pfds = num_pollfds;
163
164         if (ev->immediate_events != NULL) {
165                 *ptimeout = 0;
166                 return true;
167         }
168         if (ev->timer_events == NULL) {
169                 *ptimeout = MIN(*ptimeout, INT_MAX);
170                 return true;
171         }
172
173         now = timeval_current();
174         diff = timeval_until(&now, &ev->timer_events->next_event);
175         timeout = timeval_to_msec(diff);
176
177         if (timeout < *ptimeout) {
178                 *ptimeout = timeout;
179         }
180
181         return true;
182 }
183
184 bool run_events_poll(struct tevent_context *ev, int pollrtn,
185                      struct pollfd *pfds, int num_pfds)
186 {
187         struct tevent_poll_private *state;
188         int *pollfd_idx;
189         struct tevent_fd *fde;
190         struct timeval now;
191
192         if (ev->signal_events &&
193             tevent_common_check_signal(ev)) {
194                 return true;
195         }
196
197         if (ev->immediate_events &&
198             tevent_common_loop_immediate(ev)) {
199                 return true;
200         }
201
202         GetTimeOfDay(&now);
203
204         if ((ev->timer_events != NULL)
205             && (timeval_compare(&now, &ev->timer_events->next_event) >= 0)) {
206                 /* this older events system did not auto-free timed
207                    events on running them, and had a race condition
208                    where the event could be called twice if the
209                    talloc_free of the te happened after the callback
210                    made a call which invoked the event loop. To avoid
211                    this while still allowing old code which frees the
212                    te, we need to create a temporary context which
213                    will be used to ensure the te is freed. We also
214                    remove the te from the timed event list before we
215                    call the handler, to ensure we can't loop */
216
217                 struct tevent_timer *te = ev->timer_events;
218                 TALLOC_CTX *tmp_ctx = talloc_new(ev);
219
220                 DEBUG(10, ("Running timed event \"%s\" %p\n",
221                            ev->timer_events->handler_name, ev->timer_events));
222
223                 DLIST_REMOVE(ev->timer_events, te);
224                 talloc_steal(tmp_ctx, te);
225
226                 te->handler(ev, te, now, te->private_data);
227
228                 talloc_free(tmp_ctx);
229                 return true;
230         }
231
232         if (pollrtn <= 0) {
233                 /*
234                  * No fd ready
235                  */
236                 return false;
237         }
238
239         state = (struct tevent_poll_private *)ev->additional_data;
240         pollfd_idx = state->pollfd_idx;
241
242         for (fde = ev->fd_events; fde; fde = fde->next) {
243                 struct pollfd *pfd;
244                 uint16 flags = 0;
245
246                 if (pollfd_idx[fde->fd] >= num_pfds) {
247                         DEBUG(1, ("internal error: pollfd_idx[fde->fd] (%d) "
248                                   ">= num_pfds (%d)\n", pollfd_idx[fde->fd],
249                                   num_pfds));
250                         return false;
251                 }
252                 pfd = &pfds[pollfd_idx[fde->fd]];
253
254                 if (pfd->fd != fde->fd) {
255                         DEBUG(1, ("internal error: pfd->fd (%d) "
256                                   "!= fde->fd (%d)\n", pollfd_idx[fde->fd],
257                                   num_pfds));
258                         return false;
259                 }
260
261                 if (pfd->revents & (POLLHUP|POLLERR)) {
262                         /* If we only wait for EVENT_FD_WRITE, we
263                            should not tell the event handler about it,
264                            and remove the writable flag, as we only
265                            report errors when waiting for read events
266                            to match the select behavior. */
267                         if (!(fde->flags & EVENT_FD_READ)) {
268                                 EVENT_FD_NOT_WRITEABLE(fde);
269                                 continue;
270                         }
271                         flags |= EVENT_FD_READ;
272                 }
273
274                 if (pfd->revents & POLLIN) {
275                         flags |= EVENT_FD_READ;
276                 }
277                 if (pfd->revents & POLLOUT) {
278                         flags |= EVENT_FD_WRITE;
279                 }
280                 if (flags & fde->flags) {
281                         DLIST_DEMOTE(ev->fd_events, fde, struct tevent_fd);
282                         fde->handler(ev, fde, flags, fde->private_data);
283                         return true;
284                 }
285         }
286
287         return false;
288 }
289
290 struct timeval *get_timed_events_timeout(struct tevent_context *ev,
291                                          struct timeval *to_ret)
292 {
293         struct timeval now;
294
295         if ((ev->timer_events == NULL) && (ev->immediate_events == NULL)) {
296                 return NULL;
297         }
298         if (ev->immediate_events != NULL) {
299                 *to_ret = timeval_zero();
300                 return to_ret;
301         }
302
303         now = timeval_current();
304         *to_ret = timeval_until(&now, &ev->timer_events->next_event);
305
306         DEBUG(10, ("timed_events_timeout: %d/%d\n", (int)to_ret->tv_sec,
307                 (int)to_ret->tv_usec));
308
309         return to_ret;
310 }
311
312 static int s3_event_loop_once(struct tevent_context *ev, const char *location)
313 {
314         struct tevent_poll_private *state;
315         int timeout;
316         int num_pfds;
317         int ret;
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         ret = sys_poll(state->pfds, num_pfds, timeout);
338         if (ret == -1 && errno != EINTR) {
339                 tevent_debug(ev, TEVENT_DEBUG_FATAL,
340                              "poll() failed: %d:%s\n",
341                              errno, strerror(errno));
342                 return -1;
343         }
344
345         run_events_poll(ev, ret, state->pfds, num_pfds);
346         return 0;
347 }
348
349 static int s3_event_context_init(struct tevent_context *ev)
350 {
351         return 0;
352 }
353
354 void dump_event_list(struct tevent_context *ev)
355 {
356         struct tevent_timer *te;
357         struct tevent_fd *fe;
358         struct timeval evt, now;
359
360         if (!ev) {
361                 return;
362         }
363
364         now = timeval_current();
365
366         DEBUG(10,("dump_event_list:\n"));
367
368         for (te = ev->timer_events; te; te = te->next) {
369
370                 evt = timeval_until(&now, &te->next_event);
371
372                 DEBUGADD(10,("Timed Event \"%s\" %p handled in %d seconds (at %s)\n",
373                            te->handler_name,
374                            te,
375                            (int)evt.tv_sec,
376                            http_timestring(talloc_tos(), te->next_event.tv_sec)));
377         }
378
379         for (fe = ev->fd_events; fe; fe = fe->next) {
380
381                 DEBUGADD(10,("FD Event %d %p, flags: 0x%04x\n",
382                            fe->fd,
383                            fe,
384                            fe->flags));
385         }
386 }
387
388 static const struct tevent_ops s3_event_ops = {
389         .context_init           = s3_event_context_init,
390         .add_fd                 = tevent_common_add_fd,
391         .set_fd_close_fn        = tevent_common_fd_set_close_fn,
392         .get_fd_flags           = tevent_common_fd_get_flags,
393         .set_fd_flags           = tevent_common_fd_set_flags,
394         .add_timer              = tevent_common_add_timer,
395         .schedule_immediate     = tevent_common_schedule_immediate,
396         .add_signal             = tevent_common_add_signal,
397         .loop_once              = s3_event_loop_once,
398         .loop_wait              = tevent_common_loop_wait,
399 };
400
401 static bool s3_tevent_init(void)
402 {
403         static bool initialized;
404         if (initialized) {
405                 return true;
406         }
407         initialized = tevent_register_backend("s3", &s3_event_ops);
408         tevent_set_default_backend("s3");
409         return initialized;
410 }
411
412 /*
413   this is used to catch debug messages from events
414 */
415 static void s3_event_debug(void *context, enum tevent_debug_level level,
416                            const char *fmt, va_list ap)  PRINTF_ATTRIBUTE(3,0);
417
418 static void s3_event_debug(void *context, enum tevent_debug_level level,
419                            const char *fmt, va_list ap)
420 {
421         int samba_level = -1;
422         char *s = NULL;
423         switch (level) {
424         case TEVENT_DEBUG_FATAL:
425                 samba_level = 0;
426                 break;
427         case TEVENT_DEBUG_ERROR:
428                 samba_level = 1;
429                 break;
430         case TEVENT_DEBUG_WARNING:
431                 samba_level = 2;
432                 break;
433         case TEVENT_DEBUG_TRACE:
434                 samba_level = 11;
435                 break;
436
437         };
438         if (vasprintf(&s, fmt, ap) == -1) {
439                 return;
440         }
441         DEBUG(samba_level, ("s3_event: %s", s));
442         free(s);
443 }
444
445 struct tevent_context *s3_tevent_context_init(TALLOC_CTX *mem_ctx)
446 {
447         struct tevent_context *ev;
448
449         s3_tevent_init();
450
451         ev = tevent_context_init_byname(mem_ctx, "s3");
452         if (ev) {
453                 tevent_set_debug(ev, s3_event_debug, NULL);
454         }
455
456         return ev;
457 }
458