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
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/>.
26 #include "system/filesys.h"
27 #include "system/select.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;
43 * These two arrays are maintained together.
46 struct tevent_fd **fdes;
50 * Signal fd to wake the poll() thread
54 /* information for exiting from the event loop */
58 static int poll_event_context_destructor(struct poll_event_context *poll_ev)
60 struct tevent_fd *fd, *fn;
62 for (fd = poll_ev->fresh; fd; fd = fn) {
65 DLIST_REMOVE(poll_ev->fresh, fd);
68 if (poll_ev->signal_fd == -1) {
70 * Non-threaded, no signal pipe
75 close(poll_ev->signal_fd);
76 poll_ev->signal_fd = -1;
78 if (poll_ev->num_fds == 0) {
81 if (poll_ev->fds[0].fd != -1) {
82 close(poll_ev->fds[0].fd);
83 poll_ev->fds[0].fd = -1;
89 create a poll_event_context structure.
91 static int poll_event_context_init(struct tevent_context *ev)
93 struct poll_event_context *poll_ev;
95 poll_ev = talloc_zero(ev, struct poll_event_context);
96 if (poll_ev == NULL) {
100 poll_ev->signal_fd = -1;
101 ev->additional_data = poll_ev;
102 talloc_set_destructor(poll_ev, poll_event_context_destructor);
106 static bool set_nonblock(int fd)
110 val = fcntl(fd, F_GETFL, 0);
116 return (fcntl(fd, F_SETFL, val) != -1);
119 static int poll_event_context_init_mt(struct tevent_context *ev)
121 struct poll_event_context *poll_ev;
126 ret = poll_event_context_init(ev);
131 poll_ev = talloc_get_type_abort(
132 ev->additional_data, struct poll_event_context);
134 poll_ev->fds = talloc_zero(poll_ev, struct pollfd);
135 if (poll_ev->fds == NULL) {
144 if (!set_nonblock(fds[0]) || !set_nonblock(fds[1])) {
150 poll_ev->signal_fd = fds[1];
152 pfd = &poll_ev->fds[0];
154 pfd->events = (POLLIN|POLLHUP);
156 poll_ev->num_fds = 1;
158 talloc_set_destructor(poll_ev, poll_event_context_destructor);
163 static void poll_event_wake_pollthread(struct poll_event_context *poll_ev)
168 if (poll_ev->signal_fd == -1) {
173 ret = write(poll_ev->signal_fd, &c, sizeof(c));
174 } while ((ret == -1) && (errno == EINTR));
177 static void poll_event_drain_signal_fd(struct poll_event_context *poll_ev)
183 if (poll_ev->signal_fd == -1) {
187 if (poll_ev->num_fds < 1) {
190 fd = poll_ev->fds[0].fd;
193 ret = read(fd, buf, sizeof(buf));
194 } while (ret == sizeof(buf));
200 static int poll_event_fd_destructor(struct tevent_fd *fde)
202 struct tevent_context *ev = fde->event_ctx;
203 struct poll_event_context *poll_ev;
204 uint64_t del_idx = fde->additional_flags;
210 poll_ev = talloc_get_type_abort(
211 ev->additional_data, struct poll_event_context);
213 poll_ev->fdes[del_idx] = NULL;
214 poll_event_wake_pollthread(poll_ev);
216 return tevent_common_fd_destructor(fde);
219 static int poll_fresh_fde_destructor(struct tevent_fd *fde)
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);
227 static void poll_event_schedule_immediate(struct tevent_immediate *im,
228 struct tevent_context *ev,
229 tevent_immediate_handler_t handler,
231 const char *handler_name,
232 const char *location)
234 struct poll_event_context *poll_ev = talloc_get_type_abort(
235 ev->additional_data, struct poll_event_context);
237 tevent_common_schedule_immediate(im, ev, handler, private_data,
238 handler_name, location);
239 poll_event_wake_pollthread(poll_ev);
244 return NULL on failure (memory allocation error)
246 static struct tevent_fd *poll_event_add_fd(struct tevent_context *ev,
248 int fd, uint16_t flags,
249 tevent_fd_handler_t handler,
251 const char *handler_name,
252 const char *location)
254 struct poll_event_context *poll_ev = talloc_get_type_abort(
255 ev->additional_data, struct poll_event_context);
256 struct tevent_fd *fde;
262 fde = talloc(mem_ctx ? mem_ctx : ev, struct tevent_fd);
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;
277 DLIST_ADD(poll_ev->fresh, fde);
278 talloc_set_destructor(fde, poll_fresh_fde_destructor);
279 poll_event_wake_pollthread(poll_ev);
282 * poll_event_loop_poll will take care of the rest in
283 * poll_event_setup_fresh
289 set the fd event flags
291 static void poll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
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;
300 if (idx == UINT64_MAX) {
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)
311 if (flags & TEVENT_FD_READ) {
312 pollflags |= (POLLIN|POLLHUP);
314 if (flags & TEVENT_FD_WRITE) {
315 pollflags |= (POLLOUT);
317 poll_ev->fds[idx].events = pollflags;
319 poll_event_wake_pollthread(poll_ev);
322 static bool poll_event_setup_fresh(struct tevent_context *ev,
323 struct poll_event_context *poll_ev)
325 struct tevent_fd *fde, *next;
326 unsigned num_fresh, num_fds;
328 if (poll_ev->fresh == NULL) {
333 for (fde = poll_ev->fresh; fde; fde = fde->next) {
336 num_fds = poll_ev->num_fds + num_fresh;
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
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;
349 array_length = (num_fds + 15) & ~15; /* round up to 16 */
351 tmp_fds = talloc_realloc(
352 poll_ev, poll_ev->fds, struct pollfd, array_length);
353 if (tmp_fds == NULL) {
356 poll_ev->fds = tmp_fds;
358 tmp_fdes = talloc_realloc(
359 poll_ev, poll_ev->fdes, struct tevent_fd *,
361 if (tmp_fdes == NULL) {
364 poll_ev->fdes = tmp_fdes;
367 for (fde = poll_ev->fresh; fde; fde = next) {
370 pfd = &poll_ev->fds[poll_ev->num_fds];
376 if (fde->flags & TEVENT_FD_READ) {
377 pfd->events |= (POLLIN|POLLHUP);
379 if (fde->flags & TEVENT_FD_WRITE) {
380 pfd->events |= (POLLOUT);
383 fde->additional_flags = poll_ev->num_fds;
384 poll_ev->fdes[poll_ev->num_fds] = fde;
387 DLIST_REMOVE(poll_ev->fresh, fde);
388 DLIST_ADD(ev->fd_events, fde);
390 talloc_set_destructor(fde, poll_event_fd_destructor);
392 poll_ev->num_fds += 1;
398 event loop handling using poll()
400 static int poll_event_loop_poll(struct tevent_context *ev,
401 struct timeval *tvalp)
403 struct poll_event_context *poll_ev = talloc_get_type_abort(
404 ev->additional_data, struct poll_event_context);
410 if (ev->signal_events && tevent_common_check_signal(ev)) {
415 timeout = tvalp->tv_sec * 1000;
416 timeout += (tvalp->tv_usec + 999) / 1000;
419 poll_event_drain_signal_fd(poll_ev);
421 if (!poll_event_setup_fresh(ev, poll_ev)) {
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);
429 if (pollrtn == -1 && errno == EINTR && ev->signal_events) {
430 tevent_common_check_signal(ev);
434 if (pollrtn == 0 && tvalp) {
435 /* we don't care about a possible delay here */
436 tevent_common_loop_timer_delay(ev);
447 first_fd = (poll_ev->signal_fd != -1) ? 1 : 0;
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 */
453 for (i=first_fd; i<poll_ev->num_fds; i++) {
455 struct tevent_fd *fde;
458 fde = poll_ev->fdes[i];
461 * This fde was talloc_free()'ed. Delete it
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;
473 pfd = &poll_ev->fds[i];
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);
485 flags |= TEVENT_FD_READ;
487 if (pfd->revents & POLLIN) {
488 flags |= TEVENT_FD_READ;
490 if (pfd->revents & POLLOUT) {
491 flags |= TEVENT_FD_WRITE;
494 fde->handler(ev, fde, flags, fde->private_data);
503 do a single event loop using the events defined in ev
505 static int poll_event_loop_once(struct tevent_context *ev,
506 const char *location)
510 if (ev->signal_events &&
511 tevent_common_check_signal(ev)) {
515 if (ev->immediate_events &&
516 tevent_common_loop_immediate(ev)) {
520 tval = tevent_common_loop_timer_delay(ev);
521 if (tevent_timeval_is_zero(&tval)) {
525 return poll_event_loop_poll(ev, &tval);
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,
541 _PRIVATE_ bool tevent_poll_init(void)
543 return tevent_register_backend("poll", &poll_event_ops);
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,
559 _PRIVATE_ bool tevent_poll_mt_init(void)
561 return tevent_register_backend("poll_mt", &poll_event_mt_ops);