Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : generalised event loop handling
5 :
6 : INTERNAL STRUCTS. THERE ARE NO API GUARANTEES.
7 : External users should only ever have to include this header when
8 : implementing new tevent backends.
9 :
10 : Copyright (C) Stefan Metzmacher 2005-2009
11 :
12 : ** NOTE! The following LGPL license applies to the tevent
13 : ** library. This does NOT imply that all of Samba is released
14 : ** under the LGPL
15 :
16 : This library is free software; you can redistribute it and/or
17 : modify it under the terms of the GNU Lesser General Public
18 : License as published by the Free Software Foundation; either
19 : version 3 of the License, or (at your option) any later version.
20 :
21 : This library is distributed in the hope that it will be useful,
22 : but WITHOUT ANY WARRANTY; without even the implied warranty of
23 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 : Lesser General Public License for more details.
25 :
26 : You should have received a copy of the GNU Lesser General Public
27 : License along with this library; if not, see <http://www.gnu.org/licenses/>.
28 : */
29 :
30 : struct tevent_req {
31 : /**
32 : * @brief What to do on completion
33 : *
34 : * This is used for the user of an async request, fn is called when
35 : * the request completes, either successfully or with an error.
36 : */
37 : struct {
38 : /**
39 : * @brief Completion function
40 : * Completion function, to be filled by the API user
41 : */
42 : tevent_req_fn fn;
43 : /**
44 : * @brief Private data for the completion function
45 : */
46 : void *private_data;
47 : /**
48 : * @brief The completion function name, for flow tracing.
49 : */
50 : const char *fn_name;
51 : } async;
52 :
53 : /**
54 : * @brief Private state pointer for the actual implementation
55 : *
56 : * The implementation doing the work for the async request needs to
57 : * keep around current data like for example a fd event. The user of
58 : * an async request should not touch this.
59 : */
60 : void *data;
61 :
62 : /**
63 : * @brief A function to overwrite the default print function
64 : *
65 : * The implementation doing the work may want to implement a
66 : * custom function to print the text representation of the async
67 : * request.
68 : */
69 : tevent_req_print_fn private_print;
70 :
71 : /**
72 : * @brief A function to cancel the request
73 : *
74 : * The implementation might want to set a function
75 : * that is called when the tevent_req_cancel() function
76 : * was called.
77 : */
78 : struct {
79 : tevent_req_cancel_fn fn;
80 : const char *fn_name;
81 : } private_cancel;
82 :
83 : /**
84 : * @brief A function to cleanup the request
85 : *
86 : * The implementation might want to set a function
87 : * that is called before the tevent_req_done() and tevent_req_error()
88 : * trigger the callers callback function.
89 : */
90 : struct {
91 : tevent_req_cleanup_fn fn;
92 : const char *fn_name;
93 : enum tevent_req_state state;
94 : } private_cleanup;
95 :
96 : /**
97 : * @brief Internal state of the request
98 : *
99 : * Callers should only access this via functions and never directly.
100 : */
101 : struct {
102 : /**
103 : * @brief The talloc type of the data pointer
104 : *
105 : * This is filled by the tevent_req_create() macro.
106 : *
107 : * This for debugging only.
108 : */
109 : const char *private_type;
110 :
111 : /**
112 : * @brief The location where the request was created
113 : *
114 : * This uses the __location__ macro via the tevent_req_create()
115 : * macro.
116 : *
117 : * This for debugging only.
118 : */
119 : const char *create_location;
120 :
121 : /**
122 : * @brief The location where the request was finished
123 : *
124 : * This uses the __location__ macro via the tevent_req_done(),
125 : * tevent_req_error() or tevent_req_nomem() macro.
126 : *
127 : * This for debugging only.
128 : */
129 : const char *finish_location;
130 :
131 : /**
132 : * @brief The location where the request was canceled
133 : *
134 : * This uses the __location__ macro via the
135 : * tevent_req_cancel() macro.
136 : *
137 : * This for debugging only.
138 : */
139 : const char *cancel_location;
140 :
141 : /**
142 : * @brief The external state - will be queried by the caller
143 : *
144 : * While the async request is being processed, state will remain in
145 : * TEVENT_REQ_IN_PROGRESS. A request is finished if
146 : * req->state>=TEVENT_REQ_DONE.
147 : */
148 : enum tevent_req_state state;
149 :
150 : /**
151 : * @brief status code when finished
152 : *
153 : * This status can be queried in the async completion function. It
154 : * will be set to 0 when everything went fine.
155 : */
156 : uint64_t error;
157 :
158 : /**
159 : * @brief the immediate event used by tevent_req_post
160 : *
161 : */
162 : struct tevent_immediate *trigger;
163 :
164 : /**
165 : * @brief An event context which will be used to
166 : * defer the _tevent_req_notify_callback().
167 : */
168 : struct tevent_context *defer_callback_ev;
169 :
170 : /**
171 : * @brief the timer event if tevent_req_set_endtime was used
172 : *
173 : */
174 : struct tevent_timer *timer;
175 :
176 : /**
177 : * @brief The place where profiling data is kept
178 : */
179 : struct tevent_req_profile *profile;
180 :
181 : size_t call_depth;
182 : } internal;
183 : };
184 :
185 : struct tevent_req_profile {
186 : struct tevent_req_profile *prev, *next;
187 : struct tevent_req_profile *parent;
188 : const char *req_name;
189 : pid_t pid;
190 : const char *start_location;
191 : struct timeval start_time;
192 : const char *stop_location;
193 : struct timeval stop_time;
194 : enum tevent_req_state state;
195 : uint64_t user_error;
196 : struct tevent_req_profile *subprofiles;
197 : };
198 :
199 : struct tevent_fd {
200 : struct tevent_fd *prev, *next;
201 : struct tevent_context *event_ctx;
202 : struct tevent_wrapper_glue *wrapper;
203 : bool busy;
204 : bool destroyed;
205 : int fd;
206 : uint16_t flags; /* see TEVENT_FD_* flags */
207 : tevent_fd_handler_t handler;
208 : tevent_fd_close_fn_t close_fn;
209 : /* this is private for the specific handler */
210 : void *private_data;
211 : /* this is for debugging only! */
212 : const char *handler_name;
213 : const char *location;
214 : /* this is private for the events_ops implementation */
215 : uint64_t additional_flags;
216 : void *additional_data;
217 : /* custom tag that can be set by caller */
218 : uint64_t tag;
219 : struct tevent_fd_mpx {
220 : struct tevent_fd_mpx *prev, *next;
221 : struct tevent_fd *fde;
222 : struct tevent_fd *primary;
223 : struct tevent_fd_mpx *list;
224 : uint16_t total_flags;
225 : bool has_mpx;
226 : } mpx;
227 : };
228 :
229 : struct tevent_timer {
230 : struct tevent_timer *prev, *next;
231 : struct tevent_context *event_ctx;
232 : struct tevent_wrapper_glue *wrapper;
233 : bool busy;
234 : bool destroyed;
235 : struct timeval next_event;
236 : tevent_timer_handler_t handler;
237 : /* this is private for the specific handler */
238 : void *private_data;
239 : /* this is for debugging only! */
240 : const char *handler_name;
241 : const char *location;
242 : /* this is private for the events_ops implementation */
243 : void *additional_data;
244 : /* custom tag that can be set by caller */
245 : uint64_t tag;
246 : };
247 :
248 : struct tevent_immediate {
249 : struct tevent_immediate *prev, *next;
250 : struct tevent_context *event_ctx;
251 : struct tevent_wrapper_glue *wrapper;
252 : bool busy;
253 : bool destroyed;
254 : struct tevent_context *detach_ev_ctx;
255 : tevent_immediate_handler_t handler;
256 : /* this is private for the specific handler */
257 : void *private_data;
258 : /* this is for debugging only! */
259 : const char *handler_name;
260 : const char *create_location;
261 : const char *schedule_location;
262 : /* this is private for the events_ops implementation */
263 : void (*cancel_fn)(struct tevent_immediate *im);
264 : void *additional_data;
265 : /* custom tag that can be set by caller */
266 : uint64_t tag;
267 : };
268 :
269 : struct tevent_signal {
270 : struct tevent_signal *prev, *next;
271 : struct tevent_context *event_ctx;
272 : struct tevent_wrapper_glue *wrapper;
273 : bool busy;
274 : bool destroyed;
275 : int signum;
276 : int sa_flags;
277 : tevent_signal_handler_t handler;
278 : /* this is private for the specific handler */
279 : void *private_data;
280 : /* this is for debugging only! */
281 : const char *handler_name;
282 : const char *location;
283 : /* this is private for the events_ops implementation */
284 : void *additional_data;
285 : /* custom tag that can be set by caller */
286 : uint64_t tag;
287 : };
288 :
289 : struct tevent_threaded_context {
290 : struct tevent_threaded_context *next, *prev;
291 :
292 : #ifdef HAVE_PTHREAD
293 : pthread_mutex_t event_ctx_mutex;
294 : #endif
295 : struct tevent_context *event_ctx;
296 : };
297 :
298 : struct tevent_debug_ops {
299 : enum tevent_debug_level max_level;
300 : void (*debug)(void *context, enum tevent_debug_level level,
301 : const char *fmt, va_list ap) PRINTF_ATTRIBUTE(3,0);
302 : void *context;
303 : };
304 :
305 : void tevent_debug(struct tevent_context *ev, enum tevent_debug_level level,
306 : const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
307 : #define TEVENT_DEBUG(__ev, __level, __fmt, ...) do { \
308 : if (unlikely((__ev) != NULL && \
309 : (__level) <= (__ev)->debug_ops.max_level)) \
310 : { \
311 : tevent_debug((__ev), (__level), (__fmt), __VA_ARGS__); \
312 : } \
313 : } while(0)
314 :
315 : void tevent_abort(struct tevent_context *ev, const char *reason);
316 :
317 : void tevent_common_check_double_free(TALLOC_CTX *ptr, const char *reason);
318 :
319 : struct tevent_context {
320 : /* the specific events implementation */
321 : const struct tevent_ops *ops;
322 :
323 : /*
324 : * The following three pointers are queried on every loop_once
325 : * in the order in which they appear here. Not measured, but
326 : * hopefully putting them at the top together with "ops"
327 : * should make tevent a *bit* more cache-friendly than before.
328 : */
329 :
330 : /* list of signal events - used by common code */
331 : struct tevent_signal *signal_events;
332 :
333 : /* List of threaded job indicators */
334 : struct tevent_threaded_context *threaded_contexts;
335 :
336 : /* list of immediate events - used by common code */
337 : struct tevent_immediate *immediate_events;
338 :
339 : /* list of fd events - used by common code */
340 : struct tevent_fd *fd_events;
341 :
342 : /* list of timed events - used by common code */
343 : struct tevent_timer *timer_events;
344 :
345 : /* List of scheduled immediates */
346 : pthread_mutex_t scheduled_mutex;
347 : struct tevent_immediate *scheduled_immediates;
348 :
349 : /* this is private for the events_ops implementation */
350 : void *additional_data;
351 :
352 : /* pipe hack used with signal handlers */
353 : struct tevent_fd *wakeup_fde;
354 : int wakeup_fd; /* fd to write into */
355 : #ifndef HAVE_EVENT_FD
356 : int wakeup_read_fd;
357 : #endif
358 :
359 : /* debugging operations */
360 : struct tevent_debug_ops debug_ops;
361 :
362 : /* info about the nesting status */
363 : struct {
364 : bool allowed;
365 : uint32_t level;
366 : tevent_nesting_hook hook_fn;
367 : void *hook_private;
368 : } nesting;
369 :
370 : struct {
371 : struct {
372 : tevent_trace_callback_t callback;
373 : void *private_data;
374 : } point;
375 :
376 : struct {
377 : tevent_trace_fd_callback_t callback;
378 : void *private_data;
379 : } fde;
380 :
381 : struct {
382 : tevent_trace_signal_callback_t callback;
383 : void *private_data;
384 : } se;
385 :
386 : struct {
387 : tevent_trace_timer_callback_t callback;
388 : void *private_data;
389 : } te;
390 :
391 : struct {
392 : tevent_trace_immediate_callback_t callback;
393 : void *private_data;
394 : } im;
395 :
396 : struct {
397 : tevent_trace_queue_callback_t callback;
398 : void *private_data;
399 : } qe;
400 : } tracing;
401 :
402 : struct {
403 : /*
404 : * This is used on the main event context
405 : */
406 : struct tevent_wrapper_glue *list;
407 :
408 : /*
409 : * This is used on the wrapper event context
410 : */
411 : struct tevent_wrapper_glue *glue;
412 : } wrapper;
413 :
414 : /*
415 : * an optimization pointer into timer_events
416 : * used by used by common code via
417 : * tevent_common_add_timer_v2()
418 : */
419 : struct tevent_timer *last_zero_timer;
420 :
421 : #ifdef HAVE_PTHREAD
422 : struct tevent_context *prev, *next;
423 : #endif
424 : };
425 :
426 : int tevent_common_context_destructor(struct tevent_context *ev);
427 : int tevent_common_loop_wait(struct tevent_context *ev,
428 : const char *location);
429 :
430 : struct tevent_common_fd_buf {
431 : char buf[128];
432 : };
433 :
434 : const char *tevent_common_fd_str(struct tevent_common_fd_buf *buf,
435 : const char *description,
436 : const struct tevent_fd *fde);
437 :
438 : int tevent_common_fd_destructor(struct tevent_fd *fde);
439 : struct tevent_fd *tevent_common_add_fd(struct tevent_context *ev,
440 : TALLOC_CTX *mem_ctx,
441 : int fd,
442 : uint16_t flags,
443 : tevent_fd_handler_t handler,
444 : void *private_data,
445 : const char *handler_name,
446 : const char *location);
447 : void tevent_common_fd_set_close_fn(struct tevent_fd *fde,
448 : tevent_fd_close_fn_t close_fn);
449 : uint16_t tevent_common_fd_get_flags(struct tevent_fd *fde);
450 : void tevent_common_fd_set_flags(struct tevent_fd *fde, uint16_t flags);
451 : int tevent_common_invoke_fd_handler(struct tevent_fd *fde, uint16_t flags,
452 : bool *removed);
453 :
454 : struct tevent_timer *tevent_common_add_timer(struct tevent_context *ev,
455 : TALLOC_CTX *mem_ctx,
456 : struct timeval next_event,
457 : tevent_timer_handler_t handler,
458 : void *private_data,
459 : const char *handler_name,
460 : const char *location);
461 : struct tevent_timer *tevent_common_add_timer_v2(struct tevent_context *ev,
462 : TALLOC_CTX *mem_ctx,
463 : struct timeval next_event,
464 : tevent_timer_handler_t handler,
465 : void *private_data,
466 : const char *handler_name,
467 : const char *location);
468 : struct timeval tevent_common_loop_timer_delay(struct tevent_context *);
469 : int tevent_common_invoke_timer_handler(struct tevent_timer *te,
470 : struct timeval current_time,
471 : bool *removed);
472 :
473 : void tevent_common_schedule_immediate(struct tevent_immediate *im,
474 : struct tevent_context *ev,
475 : tevent_immediate_handler_t handler,
476 : void *private_data,
477 : const char *handler_name,
478 : const char *location);
479 : int tevent_common_invoke_immediate_handler(struct tevent_immediate *im,
480 : bool *removed);
481 : bool tevent_common_loop_immediate(struct tevent_context *ev);
482 : void tevent_common_threaded_activate_immediate(struct tevent_context *ev);
483 :
484 : bool tevent_common_have_events(struct tevent_context *ev);
485 : int tevent_common_wakeup_init(struct tevent_context *ev);
486 : int tevent_common_wakeup_fd(int fd);
487 : int tevent_common_wakeup(struct tevent_context *ev);
488 :
489 : struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev,
490 : TALLOC_CTX *mem_ctx,
491 : int signum,
492 : int sa_flags,
493 : tevent_signal_handler_t handler,
494 : void *private_data,
495 : const char *handler_name,
496 : const char *location);
497 : int tevent_common_check_signal(struct tevent_context *ev);
498 : void tevent_cleanup_pending_signal_handlers(struct tevent_signal *se);
499 : int tevent_common_invoke_signal_handler(struct tevent_signal *se,
500 : int signum, int count, void *siginfo,
501 : bool *removed);
502 :
503 : struct tevent_context *tevent_wrapper_main_ev(struct tevent_context *ev);
504 :
505 : struct tevent_wrapper_ops;
506 :
507 : struct tevent_wrapper_glue {
508 : struct tevent_wrapper_glue *prev, *next;
509 : struct tevent_context *wrap_ev;
510 : struct tevent_context *main_ev;
511 : bool busy;
512 : bool destroyed;
513 : const struct tevent_wrapper_ops *ops;
514 : void *private_state;
515 : };
516 :
517 : void tevent_wrapper_push_use_internal(struct tevent_context *ev,
518 : struct tevent_wrapper_glue *wrapper);
519 : void tevent_wrapper_pop_use_internal(const struct tevent_context *__ev_ptr,
520 : struct tevent_wrapper_glue *wrapper);
521 :
522 : bool tevent_standard_init(void);
523 : bool tevent_poll_init(void);
524 : bool tevent_poll_event_add_fd_internal(struct tevent_context *ev,
525 : struct tevent_fd *fde);
526 : bool tevent_poll_mt_init(void);
527 : #ifdef HAVE_EPOLL
528 : bool tevent_epoll_init(void);
529 : void tevent_epoll_set_panic_fallback(struct tevent_context *ev,
530 : bool (*panic_fallback)(struct tevent_context *ev,
531 : bool replay));
532 : #endif
533 :
534 1037313841 : static inline void tevent_thread_call_depth_notify(
535 : enum tevent_thread_call_depth_cmd cmd,
536 : struct tevent_req *req,
537 : size_t depth,
538 : const char *fname)
539 : {
540 1037313841 : if (tevent_thread_call_depth_state_g.cb != NULL) {
541 0 : tevent_thread_call_depth_state_g.cb(
542 : tevent_thread_call_depth_state_g.cb_private,
543 : cmd,
544 : req,
545 : depth,
546 : fname);
547 : }
548 997070505 : }
549 :
550 : void tevent_trace_point_callback(struct tevent_context *ev,
551 : enum tevent_trace_point);
552 :
553 : void tevent_trace_fd_callback(struct tevent_context *ev,
554 : struct tevent_fd *fde,
555 : enum tevent_event_trace_point);
556 :
557 : void tevent_trace_signal_callback(struct tevent_context *ev,
558 : struct tevent_signal *se,
559 : enum tevent_event_trace_point);
560 :
561 : void tevent_trace_timer_callback(struct tevent_context *ev,
562 : struct tevent_timer *te,
563 : enum tevent_event_trace_point);
564 :
565 : void tevent_trace_immediate_callback(struct tevent_context *ev,
566 : struct tevent_immediate *im,
567 : enum tevent_event_trace_point);
568 :
569 : void tevent_trace_queue_callback(struct tevent_context *ev,
570 : struct tevent_queue_entry *qe,
571 : enum tevent_event_trace_point);
572 :
573 : #include "tevent_dlinklist.h"
574 :
575 42038015 : static inline void tevent_common_fd_mpx_reinit(struct tevent_fd *fde)
576 : {
577 41988744 : fde->mpx = (struct tevent_fd_mpx) { .fde = fde, };
578 41858779 : }
579 :
580 1068491 : static inline void tevent_common_fd_disarm(struct tevent_fd *fde)
581 : {
582 1068491 : if (fde->event_ctx != NULL) {
583 1068491 : tevent_trace_fd_callback(fde->event_ctx, fde,
584 : TEVENT_EVENT_TRACE_DETACH);
585 1068491 : DLIST_REMOVE(fde->event_ctx->fd_events, fde);
586 1068491 : fde->event_ctx = NULL;
587 : }
588 1068491 : tevent_common_fd_mpx_reinit(fde);
589 1068491 : fde->wrapper = NULL;
590 1068491 : }
591 :
592 : /*
593 : * tevent_common_fd_mpx_primary() returns the fde that is responsible
594 : * for the low level state.
595 : *
596 : * By default (when there's no multiplexing) it just returns 'any_fde'.
597 : *
598 : * Note it always returns a valid pointer.
599 : */
600 : static inline
601 390471412 : struct tevent_fd *tevent_common_fd_mpx_primary(struct tevent_fd *any_fde)
602 : {
603 390552333 : struct tevent_fd *primary = NULL;
604 :
605 374816883 : if (any_fde->mpx.primary != NULL) {
606 70454 : primary = any_fde->mpx.primary;
607 : } else {
608 374447651 : primary = any_fde;
609 : }
610 :
611 374816883 : return primary;
612 : }
613 :
614 : /*
615 : * tevent_common_fd_mpx_update_flags() needs to be called
616 : * if update_fde->flags has changed. It is needed in
617 : * order to let tevent_common_fd_mpx_flags() return a valid
618 : * result.
619 : */
620 : static inline
621 21206711 : void tevent_common_fd_mpx_update_flags(struct tevent_fd *update_fde)
622 : {
623 21204825 : struct tevent_fd *primary = tevent_common_fd_mpx_primary(update_fde);
624 21206711 : struct tevent_fd_mpx *mpx = NULL;
625 21206711 : uint16_t new_total_flags = 0;
626 :
627 21206711 : if (!primary->mpx.has_mpx) {
628 21133803 : primary->mpx.total_flags = primary->flags;
629 21133803 : return;
630 : }
631 :
632 185161 : for (mpx = primary->mpx.list; mpx != NULL; mpx = mpx->next) {
633 112253 : struct tevent_fd *mpx_fde = mpx->fde;
634 : /* we don't care that mpx_fde might be == primary */
635 112253 : new_total_flags |= mpx_fde->flags;
636 : }
637 :
638 72908 : primary->mpx.total_flags = new_total_flags;
639 : }
640 :
641 : /*
642 : * tevent_common_fd_mpx_flags() return the effective flags
643 : * (TEVEND_FD_*) of the primary fde and all multiplexed fdes.
644 : *
645 : * Valid after tevent_common_fd_mpx_update_flags() was called
646 : */
647 : static inline
648 197073579 : uint16_t tevent_common_fd_mpx_flags(struct tevent_fd *any_fde)
649 : {
650 197071693 : struct tevent_fd *primary = tevent_common_fd_mpx_primary(any_fde);
651 :
652 197071557 : return primary->mpx.total_flags;
653 : }
654 :
655 : /*
656 : * tevent_common_fd_mpx_clear_writeable() clears TEVENT_FD_WRITE
657 : * from all fdes belonging together.
658 : */
659 : static inline
660 0 : void tevent_common_fd_mpx_clear_writeable(struct tevent_fd *any_fde)
661 : {
662 0 : struct tevent_fd *primary = tevent_common_fd_mpx_primary(any_fde);
663 0 : struct tevent_fd_mpx *mpx = NULL;
664 :
665 0 : primary->flags &= ~TEVENT_FD_WRITE;
666 :
667 0 : for (mpx = primary->mpx.list; mpx != NULL; mpx = mpx->next) {
668 0 : struct tevent_fd *mpx_fde = mpx->fde;
669 : /* we don't care that mpx_fde might be == primary */
670 0 : mpx_fde->flags &= ~TEVENT_FD_WRITE;
671 : }
672 :
673 0 : primary->mpx.total_flags &= ~TEVENT_FD_WRITE;
674 0 : }
675 :
676 : /*
677 : * tevent_common_fd_mpx_additional_flags() modifies
678 : * fde->additional_flags for all fdes belonging together.
679 : */
680 : static inline
681 67843956 : void tevent_common_fd_mpx_additional_flags(struct tevent_fd *any_fde,
682 : uint64_t clear_flags,
683 : uint64_t add_flags)
684 : {
685 67763961 : struct tevent_fd *primary = tevent_common_fd_mpx_primary(any_fde);
686 67843956 : struct tevent_fd_mpx *mpx = NULL;
687 :
688 67843956 : primary->additional_flags &= ~clear_flags;
689 67843956 : primary->additional_flags |= add_flags;
690 :
691 68200926 : for (mpx = primary->mpx.list; mpx != NULL; mpx = mpx->next) {
692 356970 : struct tevent_fd *mpx_fde = mpx->fde;
693 : /* we don't care that mpx_fde might be == primary */
694 356970 : mpx_fde->additional_flags &= ~clear_flags;
695 356970 : mpx_fde->additional_flags |= add_flags;
696 : }
697 67641660 : }
698 :
699 : /*
700 : * tevent_common_fd_mpx_disarm_all() detaches
701 : * all fdes currently belonging together from each other
702 : * and also from the tevent_context, which means their
703 : * handler will never be called again.
704 : */
705 : static inline
706 1 : void tevent_common_fd_mpx_disarm_all(struct tevent_fd *any_fde)
707 : {
708 1 : struct tevent_fd *primary = tevent_common_fd_mpx_primary(any_fde);
709 1 : struct tevent_fd_mpx *mpx = NULL, *next = NULL;
710 :
711 1 : for (mpx = primary->mpx.list; mpx != NULL; mpx = next) {
712 0 : struct tevent_fd *mpx_fde = mpx->fde;
713 :
714 0 : next = mpx->next;
715 0 : DLIST_REMOVE(primary->mpx.list, mpx);
716 :
717 0 : if (mpx_fde == primary) {
718 : /* primary is handled below */
719 0 : continue;
720 : }
721 :
722 0 : tevent_common_fd_disarm(mpx_fde);
723 : }
724 :
725 1 : tevent_common_fd_disarm(primary);
726 1 : }
727 :
728 : /*
729 : * tevent_common_fd_mpx_select() selects the handler that
730 : * should be called for the given low level event.
731 : *
732 : * Note it's important to pass the primary fde!
733 : */
734 : static inline
735 153883944 : struct tevent_fd *tevent_common_fd_mpx_select(struct tevent_fd *primary,
736 : uint16_t flags,
737 : bool got_error)
738 : {
739 153883944 : struct tevent_fd_mpx *mpx = NULL;
740 153883944 : struct tevent_fd *selected = NULL;
741 :
742 : /* optimize for the single event case. */
743 153883944 : if (!primary->mpx.has_mpx) {
744 : /*
745 : * If we got an error, we won't report it if
746 : * the caller only asked for TEVENT_FD_WRITE.
747 : */
748 143891558 : if (got_error &&
749 10003547 : !(primary->flags & (TEVENT_FD_READ|TEVENT_FD_ERROR)))
750 : {
751 0 : return NULL;
752 : }
753 :
754 143891558 : if (flags & primary->flags) {
755 138044572 : return primary;
756 : }
757 :
758 0 : return NULL;
759 : }
760 :
761 23912528 : for (mpx = primary->mpx.list; mpx != NULL; mpx = mpx->next) {
762 23912528 : struct tevent_fd *mpx_fde = mpx->fde;
763 :
764 : /*
765 : * If we got an error, we won't report it if
766 : * the caller only asked for TEVENT_FD_WRITE.
767 : */
768 23912528 : if (got_error &&
769 5330 : !(mpx_fde->flags & (TEVENT_FD_READ|TEVENT_FD_ERROR)))
770 : {
771 3552 : continue;
772 : }
773 :
774 23908976 : if (flags & mpx_fde->flags) {
775 585041 : selected = mpx_fde;
776 585041 : break;
777 : }
778 : }
779 :
780 9992386 : if (selected == NULL) {
781 0 : return NULL;
782 : }
783 :
784 : /*
785 : * Maintain fairness and demote the just selected fde
786 : */
787 9992386 : DLIST_DEMOTE_SHORT(primary->mpx.list, &selected->mpx);
788 585041 : return selected;
789 : }
790 :
791 : /*
792 : * tevent_common_fd_mpx_add() searches for an existing (active) fde
793 : * for the same low level fd and adds the given 'add_fde'
794 : * as multiplexed to the found fde.
795 : *
796 : * If another fde was found it is returned.
797 : * NULL is returned to indicate no match
798 : */
799 : static inline
800 37687 : struct tevent_fd *tevent_common_fd_mpx_add(struct tevent_fd *add_fde)
801 : {
802 37687 : struct tevent_context *ev = add_fde->event_ctx;
803 37687 : struct tevent_fd *add_primary = tevent_common_fd_mpx_primary(add_fde);
804 37687 : uint16_t add_flags = tevent_common_fd_mpx_flags(add_primary);
805 37687 : struct tevent_fd *mpx_fde = NULL;
806 37687 : struct tevent_fd *mpx_primary = NULL;
807 37687 : struct tevent_fd_mpx *tmp = NULL;
808 37687 : struct tevent_fd_mpx *next = NULL;
809 :
810 : /* Find the existing fde that caused the EEXIST error. */
811 75659 : for (mpx_fde = ev->fd_events; mpx_fde; mpx_fde = mpx_fde->next) {
812 75659 : mpx_primary = tevent_common_fd_mpx_primary(mpx_fde);
813 :
814 75659 : if (mpx_primary->fd != add_primary->fd) {
815 185 : mpx_primary = NULL;
816 185 : continue;
817 : }
818 :
819 75474 : if (mpx_primary == add_primary) {
820 37685 : mpx_primary = NULL;
821 37685 : continue;
822 : }
823 :
824 74516 : if (add_flags != 0 &&
825 37789 : tevent_common_fd_mpx_flags(mpx_primary) == 0)
826 : {
827 : /*
828 : * only active events should match
829 : */
830 102 : mpx_primary = NULL;
831 102 : continue;
832 : }
833 36727 : break;
834 : }
835 37687 : if (mpx_primary == NULL) {
836 0 : tevent_debug(ev, TEVENT_DEBUG_FATAL,
837 : "can't find multiplex fde for fd[%d]",
838 : add_fde->fd);
839 0 : return NULL;
840 : }
841 :
842 : /*
843 : * If add_primary is not in it's own list
844 : * we add it in order to simplify the loop below.
845 : */
846 :
847 37687 : if (add_primary->mpx.prev == NULL && add_primary->mpx.next == NULL) {
848 37687 : DLIST_ADD_END(add_primary->mpx.list, &add_primary->mpx);
849 : }
850 :
851 : /*
852 : * Add the new mpx_primary to its own list before others,
853 : * if it is not already added.
854 : */
855 37687 : if (mpx_primary->mpx.prev == NULL && mpx_primary->mpx.next == NULL) {
856 30964 : DLIST_ADD_END(mpx_primary->mpx.list, &mpx_primary->mpx);
857 : }
858 :
859 : /*
860 : * Now we clear all entries and move them to the
861 : * new primary
862 : */
863 75374 : for (tmp = add_primary->mpx.list; tmp != NULL; tmp = next) {
864 37687 : struct tevent_fd *tmp_fde = tmp->fde;
865 :
866 37687 : next = tmp->next;
867 :
868 37687 : DLIST_REMOVE(add_primary->mpx.list, tmp);
869 37687 : tevent_common_fd_mpx_reinit(tmp_fde);
870 37687 : DLIST_ADD_END(mpx_primary->mpx.list, tmp);
871 37687 : tmp->primary = mpx_primary;
872 37687 : tmp->has_mpx = true;
873 : }
874 :
875 37687 : mpx_primary->mpx.has_mpx = true;
876 37687 : return mpx_primary;
877 : }
878 :
879 : /*
880 : * tevent_common_fd_mpx_update() calls tevent_common_fd_mpx_update_flags()
881 : * and compares tevent_common_fd_mpx_flags() before and after.
882 : *
883 : * When there's a low level update needed the primary fde,
884 : * otherwise NULL is returned.
885 : */
886 : static inline
887 75340 : struct tevent_fd *tevent_common_fd_mpx_update(struct tevent_fd *update_fde)
888 : {
889 75340 : struct tevent_fd *primary = tevent_common_fd_mpx_primary(update_fde);
890 1886 : uint16_t old_total_flags;
891 1886 : uint16_t new_total_flags;
892 :
893 75340 : old_total_flags = primary->mpx.total_flags;
894 75340 : tevent_common_fd_mpx_update_flags(primary);
895 75340 : new_total_flags = primary->mpx.total_flags;
896 :
897 75340 : if (old_total_flags == new_total_flags) {
898 : /* No update needed */
899 36 : return NULL;
900 : }
901 :
902 73454 : return primary;
903 : }
904 :
905 : /*
906 : * tevent_common_fd_mpx_remove() removes remove_fde from its possible primary,
907 : * if remove_fde is a primary itself, a new primary is selected.
908 : *
909 : * The remaining primary or NULL is returned.
910 : */
911 : static inline
912 15003683 : struct tevent_fd *tevent_common_fd_mpx_remove(struct tevent_fd *remove_fde)
913 : {
914 15003683 : struct tevent_fd *primary = tevent_common_fd_mpx_primary(remove_fde);
915 15003683 : struct tevent_fd_mpx *mpx = NULL, *next = NULL;
916 15003683 : struct tevent_fd *new_primary = NULL;
917 :
918 15003683 : DLIST_REMOVE(primary->mpx.list, &remove_fde->mpx);
919 :
920 15003683 : if (primary != remove_fde) {
921 35019 : tevent_common_fd_mpx_reinit(remove_fde);
922 35019 : return primary;
923 : }
924 :
925 14971316 : for (mpx = primary->mpx.list; mpx != NULL; mpx = next) {
926 2652 : struct tevent_fd *mpx_fde = mpx->fde;
927 :
928 2652 : next = mpx->next;
929 :
930 2652 : DLIST_REMOVE(primary->mpx.list, &mpx_fde->mpx);
931 2652 : tevent_common_fd_mpx_reinit(mpx_fde);
932 2652 : mpx->primary = new_primary;
933 2652 : if (new_primary == NULL) {
934 : /*
935 : * Select the first one as the new primary and add
936 : * itself as the first mpx-fde to the mpx list
937 : */
938 2634 : new_primary = mpx_fde;
939 2634 : DLIST_ADD(new_primary->mpx.list, &mpx_fde->mpx);
940 2634 : continue;
941 : }
942 18 : new_primary->mpx.has_mpx = true;
943 18 : mpx->has_mpx = true;
944 18 : DLIST_ADD_END(new_primary->mpx.list, &mpx_fde->mpx);
945 : }
946 :
947 : /* primary == remove_fde */
948 14968664 : tevent_common_fd_mpx_reinit(primary);
949 14968664 : return new_primary;
950 : }
|