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