tevent: revalidate fde->flags after poll()
[Samba/gebeck_regimport.git] / lib / tevent / tevent_poll.c
blobaa4c50c0c5ec39651d4eea2224d2043ad325ce45
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
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
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.
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.
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/>.
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"
32 struct poll_event_context {
33 /* a pointer back to the generic event_context */
34 struct tevent_context *ev;
37 * A DLIST for fresh fde's added by poll_event_add_fd but not
38 * picked up yet by poll_event_loop_once
40 struct tevent_fd *fresh;
42 * A DLIST for disabled fde's.
44 struct tevent_fd *disabled;
46 * one or more events were deleted or disabled
48 bool deleted;
51 * These two arrays are maintained together.
53 struct pollfd *fds;
54 struct tevent_fd **fdes;
55 unsigned num_fds;
58 * Signal fd to wake the poll() thread
60 int signal_fd;
62 /* information for exiting from the event loop */
63 int exit_code;
66 static int poll_event_context_destructor(struct poll_event_context *poll_ev)
68 struct tevent_fd *fd, *fn;
70 for (fd = poll_ev->fresh; fd; fd = fn) {
71 fn = fd->next;
72 fd->event_ctx = NULL;
73 DLIST_REMOVE(poll_ev->fresh, fd);
76 for (fd = poll_ev->disabled; fd; fd = fn) {
77 fn = fd->next;
78 fd->event_ctx = NULL;
79 DLIST_REMOVE(poll_ev->disabled, fd);
82 if (poll_ev->signal_fd == -1) {
84 * Non-threaded, no signal pipe
86 return 0;
89 close(poll_ev->signal_fd);
90 poll_ev->signal_fd = -1;
92 if (poll_ev->num_fds == 0) {
93 return 0;
95 if (poll_ev->fds[0].fd != -1) {
96 close(poll_ev->fds[0].fd);
97 poll_ev->fds[0].fd = -1;
99 return 0;
103 create a poll_event_context structure.
105 static int poll_event_context_init(struct tevent_context *ev)
107 struct poll_event_context *poll_ev;
110 * we might be called during tevent_re_initialise()
111 * which means we need to free our old additional_data
112 * in order to detach old fd events from the
113 * poll_ev->fresh list
115 TALLOC_FREE(ev->additional_data);
117 poll_ev = talloc_zero(ev, struct poll_event_context);
118 if (poll_ev == NULL) {
119 return -1;
121 poll_ev->ev = ev;
122 poll_ev->signal_fd = -1;
123 ev->additional_data = poll_ev;
124 talloc_set_destructor(poll_ev, poll_event_context_destructor);
125 return 0;
128 static bool set_nonblock(int fd)
130 int val;
132 val = fcntl(fd, F_GETFL, 0);
133 if (val == -1) {
134 return false;
136 val |= O_NONBLOCK;
138 return (fcntl(fd, F_SETFL, val) != -1);
141 static int poll_event_context_init_mt(struct tevent_context *ev)
143 struct poll_event_context *poll_ev;
144 struct pollfd *pfd;
145 int fds[2];
146 int ret;
148 ret = poll_event_context_init(ev);
149 if (ret == -1) {
150 return ret;
153 poll_ev = talloc_get_type_abort(
154 ev->additional_data, struct poll_event_context);
156 poll_ev->fds = talloc_zero(poll_ev, struct pollfd);
157 if (poll_ev->fds == NULL) {
158 return -1;
161 ret = pipe(fds);
162 if (ret == -1) {
163 return -1;
166 if (!set_nonblock(fds[0]) || !set_nonblock(fds[1])) {
167 close(fds[0]);
168 close(fds[1]);
169 return -1;
172 poll_ev->signal_fd = fds[1];
174 pfd = &poll_ev->fds[0];
175 pfd->fd = fds[0];
176 pfd->events = (POLLIN|POLLHUP);
178 poll_ev->num_fds = 1;
180 talloc_set_destructor(poll_ev, poll_event_context_destructor);
182 return 0;
185 static void poll_event_wake_pollthread(struct poll_event_context *poll_ev)
187 char c;
188 ssize_t ret;
190 if (poll_ev->signal_fd == -1) {
191 return;
193 c = 0;
194 do {
195 ret = write(poll_ev->signal_fd, &c, sizeof(c));
196 } while ((ret == -1) && (errno == EINTR));
199 static void poll_event_drain_signal_fd(struct poll_event_context *poll_ev)
201 char buf[16];
202 ssize_t ret;
203 int fd;
205 if (poll_ev->signal_fd == -1) {
206 return;
209 if (poll_ev->num_fds < 1) {
210 return;
212 fd = poll_ev->fds[0].fd;
214 do {
215 ret = read(fd, buf, sizeof(buf));
216 } while (ret == sizeof(buf));
220 destroy an fd_event
222 static int poll_event_fd_destructor(struct tevent_fd *fde)
224 struct tevent_context *ev = fde->event_ctx;
225 struct poll_event_context *poll_ev;
226 uint64_t del_idx = fde->additional_flags;
228 if (ev == NULL) {
229 goto done;
232 poll_ev = talloc_get_type_abort(
233 ev->additional_data, struct poll_event_context);
235 if (del_idx == UINT64_MAX) {
236 struct tevent_fd **listp =
237 (struct tevent_fd **)fde->additional_data;
239 DLIST_REMOVE((*listp), fde);
240 goto done;
243 poll_ev->fdes[del_idx] = NULL;
244 poll_ev->deleted = true;
245 poll_event_wake_pollthread(poll_ev);
246 done:
247 return tevent_common_fd_destructor(fde);
250 static void poll_event_schedule_immediate(struct tevent_immediate *im,
251 struct tevent_context *ev,
252 tevent_immediate_handler_t handler,
253 void *private_data,
254 const char *handler_name,
255 const char *location)
257 struct poll_event_context *poll_ev = talloc_get_type_abort(
258 ev->additional_data, struct poll_event_context);
260 tevent_common_schedule_immediate(im, ev, handler, private_data,
261 handler_name, location);
262 poll_event_wake_pollthread(poll_ev);
266 Private function called by "standard" backend fallback.
267 Note this only allows fallback to "poll" backend, not "poll-mt".
269 _PRIVATE_ void tevent_poll_event_add_fd_internal(struct tevent_context *ev,
270 struct tevent_fd *fde)
272 struct poll_event_context *poll_ev = talloc_get_type_abort(
273 ev->additional_data, struct poll_event_context);
274 struct tevent_fd **listp;
276 if (fde->flags != 0) {
277 listp = &poll_ev->fresh;
278 } else {
279 listp = &poll_ev->disabled;
282 fde->additional_flags = UINT64_MAX;
283 fde->additional_data = listp;
285 DLIST_ADD((*listp), fde);
286 talloc_set_destructor(fde, poll_event_fd_destructor);
290 add a fd based event
291 return NULL on failure (memory allocation error)
293 static struct tevent_fd *poll_event_add_fd(struct tevent_context *ev,
294 TALLOC_CTX *mem_ctx,
295 int fd, uint16_t flags,
296 tevent_fd_handler_t handler,
297 void *private_data,
298 const char *handler_name,
299 const char *location)
301 struct poll_event_context *poll_ev = talloc_get_type_abort(
302 ev->additional_data, struct poll_event_context);
303 struct tevent_fd *fde;
305 if (fd < 0) {
306 return NULL;
309 fde = talloc(mem_ctx ? mem_ctx : ev, struct tevent_fd);
310 if (fde == NULL) {
311 return NULL;
313 fde->event_ctx = ev;
314 fde->fd = fd;
315 fde->flags = flags;
316 fde->handler = handler;
317 fde->close_fn = NULL;
318 fde->private_data = private_data;
319 fde->handler_name = handler_name;
320 fde->location = location;
321 fde->additional_flags = UINT64_MAX;
322 fde->additional_data = NULL;
324 tevent_poll_event_add_fd_internal(ev, fde);
325 poll_event_wake_pollthread(poll_ev);
328 * poll_event_loop_poll will take care of the rest in
329 * poll_event_setup_fresh
331 return fde;
335 set the fd event flags
337 static void poll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
339 struct tevent_context *ev = fde->event_ctx;
340 struct poll_event_context *poll_ev;
341 uint64_t idx = fde->additional_flags;
342 uint16_t pollflags;
344 if (ev == NULL) {
345 return;
347 poll_ev = talloc_get_type_abort(
348 ev->additional_data, struct poll_event_context);
350 fde->flags = flags;
352 if (idx == UINT64_MAX) {
353 struct tevent_fd **listp =
354 (struct tevent_fd **)fde->additional_data;
357 * We move it between the fresh and disabled lists.
359 DLIST_REMOVE((*listp), fde);
360 tevent_poll_event_add_fd_internal(ev, fde);
361 poll_event_wake_pollthread(poll_ev);
362 return;
365 if (fde->flags == 0) {
367 * We need to remove it from the array
368 * and move it to the disabled list.
370 poll_ev->fdes[idx] = NULL;
371 poll_ev->deleted = true;
372 DLIST_REMOVE(ev->fd_events, fde);
373 tevent_poll_event_add_fd_internal(ev, fde);
374 poll_event_wake_pollthread(poll_ev);
375 return;
378 pollflags = 0;
380 if (flags & TEVENT_FD_READ) {
381 pollflags |= (POLLIN|POLLHUP);
383 if (flags & TEVENT_FD_WRITE) {
384 pollflags |= (POLLOUT);
386 poll_ev->fds[idx].events = pollflags;
388 poll_event_wake_pollthread(poll_ev);
391 static bool poll_event_setup_fresh(struct tevent_context *ev,
392 struct poll_event_context *poll_ev)
394 struct tevent_fd *fde, *next;
395 unsigned num_fresh, num_fds;
397 if (poll_ev->deleted) {
398 unsigned first_fd = (poll_ev->signal_fd != -1) ? 1 : 0;
399 unsigned i;
401 for (i=first_fd; i < poll_ev->num_fds;) {
402 fde = poll_ev->fdes[i];
403 if (fde != NULL) {
404 i++;
405 continue;
409 * This fde was talloc_free()'ed. Delete it
410 * from the arrays
412 poll_ev->num_fds -= 1;
413 if (poll_ev->num_fds == i) {
414 break;
416 poll_ev->fds[i] = poll_ev->fds[poll_ev->num_fds];
417 poll_ev->fdes[i] = poll_ev->fdes[poll_ev->num_fds];
418 if (poll_ev->fdes[i] != NULL) {
419 poll_ev->fdes[i]->additional_flags = i;
423 poll_ev->deleted = false;
425 if (poll_ev->fresh == NULL) {
426 return true;
429 num_fresh = 0;
430 for (fde = poll_ev->fresh; fde; fde = fde->next) {
431 num_fresh += 1;
433 num_fds = poll_ev->num_fds + num_fresh;
436 * We check the length of fdes here. It is the last one
437 * enlarged, so if the realloc for poll_fd->fdes fails,
438 * poll_fd->fds will have at least the size of poll_fd->fdes
441 if (num_fds >= talloc_array_length(poll_ev->fdes)) {
442 struct pollfd *tmp_fds;
443 struct tevent_fd **tmp_fdes;
444 unsigned array_length;
446 array_length = (num_fds + 15) & ~15; /* round up to 16 */
448 tmp_fds = talloc_realloc(
449 poll_ev, poll_ev->fds, struct pollfd, array_length);
450 if (tmp_fds == NULL) {
451 return false;
453 poll_ev->fds = tmp_fds;
455 tmp_fdes = talloc_realloc(
456 poll_ev, poll_ev->fdes, struct tevent_fd *,
457 array_length);
458 if (tmp_fdes == NULL) {
459 return false;
461 poll_ev->fdes = tmp_fdes;
464 for (fde = poll_ev->fresh; fde; fde = next) {
465 struct pollfd *pfd;
467 pfd = &poll_ev->fds[poll_ev->num_fds];
469 pfd->fd = fde->fd;
470 pfd->events = 0;
471 pfd->revents = 0;
473 if (fde->flags & TEVENT_FD_READ) {
474 pfd->events |= (POLLIN|POLLHUP);
476 if (fde->flags & TEVENT_FD_WRITE) {
477 pfd->events |= (POLLOUT);
480 fde->additional_flags = poll_ev->num_fds;
481 poll_ev->fdes[poll_ev->num_fds] = fde;
483 next = fde->next;
484 DLIST_REMOVE(poll_ev->fresh, fde);
485 DLIST_ADD(ev->fd_events, fde);
487 poll_ev->num_fds += 1;
489 return true;
493 event loop handling using poll()
495 static int poll_event_loop_poll(struct tevent_context *ev,
496 struct timeval *tvalp)
498 struct poll_event_context *poll_ev = talloc_get_type_abort(
499 ev->additional_data, struct poll_event_context);
500 int pollrtn;
501 int timeout = -1;
502 int poll_errno;
503 struct tevent_fd *fde = NULL;
504 unsigned i;
506 if (ev->signal_events && tevent_common_check_signal(ev)) {
507 return 0;
510 if (tvalp != NULL) {
511 timeout = tvalp->tv_sec * 1000;
512 timeout += (tvalp->tv_usec + 999) / 1000;
515 poll_event_drain_signal_fd(poll_ev);
517 if (!poll_event_setup_fresh(ev, poll_ev)) {
518 return -1;
521 tevent_trace_point_callback(poll_ev->ev, TEVENT_TRACE_BEFORE_WAIT);
522 pollrtn = poll(poll_ev->fds, poll_ev->num_fds, timeout);
523 poll_errno = errno;
524 tevent_trace_point_callback(poll_ev->ev, TEVENT_TRACE_AFTER_WAIT);
526 if (pollrtn == -1 && poll_errno == EINTR && ev->signal_events) {
527 tevent_common_check_signal(ev);
528 return 0;
531 if (pollrtn == 0 && tvalp) {
532 /* we don't care about a possible delay here */
533 tevent_common_loop_timer_delay(ev);
534 return 0;
537 if (pollrtn <= 0) {
539 * No fd's ready
541 return 0;
544 /* at least one file descriptor is ready - check
545 which ones and call the handler, being careful to allow
546 the handler to remove itself when called */
548 for (fde = ev->fd_events; fde; fde = fde->next) {
549 unsigned idx = fde->additional_flags;
550 struct pollfd *pfd;
551 uint16_t flags = 0;
553 if (idx == UINT64_MAX) {
554 continue;
557 pfd = &poll_ev->fds[idx];
559 if (pfd->revents & POLLNVAL) {
561 * the socket is dead! this should never
562 * happen as the socket should have first been
563 * made readable and that should have removed
564 * the event, so this must be a bug.
566 * We ignore it here to match the epoll
567 * behavior.
569 tevent_debug(ev, TEVENT_DEBUG_ERROR,
570 "POLLNVAL on fde[%p] fd[%d] - disabling\n",
571 fde, pfd->fd);
572 poll_ev->fdes[idx] = NULL;
573 poll_ev->deleted = true;
574 DLIST_REMOVE(ev->fd_events, fde);
575 fde->event_ctx = NULL;
576 continue;
579 if (pfd->revents & (POLLHUP|POLLERR)) {
580 /* If we only wait for TEVENT_FD_WRITE, we
581 should not tell the event handler about it,
582 and remove the writable flag, as we only
583 report errors when waiting for read events
584 to match the select behavior. */
585 if (!(fde->flags & TEVENT_FD_READ)) {
586 TEVENT_FD_NOT_WRITEABLE(fde);
587 continue;
589 flags |= TEVENT_FD_READ;
591 if (pfd->revents & POLLIN) {
592 flags |= TEVENT_FD_READ;
594 if (pfd->revents & POLLOUT) {
595 flags |= TEVENT_FD_WRITE;
598 * Note that fde->flags could be changed when using
599 * the poll_mt backend together with threads,
600 * that why we need to check pfd->revents and fde->flags
602 flags &= fde->flags;
603 if (flags != 0) {
604 fde->handler(ev, fde, flags, fde->private_data);
605 return 0;
609 for (i = 0; i < poll_ev->num_fds; i++) {
610 if (poll_ev->fds[i].revents & POLLNVAL) {
612 * the socket is dead! this should never
613 * happen as the socket should have first been
614 * made readable and that should have removed
615 * the event, so this must be a bug or
616 * a race in the poll_mt usage.
618 fde = poll_ev->fdes[i];
619 tevent_debug(ev, TEVENT_DEBUG_WARNING,
620 "POLLNVAL on dangling fd[%d] fde[%p] - disabling\n",
621 poll_ev->fds[i].fd, fde);
622 poll_ev->fdes[i] = NULL;
623 poll_ev->deleted = true;
624 if (fde != NULL) {
625 DLIST_REMOVE(ev->fd_events, fde);
626 fde->event_ctx = NULL;
631 return 0;
635 do a single event loop using the events defined in ev
637 static int poll_event_loop_once(struct tevent_context *ev,
638 const char *location)
640 struct timeval tval;
642 if (ev->signal_events &&
643 tevent_common_check_signal(ev)) {
644 return 0;
647 if (ev->immediate_events &&
648 tevent_common_loop_immediate(ev)) {
649 return 0;
652 tval = tevent_common_loop_timer_delay(ev);
653 if (tevent_timeval_is_zero(&tval)) {
654 return 0;
657 return poll_event_loop_poll(ev, &tval);
660 static int poll_event_loop_wait(struct tevent_context *ev,
661 const char *location)
663 struct poll_event_context *poll_ev = talloc_get_type_abort(
664 ev->additional_data, struct poll_event_context);
667 * loop as long as we have events pending
669 while (ev->fd_events ||
670 ev->timer_events ||
671 ev->immediate_events ||
672 ev->signal_events ||
673 poll_ev->fresh ||
674 poll_ev->disabled) {
675 int ret;
676 ret = _tevent_loop_once(ev, location);
677 if (ret != 0) {
678 tevent_debug(ev, TEVENT_DEBUG_FATAL,
679 "_tevent_loop_once() failed: %d - %s\n",
680 ret, strerror(errno));
681 return ret;
685 tevent_debug(ev, TEVENT_DEBUG_WARNING,
686 "poll_event_loop_wait() out of events\n");
687 return 0;
690 static const struct tevent_ops poll_event_ops = {
691 .context_init = poll_event_context_init,
692 .add_fd = poll_event_add_fd,
693 .set_fd_close_fn = tevent_common_fd_set_close_fn,
694 .get_fd_flags = tevent_common_fd_get_flags,
695 .set_fd_flags = poll_event_set_fd_flags,
696 .add_timer = tevent_common_add_timer,
697 .schedule_immediate = tevent_common_schedule_immediate,
698 .add_signal = tevent_common_add_signal,
699 .loop_once = poll_event_loop_once,
700 .loop_wait = poll_event_loop_wait,
703 _PRIVATE_ bool tevent_poll_init(void)
705 return tevent_register_backend("poll", &poll_event_ops);
708 static const struct tevent_ops poll_event_mt_ops = {
709 .context_init = poll_event_context_init_mt,
710 .add_fd = poll_event_add_fd,
711 .set_fd_close_fn = tevent_common_fd_set_close_fn,
712 .get_fd_flags = tevent_common_fd_get_flags,
713 .set_fd_flags = poll_event_set_fd_flags,
714 .add_timer = tevent_common_add_timer,
715 .schedule_immediate = poll_event_schedule_immediate,
716 .add_signal = tevent_common_add_signal,
717 .loop_once = poll_event_loop_once,
718 .loop_wait = poll_event_loop_wait,
721 _PRIVATE_ bool tevent_poll_mt_init(void)
723 return tevent_register_backend("poll_mt", &poll_event_mt_ops);