Line data Source code
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 : * one or more events were deleted or disabled
38 : */
39 : bool deleted;
40 :
41 : /*
42 : * These two arrays are maintained together.
43 : *
44 : * The following is always true:
45 : * num_fds <= num_fdes
46 : *
47 : * new 'fresh' elements are added at the end
48 : * of the 'fdes' array and picked up later
49 : * to the 'fds' array in poll_event_sync_arrays()
50 : * before the poll() syscall.
51 : */
52 : struct pollfd *fds;
53 : size_t num_fds;
54 : struct tevent_fd **fdes;
55 : size_t num_fdes;
56 :
57 : /*
58 : * use tevent_common_wakeup(ev) to wake the poll() thread
59 : */
60 : bool use_mt_mode;
61 : };
62 :
63 : /*
64 : create a poll_event_context structure.
65 : */
66 7 : static int poll_event_context_init(struct tevent_context *ev)
67 : {
68 : struct poll_event_context *poll_ev;
69 :
70 : /*
71 : * we might be called during tevent_re_initialise()
72 : * which means we need to free our old additional_data
73 : * in order to detach old fd events from the
74 : * poll_ev->fresh list
75 : */
76 7 : TALLOC_FREE(ev->additional_data);
77 :
78 7 : poll_ev = talloc_zero(ev, struct poll_event_context);
79 7 : if (poll_ev == NULL) {
80 0 : return -1;
81 : }
82 7 : poll_ev->ev = ev;
83 7 : ev->additional_data = poll_ev;
84 7 : return 0;
85 : }
86 :
87 0 : static int poll_event_context_init_mt(struct tevent_context *ev)
88 : {
89 : struct poll_event_context *poll_ev;
90 : int ret;
91 :
92 0 : ret = poll_event_context_init(ev);
93 0 : if (ret == -1) {
94 0 : return ret;
95 : }
96 :
97 0 : poll_ev = talloc_get_type_abort(
98 : ev->additional_data, struct poll_event_context);
99 :
100 0 : ret = tevent_common_wakeup_init(ev);
101 0 : if (ret != 0) {
102 0 : return ret;
103 : }
104 :
105 0 : poll_ev->use_mt_mode = true;
106 :
107 0 : return 0;
108 : }
109 :
110 3 : static void poll_event_wake_pollthread(struct poll_event_context *poll_ev)
111 : {
112 3 : if (!poll_ev->use_mt_mode) {
113 3 : return;
114 : }
115 0 : tevent_common_wakeup(poll_ev->ev);
116 : }
117 :
118 : /*
119 : destroy an fd_event
120 : */
121 5 : static int poll_event_fd_destructor(struct tevent_fd *fde)
122 : {
123 5 : struct tevent_context *ev = fde->event_ctx;
124 : struct poll_event_context *poll_ev;
125 5 : uint64_t del_idx = fde->additional_flags;
126 :
127 5 : if (ev == NULL) {
128 2 : goto done;
129 : }
130 :
131 3 : poll_ev = talloc_get_type_abort(
132 : ev->additional_data, struct poll_event_context);
133 :
134 3 : if (del_idx == UINT64_MAX) {
135 0 : goto done;
136 : }
137 :
138 3 : poll_ev->fdes[del_idx] = NULL;
139 3 : poll_ev->deleted = true;
140 3 : poll_event_wake_pollthread(poll_ev);
141 5 : done:
142 5 : return tevent_common_fd_destructor(fde);
143 : }
144 :
145 0 : static void poll_event_schedule_immediate(struct tevent_immediate *im,
146 : struct tevent_context *ev,
147 : tevent_immediate_handler_t handler,
148 : void *private_data,
149 : const char *handler_name,
150 : const char *location)
151 : {
152 0 : struct poll_event_context *poll_ev = talloc_get_type_abort(
153 : ev->additional_data, struct poll_event_context);
154 :
155 0 : tevent_common_schedule_immediate(im, ev, handler, private_data,
156 : handler_name, location);
157 0 : poll_event_wake_pollthread(poll_ev);
158 0 : }
159 :
160 : /*
161 : Private function called by "standard" backend fallback.
162 : Note this only allows fallback to "poll" backend, not "poll-mt".
163 : */
164 5 : _PRIVATE_ bool tevent_poll_event_add_fd_internal(struct tevent_context *ev,
165 : struct tevent_fd *fde)
166 : {
167 5 : struct poll_event_context *poll_ev = talloc_get_type_abort(
168 : ev->additional_data, struct poll_event_context);
169 5 : uint64_t fde_idx = UINT64_MAX;
170 : size_t num_fdes;
171 :
172 5 : fde->additional_flags = UINT64_MAX;
173 5 : talloc_set_destructor(fde, poll_event_fd_destructor);
174 :
175 5 : if (fde->flags == 0) {
176 : /*
177 : * Nothing more to do...
178 : */
179 0 : return true;
180 : }
181 :
182 : /*
183 : * We need to add it to the end of the 'fdes' array.
184 : */
185 5 : num_fdes = poll_ev->num_fdes + 1;
186 5 : if (num_fdes > talloc_array_length(poll_ev->fdes)) {
187 5 : struct tevent_fd **tmp_fdes = NULL;
188 : size_t array_length;
189 :
190 5 : array_length = (num_fdes + 15) & ~15; /* round up to 16 */
191 :
192 5 : tmp_fdes = talloc_realloc(poll_ev,
193 : poll_ev->fdes,
194 : struct tevent_fd *,
195 : array_length);
196 5 : if (tmp_fdes == NULL) {
197 0 : return false;
198 : }
199 5 : poll_ev->fdes = tmp_fdes;
200 : }
201 :
202 5 : fde_idx = poll_ev->num_fdes;
203 5 : fde->additional_flags = fde_idx;
204 5 : poll_ev->fdes[fde_idx] = fde;
205 5 : poll_ev->num_fdes++;
206 :
207 5 : return true;
208 : }
209 :
210 : /*
211 : add a fd based event
212 : return NULL on failure (memory allocation error)
213 : */
214 0 : static struct tevent_fd *poll_event_add_fd(struct tevent_context *ev,
215 : TALLOC_CTX *mem_ctx,
216 : int fd, uint16_t flags,
217 : tevent_fd_handler_t handler,
218 : void *private_data,
219 : const char *handler_name,
220 : const char *location)
221 : {
222 0 : struct poll_event_context *poll_ev = talloc_get_type_abort(
223 : ev->additional_data, struct poll_event_context);
224 : struct tevent_fd *fde;
225 : bool ok;
226 :
227 0 : if (fd < 0) {
228 0 : return NULL;
229 : }
230 :
231 0 : fde = tevent_common_add_fd(ev,
232 : mem_ctx,
233 : fd,
234 : flags,
235 : handler,
236 : private_data,
237 : handler_name,
238 : location);
239 0 : if (fde == NULL) {
240 0 : return NULL;
241 : }
242 :
243 0 : ok = tevent_poll_event_add_fd_internal(ev, fde);
244 0 : if (!ok) {
245 0 : TALLOC_FREE(fde);
246 0 : return NULL;
247 : }
248 0 : poll_event_wake_pollthread(poll_ev);
249 :
250 : /*
251 : * poll_event_loop_poll will take care of the rest in
252 : * poll_event_setup_fresh
253 : */
254 0 : return fde;
255 : }
256 :
257 : /*
258 : set the fd event flags
259 : */
260 2 : static void poll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
261 : {
262 2 : struct tevent_context *ev = fde->event_ctx;
263 : struct poll_event_context *poll_ev;
264 2 : uint64_t idx = fde->additional_flags;
265 : uint16_t pollflags;
266 :
267 2 : if (ev == NULL) {
268 0 : return;
269 : }
270 :
271 2 : if (fde->flags == flags) {
272 2 : return;
273 : }
274 :
275 0 : poll_ev = talloc_get_type_abort(
276 : ev->additional_data, struct poll_event_context);
277 :
278 0 : fde->flags = flags;
279 :
280 0 : if (idx == UINT64_MAX) {
281 : /*
282 : * We move it between the fresh and disabled lists.
283 : */
284 0 : tevent_poll_event_add_fd_internal(ev, fde);
285 0 : poll_event_wake_pollthread(poll_ev);
286 0 : return;
287 : }
288 :
289 0 : if (fde->flags == 0) {
290 : /*
291 : * We need to remove it from the array
292 : * and move it to the disabled list.
293 : */
294 0 : poll_ev->fdes[idx] = NULL;
295 0 : poll_ev->deleted = true;
296 0 : fde->additional_flags = UINT64_MAX;
297 0 : poll_event_wake_pollthread(poll_ev);
298 0 : return;
299 : }
300 :
301 0 : if (idx >= poll_ev->num_fds) {
302 : /*
303 : * Not yet added to the
304 : * poll_ev->fds array.
305 : */
306 0 : poll_event_wake_pollthread(poll_ev);
307 0 : return;
308 : }
309 :
310 0 : pollflags = 0;
311 :
312 0 : if (flags & TEVENT_FD_READ) {
313 0 : pollflags |= (POLLIN|POLLHUP);
314 : }
315 0 : if (flags & TEVENT_FD_WRITE) {
316 0 : pollflags |= (POLLOUT);
317 : }
318 0 : poll_ev->fds[idx].events = pollflags;
319 :
320 0 : poll_event_wake_pollthread(poll_ev);
321 : }
322 :
323 2 : static bool poll_event_sync_arrays(struct tevent_context *ev,
324 : struct poll_event_context *poll_ev)
325 : {
326 : size_t i;
327 : size_t array_length;
328 :
329 2 : if (poll_ev->deleted) {
330 :
331 0 : for (i=0; i < poll_ev->num_fds;) {
332 0 : struct tevent_fd *fde = poll_ev->fdes[i];
333 : size_t ci;
334 :
335 0 : if (fde != NULL) {
336 0 : i++;
337 0 : continue;
338 : }
339 :
340 : /*
341 : * This fde was talloc_free()'ed. Delete it
342 : * from the arrays
343 : */
344 0 : poll_ev->num_fds -= 1;
345 0 : ci = poll_ev->num_fds;
346 0 : if (ci > i) {
347 0 : poll_ev->fds[i] = poll_ev->fds[ci];
348 0 : poll_ev->fdes[i] = poll_ev->fdes[ci];
349 0 : if (poll_ev->fdes[i] != NULL) {
350 0 : poll_ev->fdes[i]->additional_flags = i;
351 : }
352 : }
353 0 : poll_ev->fds[ci] = (struct pollfd) { .fd = -1 };
354 0 : poll_ev->fdes[ci] = NULL;
355 : }
356 0 : poll_ev->deleted = false;
357 : }
358 :
359 2 : if (poll_ev->num_fds == poll_ev->num_fdes) {
360 0 : return true;
361 : }
362 :
363 : /*
364 : * Recheck the size of both arrays and make sure
365 : * poll_fd->fds array has at least the size of the
366 : * in use poll_ev->fdes array.
367 : */
368 2 : if (poll_ev->num_fdes > talloc_array_length(poll_ev->fds)) {
369 2 : struct pollfd *tmp_fds = NULL;
370 :
371 : /*
372 : * Make sure both allocated the same length.
373 : */
374 2 : array_length = talloc_array_length(poll_ev->fdes);
375 :
376 2 : tmp_fds = talloc_realloc(poll_ev,
377 : poll_ev->fds,
378 : struct pollfd,
379 : array_length);
380 2 : if (tmp_fds == NULL) {
381 0 : return false;
382 : }
383 2 : poll_ev->fds = tmp_fds;
384 : }
385 :
386 : /*
387 : * Now setup the new elements.
388 : */
389 4 : for (i = poll_ev->num_fds; i < poll_ev->num_fdes; i++) {
390 2 : struct tevent_fd *fde = poll_ev->fdes[i];
391 2 : struct pollfd *pfd = &poll_ev->fds[poll_ev->num_fds];
392 :
393 2 : if (fde == NULL) {
394 0 : continue;
395 : }
396 :
397 2 : if (i > poll_ev->num_fds) {
398 0 : poll_ev->fdes[poll_ev->num_fds] = fde;
399 0 : fde->additional_flags = poll_ev->num_fds;
400 0 : poll_ev->fdes[i] = NULL;
401 : }
402 :
403 2 : pfd->fd = fde->fd;
404 2 : pfd->events = 0;
405 2 : pfd->revents = 0;
406 :
407 2 : if (fde->flags & TEVENT_FD_READ) {
408 0 : pfd->events |= (POLLIN|POLLHUP);
409 : }
410 2 : if (fde->flags & TEVENT_FD_WRITE) {
411 2 : pfd->events |= (POLLOUT);
412 : }
413 :
414 2 : poll_ev->num_fds += 1;
415 : }
416 : /* Both are in sync again */
417 2 : poll_ev->num_fdes = poll_ev->num_fds;
418 :
419 : /*
420 : * Check if we should shrink the arrays
421 : * But keep at least 16 elements.
422 : */
423 :
424 2 : array_length = (poll_ev->num_fds + 15) & ~15; /* round up to 16 */
425 2 : array_length = MAX(array_length, 16);
426 2 : if (array_length < talloc_array_length(poll_ev->fdes)) {
427 0 : struct tevent_fd **tmp_fdes = NULL;
428 0 : struct pollfd *tmp_fds = NULL;
429 :
430 0 : tmp_fdes = talloc_realloc(poll_ev,
431 : poll_ev->fdes,
432 : struct tevent_fd *,
433 : array_length);
434 0 : if (tmp_fdes == NULL) {
435 0 : return false;
436 : }
437 0 : poll_ev->fdes = tmp_fdes;
438 :
439 0 : tmp_fds = talloc_realloc(poll_ev,
440 : poll_ev->fds,
441 : struct pollfd,
442 : array_length);
443 0 : if (tmp_fds == NULL) {
444 0 : return false;
445 : }
446 0 : poll_ev->fds = tmp_fds;
447 : }
448 :
449 2 : return true;
450 : }
451 :
452 : /*
453 : event loop handling using poll()
454 : */
455 2 : static int poll_event_loop_poll(struct tevent_context *ev,
456 : struct timeval *tvalp)
457 : {
458 2 : struct poll_event_context *poll_ev = talloc_get_type_abort(
459 : ev->additional_data, struct poll_event_context);
460 : int pollrtn;
461 2 : int timeout = -1;
462 : int poll_errno;
463 2 : struct tevent_fd *fde = NULL;
464 2 : struct tevent_fd *next = NULL;
465 : unsigned i;
466 : bool ok;
467 :
468 2 : if (ev->signal_events && tevent_common_check_signal(ev)) {
469 0 : return 0;
470 : }
471 :
472 2 : if (tvalp != NULL) {
473 2 : timeout = tvalp->tv_sec * 1000;
474 2 : timeout += (tvalp->tv_usec + 999) / 1000;
475 : }
476 :
477 2 : ok = poll_event_sync_arrays(ev, poll_ev);
478 2 : if (!ok) {
479 0 : return -1;
480 : }
481 :
482 2 : tevent_trace_point_callback(poll_ev->ev, TEVENT_TRACE_BEFORE_WAIT);
483 2 : pollrtn = poll(poll_ev->fds, poll_ev->num_fds, timeout);
484 2 : poll_errno = errno;
485 2 : tevent_trace_point_callback(poll_ev->ev, TEVENT_TRACE_AFTER_WAIT);
486 :
487 2 : if (pollrtn == -1 && poll_errno == EINTR && ev->signal_events) {
488 0 : tevent_common_check_signal(ev);
489 0 : return 0;
490 : }
491 :
492 2 : if (pollrtn == 0 && tvalp) {
493 : /* we don't care about a possible delay here */
494 0 : tevent_common_loop_timer_delay(ev);
495 0 : return 0;
496 : }
497 :
498 2 : if (pollrtn <= 0) {
499 : /*
500 : * No fd's ready
501 : */
502 0 : return 0;
503 : }
504 :
505 : /* at least one file descriptor is ready - check
506 : which ones and call the handler, being careful to allow
507 : the handler to remove itself when called */
508 :
509 2 : for (fde = ev->fd_events; fde; fde = next) {
510 2 : uint64_t idx = fde->additional_flags;
511 : struct pollfd *pfd;
512 2 : uint16_t flags = 0;
513 :
514 2 : next = fde->next;
515 :
516 2 : if (idx == UINT64_MAX) {
517 0 : continue;
518 : }
519 :
520 2 : pfd = &poll_ev->fds[idx];
521 :
522 2 : if (pfd->revents & POLLNVAL) {
523 : /*
524 : * the socket is dead! this should never
525 : * happen as the socket should have first been
526 : * made readable and that should have removed
527 : * the event, so this must be a bug.
528 : *
529 : * We ignore it here to match the epoll
530 : * behavior.
531 : */
532 0 : tevent_debug(ev, TEVENT_DEBUG_ERROR,
533 : "POLLNVAL on fde[%p] fd[%d] - disabling\n",
534 : fde, pfd->fd);
535 0 : poll_ev->fdes[idx] = NULL;
536 0 : poll_ev->deleted = true;
537 0 : DLIST_REMOVE(ev->fd_events, fde);
538 0 : fde->wrapper = NULL;
539 0 : fde->event_ctx = NULL;
540 0 : continue;
541 : }
542 :
543 2 : if (pfd->revents & (POLLHUP|POLLERR)) {
544 : /* If we only wait for TEVENT_FD_WRITE, we
545 : should not tell the event handler about it,
546 : and remove the writable flag, as we only
547 : report errors when waiting for read events
548 : to match the select behavior. */
549 0 : if (!(fde->flags & TEVENT_FD_READ)) {
550 0 : TEVENT_FD_NOT_WRITEABLE(fde);
551 0 : continue;
552 : }
553 0 : flags |= TEVENT_FD_READ;
554 : }
555 2 : if (pfd->revents & POLLIN) {
556 0 : flags |= TEVENT_FD_READ;
557 : }
558 2 : if (pfd->revents & POLLOUT) {
559 2 : flags |= TEVENT_FD_WRITE;
560 : }
561 : /*
562 : * Note that fde->flags could be changed when using
563 : * the poll_mt backend together with threads,
564 : * that why we need to check pfd->revents and fde->flags
565 : */
566 2 : flags &= fde->flags;
567 2 : if (flags != 0) {
568 2 : DLIST_DEMOTE(ev->fd_events, fde);
569 2 : return tevent_common_invoke_fd_handler(fde, flags, NULL);
570 : }
571 : }
572 :
573 0 : for (i = 0; i < poll_ev->num_fds; i++) {
574 0 : if (poll_ev->fds[i].revents & POLLNVAL) {
575 : /*
576 : * the socket is dead! this should never
577 : * happen as the socket should have first been
578 : * made readable and that should have removed
579 : * the event, so this must be a bug or
580 : * a race in the poll_mt usage.
581 : */
582 0 : fde = poll_ev->fdes[i];
583 0 : tevent_debug(ev, TEVENT_DEBUG_WARNING,
584 : "POLLNVAL on dangling fd[%d] fde[%p] - disabling\n",
585 0 : poll_ev->fds[i].fd, fde);
586 0 : poll_ev->fdes[i] = NULL;
587 0 : poll_ev->deleted = true;
588 0 : if (fde != NULL) {
589 0 : DLIST_REMOVE(ev->fd_events, fde);
590 0 : fde->wrapper = NULL;
591 0 : fde->event_ctx = NULL;
592 : }
593 : }
594 : }
595 :
596 0 : return 0;
597 : }
598 :
599 : /*
600 : do a single event loop using the events defined in ev
601 : */
602 2 : static int poll_event_loop_once(struct tevent_context *ev,
603 : const char *location)
604 : {
605 : struct timeval tval;
606 :
607 2 : if (ev->signal_events &&
608 0 : tevent_common_check_signal(ev)) {
609 0 : return 0;
610 : }
611 :
612 2 : if (ev->threaded_contexts != NULL) {
613 0 : tevent_common_threaded_activate_immediate(ev);
614 : }
615 :
616 2 : if (ev->immediate_events &&
617 0 : tevent_common_loop_immediate(ev)) {
618 0 : return 0;
619 : }
620 :
621 2 : tval = tevent_common_loop_timer_delay(ev);
622 2 : if (tevent_timeval_is_zero(&tval)) {
623 0 : return 0;
624 : }
625 :
626 2 : return poll_event_loop_poll(ev, &tval);
627 : }
628 :
629 : static const struct tevent_ops poll_event_ops = {
630 : .context_init = poll_event_context_init,
631 : .add_fd = poll_event_add_fd,
632 : .set_fd_close_fn = tevent_common_fd_set_close_fn,
633 : .get_fd_flags = tevent_common_fd_get_flags,
634 : .set_fd_flags = poll_event_set_fd_flags,
635 : .add_timer = tevent_common_add_timer_v2,
636 : .schedule_immediate = tevent_common_schedule_immediate,
637 : .add_signal = tevent_common_add_signal,
638 : .loop_once = poll_event_loop_once,
639 : .loop_wait = tevent_common_loop_wait,
640 : };
641 :
642 28196 : _PRIVATE_ bool tevent_poll_init(void)
643 : {
644 28196 : return tevent_register_backend("poll", &poll_event_ops);
645 : }
646 :
647 : static const struct tevent_ops poll_event_mt_ops = {
648 : .context_init = poll_event_context_init_mt,
649 : .add_fd = poll_event_add_fd,
650 : .set_fd_close_fn = tevent_common_fd_set_close_fn,
651 : .get_fd_flags = tevent_common_fd_get_flags,
652 : .set_fd_flags = poll_event_set_fd_flags,
653 : .add_timer = tevent_common_add_timer_v2,
654 : .schedule_immediate = poll_event_schedule_immediate,
655 : .add_signal = tevent_common_add_signal,
656 : .loop_once = poll_event_loop_once,
657 : .loop_wait = tevent_common_loop_wait,
658 : };
659 :
660 28196 : _PRIVATE_ bool tevent_poll_mt_init(void)
661 : {
662 28196 : return tevent_register_backend("poll_mt", &poll_event_mt_ops);
663 : }
|