tevent_poll: NULL out fde->event_ctx for "fresh" poll fdes
[nivanova/samba-autobuild/.git] / lib / tevent / tevent_poll.c
1 /*
2    Unix SMB/CIFS implementation.
3    main select loop and event handling
4    Copyright (C) Andrew Tridgell        2003-2005
5    Copyright (C) Stefan Metzmacher      2005-2009
6
7      ** NOTE! The following LGPL license applies to the tevent
8      ** library. This does NOT imply that all of Samba is released
9      ** under the LGPL
10
11    This library is free software; you can redistribute it and/or
12    modify it under the terms of the GNU Lesser General Public
13    License as published by the Free Software Foundation; either
14    version 3 of the License, or (at your option) any later version.
15
16    This library is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19    Lesser General Public License for more details.
20
21    You should have received a copy of the GNU Lesser General Public
22    License along with this library; if not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "replace.h"
26 #include "system/filesys.h"
27 #include "system/select.h"
28 #include "tevent.h"
29 #include "tevent_util.h"
30 #include "tevent_internal.h"
31
32 struct poll_event_context {
33         /* a pointer back to the generic event_context */
34         struct tevent_context *ev;
35
36         /*
37          * A DLIST for fresh fde's added by poll_event_add_fd but not
38          * picked up yet by poll_event_loop_once
39          */
40         struct tevent_fd *fresh;
41
42         /*
43          * These two arrays are maintained together.
44          */
45         struct pollfd *fds;
46         struct tevent_fd **fdes;
47         unsigned num_fds;
48
49         /*
50          * Signal fd to wake the poll() thread
51          */
52         int signal_fd;
53
54         /* information for exiting from the event loop */
55         int exit_code;
56 };
57
58 static int poll_event_context_destructor(struct poll_event_context *poll_ev)
59 {
60         struct tevent_fd *fd, *fn;
61
62         for (fd = poll_ev->fresh; fd; fd = fn) {
63                 fn = fd->next;
64                 fd->event_ctx = NULL;
65                 DLIST_REMOVE(poll_ev->fresh, fd);
66         }
67
68         if (poll_ev->signal_fd == -1) {
69                 /*
70                  * Non-threaded, no signal pipe
71                  */
72                 return 0;
73         }
74
75         close(poll_ev->signal_fd);
76         poll_ev->signal_fd = -1;
77
78         if (poll_ev->num_fds == 0) {
79                 return 0;
80         }
81         if (poll_ev->fds[0].fd != -1) {
82                 close(poll_ev->fds[0].fd);
83                 poll_ev->fds[0].fd = -1;
84         }
85         return 0;
86 }
87
88 /*
89   create a poll_event_context structure.
90 */
91 static int poll_event_context_init(struct tevent_context *ev)
92 {
93         struct poll_event_context *poll_ev;
94
95         poll_ev = talloc_zero(ev, struct poll_event_context);
96         if (poll_ev == NULL) {
97                 return -1;
98         }
99         poll_ev->ev = ev;
100         poll_ev->signal_fd = -1;
101         ev->additional_data = poll_ev;
102         talloc_set_destructor(poll_ev, poll_event_context_destructor);
103         return 0;
104 }
105
106 static bool set_nonblock(int fd)
107 {
108         int val;
109
110         val = fcntl(fd, F_GETFL, 0);
111         if (val == -1) {
112                 return false;
113         }
114         val |= O_NONBLOCK;
115
116         return (fcntl(fd, F_SETFL, val) != -1);
117 }
118
119 static int poll_event_context_init_mt(struct tevent_context *ev)
120 {
121         struct poll_event_context *poll_ev;
122         struct pollfd *pfd;
123         int fds[2];
124         int ret;
125
126         ret = poll_event_context_init(ev);
127         if (ret == -1) {
128                 return ret;
129         }
130
131         poll_ev = talloc_get_type_abort(
132                 ev->additional_data, struct poll_event_context);
133
134         poll_ev->fds = talloc_zero(poll_ev, struct pollfd);
135         if (poll_ev->fds == NULL) {
136                 return -1;
137         }
138
139         ret = pipe(fds);
140         if (ret == -1) {
141                 return -1;
142         }
143
144         if (!set_nonblock(fds[0]) || !set_nonblock(fds[1])) {
145                 close(fds[0]);
146                 close(fds[1]);
147                 return -1;
148         }
149
150         poll_ev->signal_fd = fds[1];
151
152         pfd = &poll_ev->fds[0];
153         pfd->fd = fds[0];
154         pfd->events = (POLLIN|POLLHUP);
155
156         poll_ev->num_fds = 1;
157
158         talloc_set_destructor(poll_ev, poll_event_context_destructor);
159
160         return 0;
161 }
162
163 static void poll_event_wake_pollthread(struct poll_event_context *poll_ev)
164 {
165         char c;
166         ssize_t ret;
167
168         if (poll_ev->signal_fd == -1) {
169                 return;
170         }
171         c = 0;
172         do {
173                 ret = write(poll_ev->signal_fd, &c, sizeof(c));
174         } while ((ret == -1) && (errno == EINTR));
175 }
176
177 static void poll_event_drain_signal_fd(struct poll_event_context *poll_ev)
178 {
179         char buf[16];
180         ssize_t ret;
181         int fd;
182
183         if (poll_ev->signal_fd == -1) {
184                 return;
185         }
186
187         if (poll_ev->num_fds < 1) {
188                 return;
189         }
190         fd = poll_ev->fds[0].fd;
191
192         do {
193                 ret = read(fd, buf, sizeof(buf));
194         } while (ret == sizeof(buf));
195 }
196
197 /*
198   destroy an fd_event
199 */
200 static int poll_event_fd_destructor(struct tevent_fd *fde)
201 {
202         struct tevent_context *ev = fde->event_ctx;
203         struct poll_event_context *poll_ev;
204         uint64_t del_idx = fde->additional_flags;
205
206         if (ev == NULL) {
207                 goto done;
208         }
209
210         poll_ev = talloc_get_type_abort(
211                 ev->additional_data, struct poll_event_context);
212
213         poll_ev->fdes[del_idx] = NULL;
214         poll_event_wake_pollthread(poll_ev);
215 done:
216         return tevent_common_fd_destructor(fde);
217 }
218
219 static int poll_fresh_fde_destructor(struct tevent_fd *fde)
220 {
221         struct poll_event_context *poll_ev = talloc_get_type_abort(
222                 fde->event_ctx->additional_data, struct poll_event_context);
223         DLIST_REMOVE(poll_ev->fresh, fde);
224         return 0;
225 }
226
227 static void poll_event_schedule_immediate(struct tevent_immediate *im,
228                                           struct tevent_context *ev,
229                                           tevent_immediate_handler_t handler,
230                                           void *private_data,
231                                           const char *handler_name,
232                                           const char *location)
233 {
234         struct poll_event_context *poll_ev = talloc_get_type_abort(
235                 ev->additional_data, struct poll_event_context);
236
237         tevent_common_schedule_immediate(im, ev, handler, private_data,
238                                          handler_name, location);
239         poll_event_wake_pollthread(poll_ev);
240 }
241
242 /*
243   add a fd based event
244   return NULL on failure (memory allocation error)
245 */
246 static struct tevent_fd *poll_event_add_fd(struct tevent_context *ev,
247                                            TALLOC_CTX *mem_ctx,
248                                            int fd, uint16_t flags,
249                                            tevent_fd_handler_t handler,
250                                            void *private_data,
251                                            const char *handler_name,
252                                            const char *location)
253 {
254         struct poll_event_context *poll_ev = talloc_get_type_abort(
255                 ev->additional_data, struct poll_event_context);
256         struct tevent_fd *fde;
257
258         if (fd < 0) {
259                 return NULL;
260         }
261
262         fde = talloc(mem_ctx ? mem_ctx : ev, struct tevent_fd);
263         if (fde == NULL) {
264                 return NULL;
265         }
266         fde->event_ctx          = ev;
267         fde->fd                 = fd;
268         fde->flags              = flags;
269         fde->handler            = handler;
270         fde->close_fn           = NULL;
271         fde->private_data       = private_data;
272         fde->handler_name       = handler_name;
273         fde->location           = location;
274         fde->additional_flags   = UINT64_MAX;
275         fde->additional_data    = NULL;
276
277         DLIST_ADD(poll_ev->fresh, fde);
278         talloc_set_destructor(fde, poll_fresh_fde_destructor);
279         poll_event_wake_pollthread(poll_ev);
280
281         /*
282          * poll_event_loop_poll will take care of the rest in
283          * poll_event_setup_fresh
284          */
285         return fde;
286 }
287
288 /*
289   set the fd event flags
290 */
291 static void poll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
292 {
293         struct poll_event_context *poll_ev = talloc_get_type_abort(
294                 fde->event_ctx->additional_data, struct poll_event_context);
295         uint64_t idx = fde->additional_flags;
296         uint16_t pollflags;
297
298         fde->flags = flags;
299
300         if (idx == UINT64_MAX) {
301                 /*
302                  * poll_event_setup_fresh not yet called after this fde was
303                  * added. We don't have to do anything to transfer the changed
304                  * flags to the array passed to poll(2)
305                  */
306                 return;
307         }
308
309         pollflags = 0;
310
311         if (flags & TEVENT_FD_READ) {
312                 pollflags |= (POLLIN|POLLHUP);
313         }
314         if (flags & TEVENT_FD_WRITE) {
315                 pollflags |= (POLLOUT);
316         }
317         poll_ev->fds[idx].events = pollflags;
318
319         poll_event_wake_pollthread(poll_ev);
320 }
321
322 static bool poll_event_setup_fresh(struct tevent_context *ev,
323                                    struct poll_event_context *poll_ev)
324 {
325         struct tevent_fd *fde, *next;
326         unsigned num_fresh, num_fds;
327
328         if (poll_ev->fresh == NULL) {
329                 return true;
330         }
331
332         num_fresh = 0;
333         for (fde = poll_ev->fresh; fde; fde = fde->next) {
334                 num_fresh += 1;
335         }
336         num_fds = poll_ev->num_fds + num_fresh;
337
338         /*
339          * We check the length of fdes here. It is the last one
340          * enlarged, so if the realloc for poll_fd->fdes fails,
341          * poll_fd->fds will have at least the size of poll_fd->fdes
342          */
343
344         if (num_fds >= talloc_array_length(poll_ev->fdes)) {
345                 struct pollfd *tmp_fds;
346                 struct tevent_fd **tmp_fdes;
347                 unsigned array_length;
348
349                 array_length = (num_fds + 15) & ~15; /* round up to 16 */
350
351                 tmp_fds = talloc_realloc(
352                         poll_ev, poll_ev->fds, struct pollfd, array_length);
353                 if (tmp_fds == NULL) {
354                         return false;
355                 }
356                 poll_ev->fds = tmp_fds;
357
358                 tmp_fdes = talloc_realloc(
359                         poll_ev, poll_ev->fdes, struct tevent_fd *,
360                         array_length);
361                 if (tmp_fdes == NULL) {
362                         return false;
363                 }
364                 poll_ev->fdes = tmp_fdes;
365         }
366
367         for (fde = poll_ev->fresh; fde; fde = next) {
368                 struct pollfd *pfd;
369
370                 pfd = &poll_ev->fds[poll_ev->num_fds];
371
372                 pfd->fd = fde->fd;
373                 pfd->events = 0;
374                 pfd->revents = 0;
375
376                 if (fde->flags & TEVENT_FD_READ) {
377                         pfd->events |= (POLLIN|POLLHUP);
378                 }
379                 if (fde->flags & TEVENT_FD_WRITE) {
380                         pfd->events |= (POLLOUT);
381                 }
382
383                 fde->additional_flags = poll_ev->num_fds;
384                 poll_ev->fdes[poll_ev->num_fds] = fde;
385
386                 next = fde->next;
387                 DLIST_REMOVE(poll_ev->fresh, fde);
388                 DLIST_ADD(ev->fd_events, fde);
389
390                 talloc_set_destructor(fde, poll_event_fd_destructor);
391
392                 poll_ev->num_fds += 1;
393         }
394         return true;
395 }
396
397 /*
398   event loop handling using poll()
399 */
400 static int poll_event_loop_poll(struct tevent_context *ev,
401                                 struct timeval *tvalp)
402 {
403         struct poll_event_context *poll_ev = talloc_get_type_abort(
404                 ev->additional_data, struct poll_event_context);
405         int pollrtn;
406         int timeout = -1;
407         unsigned first_fd;
408         unsigned i;
409
410         if (ev->signal_events && tevent_common_check_signal(ev)) {
411                 return 0;
412         }
413
414         if (tvalp != NULL) {
415                 timeout = tvalp->tv_sec * 1000;
416                 timeout += (tvalp->tv_usec + 999) / 1000;
417         }
418
419         poll_event_drain_signal_fd(poll_ev);
420
421         if (!poll_event_setup_fresh(ev, poll_ev)) {
422                 return -1;
423         }
424
425         tevent_trace_point_callback(poll_ev->ev, TEVENT_TRACE_BEFORE_WAIT);
426         pollrtn = poll(poll_ev->fds, poll_ev->num_fds, timeout);
427         tevent_trace_point_callback(poll_ev->ev, TEVENT_TRACE_AFTER_WAIT);
428
429         if (pollrtn == -1 && errno == EINTR && ev->signal_events) {
430                 tevent_common_check_signal(ev);
431                 return 0;
432         }
433
434         if (pollrtn == 0 && tvalp) {
435                 /* we don't care about a possible delay here */
436                 tevent_common_loop_timer_delay(ev);
437                 return 0;
438         }
439
440         if (pollrtn <= 0) {
441                 /*
442                  * No fd's ready
443                  */
444                 return 0;
445         }
446
447         first_fd = (poll_ev->signal_fd != -1) ? 1 : 0;
448
449         /* at least one file descriptor is ready - check
450            which ones and call the handler, being careful to allow
451            the handler to remove itself when called */
452
453         for (i=first_fd; i<poll_ev->num_fds; i++) {
454                 struct pollfd *pfd;
455                 struct tevent_fd *fde;
456                 uint16_t flags = 0;
457
458                 fde = poll_ev->fdes[i];
459                 if (fde == NULL) {
460                         /*
461                          * This fde was talloc_free()'ed. Delete it
462                          * from the arrays
463                          */
464                         poll_ev->num_fds -= 1;
465                         poll_ev->fds[i] = poll_ev->fds[poll_ev->num_fds];
466                         poll_ev->fdes[i] = poll_ev->fdes[poll_ev->num_fds];
467                         if (poll_ev->fdes[i] != NULL) {
468                                 poll_ev->fdes[i]->additional_flags = i;
469                         }
470                         continue;
471                 }
472
473                 pfd = &poll_ev->fds[i];
474
475                 if (pfd->revents & (POLLHUP|POLLERR)) {
476                         /* If we only wait for TEVENT_FD_WRITE, we
477                            should not tell the event handler about it,
478                            and remove the writable flag, as we only
479                            report errors when waiting for read events
480                            to match the select behavior. */
481                         if (!(fde->flags & TEVENT_FD_READ)) {
482                                 TEVENT_FD_NOT_WRITEABLE(fde);
483                                 continue;
484                         }
485                         flags |= TEVENT_FD_READ;
486                 }
487                 if (pfd->revents & POLLIN) {
488                         flags |= TEVENT_FD_READ;
489                 }
490                 if (pfd->revents & POLLOUT) {
491                         flags |= TEVENT_FD_WRITE;
492                 }
493                 if (flags != 0) {
494                         fde->handler(ev, fde, flags, fde->private_data);
495                         break;
496                 }
497         }
498
499         return 0;
500 }
501
502 /*
503   do a single event loop using the events defined in ev
504 */
505 static int poll_event_loop_once(struct tevent_context *ev,
506                                 const char *location)
507 {
508         struct timeval tval;
509
510         if (ev->signal_events &&
511             tevent_common_check_signal(ev)) {
512                 return 0;
513         }
514
515         if (ev->immediate_events &&
516             tevent_common_loop_immediate(ev)) {
517                 return 0;
518         }
519
520         tval = tevent_common_loop_timer_delay(ev);
521         if (tevent_timeval_is_zero(&tval)) {
522                 return 0;
523         }
524
525         return poll_event_loop_poll(ev, &tval);
526 }
527
528 static const struct tevent_ops poll_event_ops = {
529         .context_init           = poll_event_context_init,
530         .add_fd                 = poll_event_add_fd,
531         .set_fd_close_fn        = tevent_common_fd_set_close_fn,
532         .get_fd_flags           = tevent_common_fd_get_flags,
533         .set_fd_flags           = poll_event_set_fd_flags,
534         .add_timer              = tevent_common_add_timer,
535         .schedule_immediate     = tevent_common_schedule_immediate,
536         .add_signal             = tevent_common_add_signal,
537         .loop_once              = poll_event_loop_once,
538         .loop_wait              = tevent_common_loop_wait,
539 };
540
541 _PRIVATE_ bool tevent_poll_init(void)
542 {
543         return tevent_register_backend("poll", &poll_event_ops);
544 }
545
546 static const struct tevent_ops poll_event_mt_ops = {
547         .context_init           = poll_event_context_init_mt,
548         .add_fd                 = poll_event_add_fd,
549         .set_fd_close_fn        = tevent_common_fd_set_close_fn,
550         .get_fd_flags           = tevent_common_fd_get_flags,
551         .set_fd_flags           = poll_event_set_fd_flags,
552         .add_timer              = tevent_common_add_timer,
553         .schedule_immediate     = poll_event_schedule_immediate,
554         .add_signal             = tevent_common_add_signal,
555         .loop_once              = poll_event_loop_once,
556         .loop_wait              = tevent_common_loop_wait,
557 };
558
559 _PRIVATE_ bool tevent_poll_mt_init(void)
560 {
561         return tevent_register_backend("poll_mt", &poll_event_mt_ops);
562 }