tevent_poll: call tevent_common_fd_destructor() from poll_fresh_fde_destructor()
[Samba/gebeck_regimport.git] / lib / tevent / tevent_poll.c
blobb8221a44ceaeb89682f8b9be675f72f9a6dcf963
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;
43 * These two arrays are maintained together.
45 struct pollfd *fds;
46 struct tevent_fd **fdes;
47 unsigned num_fds;
50 * Signal fd to wake the poll() thread
52 int signal_fd;
54 /* information for exiting from the event loop */
55 int exit_code;
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) {
63 fn = fd->next;
64 fd->event_ctx = NULL;
65 DLIST_REMOVE(poll_ev->fresh, fd);
68 if (poll_ev->signal_fd == -1) {
70 * Non-threaded, no signal pipe
72 return 0;
75 close(poll_ev->signal_fd);
76 poll_ev->signal_fd = -1;
78 if (poll_ev->num_fds == 0) {
79 return 0;
81 if (poll_ev->fds[0].fd != -1) {
82 close(poll_ev->fds[0].fd);
83 poll_ev->fds[0].fd = -1;
85 return 0;
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) {
97 return -1;
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;
106 static bool set_nonblock(int fd)
108 int val;
110 val = fcntl(fd, F_GETFL, 0);
111 if (val == -1) {
112 return false;
114 val |= O_NONBLOCK;
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;
122 struct pollfd *pfd;
123 int fds[2];
124 int ret;
126 ret = poll_event_context_init(ev);
127 if (ret == -1) {
128 return ret;
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) {
136 return -1;
139 ret = pipe(fds);
140 if (ret == -1) {
141 return -1;
144 if (!set_nonblock(fds[0]) || !set_nonblock(fds[1])) {
145 close(fds[0]);
146 close(fds[1]);
147 return -1;
150 poll_ev->signal_fd = fds[1];
152 pfd = &poll_ev->fds[0];
153 pfd->fd = fds[0];
154 pfd->events = (POLLIN|POLLHUP);
156 poll_ev->num_fds = 1;
158 talloc_set_destructor(poll_ev, poll_event_context_destructor);
160 return 0;
163 static void poll_event_wake_pollthread(struct poll_event_context *poll_ev)
165 char c;
166 ssize_t ret;
168 if (poll_ev->signal_fd == -1) {
169 return;
171 c = 0;
172 do {
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)
179 char buf[16];
180 ssize_t ret;
181 int fd;
183 if (poll_ev->signal_fd == -1) {
184 return;
187 if (poll_ev->num_fds < 1) {
188 return;
190 fd = poll_ev->fds[0].fd;
192 do {
193 ret = read(fd, buf, sizeof(buf));
194 } while (ret == sizeof(buf));
198 destroy an fd_event
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;
206 if (ev == NULL) {
207 goto done;
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);
215 done:
216 return tevent_common_fd_destructor(fde);
219 static int poll_fresh_fde_destructor(struct tevent_fd *fde)
221 struct tevent_context *ev = fde->event_ctx;
222 struct poll_event_context *poll_ev;
224 if (ev == NULL) {
225 goto done;
227 poll_ev = talloc_get_type_abort(
228 ev->additional_data, struct poll_event_context);
230 DLIST_REMOVE(poll_ev->fresh, fde);
231 done:
232 return tevent_common_fd_destructor(fde);
235 static void poll_event_schedule_immediate(struct tevent_immediate *im,
236 struct tevent_context *ev,
237 tevent_immediate_handler_t handler,
238 void *private_data,
239 const char *handler_name,
240 const char *location)
242 struct poll_event_context *poll_ev = talloc_get_type_abort(
243 ev->additional_data, struct poll_event_context);
245 tevent_common_schedule_immediate(im, ev, handler, private_data,
246 handler_name, location);
247 poll_event_wake_pollthread(poll_ev);
251 add a fd based event
252 return NULL on failure (memory allocation error)
254 static struct tevent_fd *poll_event_add_fd(struct tevent_context *ev,
255 TALLOC_CTX *mem_ctx,
256 int fd, uint16_t flags,
257 tevent_fd_handler_t handler,
258 void *private_data,
259 const char *handler_name,
260 const char *location)
262 struct poll_event_context *poll_ev = talloc_get_type_abort(
263 ev->additional_data, struct poll_event_context);
264 struct tevent_fd *fde;
266 if (fd < 0) {
267 return NULL;
270 fde = talloc(mem_ctx ? mem_ctx : ev, struct tevent_fd);
271 if (fde == NULL) {
272 return NULL;
274 fde->event_ctx = ev;
275 fde->fd = fd;
276 fde->flags = flags;
277 fde->handler = handler;
278 fde->close_fn = NULL;
279 fde->private_data = private_data;
280 fde->handler_name = handler_name;
281 fde->location = location;
282 fde->additional_flags = UINT64_MAX;
283 fde->additional_data = NULL;
285 DLIST_ADD(poll_ev->fresh, fde);
286 talloc_set_destructor(fde, poll_fresh_fde_destructor);
287 poll_event_wake_pollthread(poll_ev);
290 * poll_event_loop_poll will take care of the rest in
291 * poll_event_setup_fresh
293 return fde;
297 set the fd event flags
299 static void poll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
301 struct tevent_context *ev = fde->event_ctx;
302 struct poll_event_context *poll_ev;
303 uint64_t idx = fde->additional_flags;
304 uint16_t pollflags;
306 if (ev == NULL) {
307 return;
309 poll_ev = talloc_get_type_abort(
310 ev->additional_data, struct poll_event_context);
312 fde->flags = flags;
314 if (idx == UINT64_MAX) {
316 * poll_event_setup_fresh not yet called after this fde was
317 * added. We don't have to do anything to transfer the changed
318 * flags to the array passed to poll(2)
320 return;
323 pollflags = 0;
325 if (flags & TEVENT_FD_READ) {
326 pollflags |= (POLLIN|POLLHUP);
328 if (flags & TEVENT_FD_WRITE) {
329 pollflags |= (POLLOUT);
331 poll_ev->fds[idx].events = pollflags;
333 poll_event_wake_pollthread(poll_ev);
336 static bool poll_event_setup_fresh(struct tevent_context *ev,
337 struct poll_event_context *poll_ev)
339 struct tevent_fd *fde, *next;
340 unsigned num_fresh, num_fds;
342 if (poll_ev->fresh == NULL) {
343 return true;
346 num_fresh = 0;
347 for (fde = poll_ev->fresh; fde; fde = fde->next) {
348 num_fresh += 1;
350 num_fds = poll_ev->num_fds + num_fresh;
353 * We check the length of fdes here. It is the last one
354 * enlarged, so if the realloc for poll_fd->fdes fails,
355 * poll_fd->fds will have at least the size of poll_fd->fdes
358 if (num_fds >= talloc_array_length(poll_ev->fdes)) {
359 struct pollfd *tmp_fds;
360 struct tevent_fd **tmp_fdes;
361 unsigned array_length;
363 array_length = (num_fds + 15) & ~15; /* round up to 16 */
365 tmp_fds = talloc_realloc(
366 poll_ev, poll_ev->fds, struct pollfd, array_length);
367 if (tmp_fds == NULL) {
368 return false;
370 poll_ev->fds = tmp_fds;
372 tmp_fdes = talloc_realloc(
373 poll_ev, poll_ev->fdes, struct tevent_fd *,
374 array_length);
375 if (tmp_fdes == NULL) {
376 return false;
378 poll_ev->fdes = tmp_fdes;
381 for (fde = poll_ev->fresh; fde; fde = next) {
382 struct pollfd *pfd;
384 pfd = &poll_ev->fds[poll_ev->num_fds];
386 pfd->fd = fde->fd;
387 pfd->events = 0;
388 pfd->revents = 0;
390 if (fde->flags & TEVENT_FD_READ) {
391 pfd->events |= (POLLIN|POLLHUP);
393 if (fde->flags & TEVENT_FD_WRITE) {
394 pfd->events |= (POLLOUT);
397 fde->additional_flags = poll_ev->num_fds;
398 poll_ev->fdes[poll_ev->num_fds] = fde;
400 next = fde->next;
401 DLIST_REMOVE(poll_ev->fresh, fde);
402 DLIST_ADD(ev->fd_events, fde);
404 talloc_set_destructor(fde, poll_event_fd_destructor);
406 poll_ev->num_fds += 1;
408 return true;
412 event loop handling using poll()
414 static int poll_event_loop_poll(struct tevent_context *ev,
415 struct timeval *tvalp)
417 struct poll_event_context *poll_ev = talloc_get_type_abort(
418 ev->additional_data, struct poll_event_context);
419 int pollrtn;
420 int timeout = -1;
421 unsigned first_fd;
422 unsigned i;
424 if (ev->signal_events && tevent_common_check_signal(ev)) {
425 return 0;
428 if (tvalp != NULL) {
429 timeout = tvalp->tv_sec * 1000;
430 timeout += (tvalp->tv_usec + 999) / 1000;
433 poll_event_drain_signal_fd(poll_ev);
435 if (!poll_event_setup_fresh(ev, poll_ev)) {
436 return -1;
439 tevent_trace_point_callback(poll_ev->ev, TEVENT_TRACE_BEFORE_WAIT);
440 pollrtn = poll(poll_ev->fds, poll_ev->num_fds, timeout);
441 tevent_trace_point_callback(poll_ev->ev, TEVENT_TRACE_AFTER_WAIT);
443 if (pollrtn == -1 && errno == EINTR && ev->signal_events) {
444 tevent_common_check_signal(ev);
445 return 0;
448 if (pollrtn == 0 && tvalp) {
449 /* we don't care about a possible delay here */
450 tevent_common_loop_timer_delay(ev);
451 return 0;
454 if (pollrtn <= 0) {
456 * No fd's ready
458 return 0;
461 first_fd = (poll_ev->signal_fd != -1) ? 1 : 0;
463 /* at least one file descriptor is ready - check
464 which ones and call the handler, being careful to allow
465 the handler to remove itself when called */
467 for (i=first_fd; i<poll_ev->num_fds; i++) {
468 struct pollfd *pfd;
469 struct tevent_fd *fde;
470 uint16_t flags = 0;
472 fde = poll_ev->fdes[i];
473 if (fde == NULL) {
475 * This fde was talloc_free()'ed. Delete it
476 * from the arrays
478 poll_ev->num_fds -= 1;
479 poll_ev->fds[i] = poll_ev->fds[poll_ev->num_fds];
480 poll_ev->fdes[i] = poll_ev->fdes[poll_ev->num_fds];
481 if (poll_ev->fdes[i] != NULL) {
482 poll_ev->fdes[i]->additional_flags = i;
484 continue;
487 pfd = &poll_ev->fds[i];
489 if (pfd->revents & (POLLHUP|POLLERR)) {
490 /* If we only wait for TEVENT_FD_WRITE, we
491 should not tell the event handler about it,
492 and remove the writable flag, as we only
493 report errors when waiting for read events
494 to match the select behavior. */
495 if (!(fde->flags & TEVENT_FD_READ)) {
496 TEVENT_FD_NOT_WRITEABLE(fde);
497 continue;
499 flags |= TEVENT_FD_READ;
501 if (pfd->revents & POLLIN) {
502 flags |= TEVENT_FD_READ;
504 if (pfd->revents & POLLOUT) {
505 flags |= TEVENT_FD_WRITE;
507 if (flags != 0) {
508 fde->handler(ev, fde, flags, fde->private_data);
509 break;
513 return 0;
517 do a single event loop using the events defined in ev
519 static int poll_event_loop_once(struct tevent_context *ev,
520 const char *location)
522 struct timeval tval;
524 if (ev->signal_events &&
525 tevent_common_check_signal(ev)) {
526 return 0;
529 if (ev->immediate_events &&
530 tevent_common_loop_immediate(ev)) {
531 return 0;
534 tval = tevent_common_loop_timer_delay(ev);
535 if (tevent_timeval_is_zero(&tval)) {
536 return 0;
539 return poll_event_loop_poll(ev, &tval);
542 static const struct tevent_ops poll_event_ops = {
543 .context_init = poll_event_context_init,
544 .add_fd = poll_event_add_fd,
545 .set_fd_close_fn = tevent_common_fd_set_close_fn,
546 .get_fd_flags = tevent_common_fd_get_flags,
547 .set_fd_flags = poll_event_set_fd_flags,
548 .add_timer = tevent_common_add_timer,
549 .schedule_immediate = tevent_common_schedule_immediate,
550 .add_signal = tevent_common_add_signal,
551 .loop_once = poll_event_loop_once,
552 .loop_wait = tevent_common_loop_wait,
555 _PRIVATE_ bool tevent_poll_init(void)
557 return tevent_register_backend("poll", &poll_event_ops);
560 static const struct tevent_ops poll_event_mt_ops = {
561 .context_init = poll_event_context_init_mt,
562 .add_fd = poll_event_add_fd,
563 .set_fd_close_fn = tevent_common_fd_set_close_fn,
564 .get_fd_flags = tevent_common_fd_get_flags,
565 .set_fd_flags = poll_event_set_fd_flags,
566 .add_timer = tevent_common_add_timer,
567 .schedule_immediate = poll_event_schedule_immediate,
568 .add_signal = tevent_common_add_signal,
569 .loop_once = poll_event_loop_once,
570 .loop_wait = tevent_common_loop_wait,
573 _PRIVATE_ bool tevent_poll_mt_init(void)
575 return tevent_register_backend("poll_mt", &poll_event_mt_ops);