selftest: Move MIT Kerberos knownfails to separate files in their own directory
[Samba.git] / lib / tevent / tevent_internal.h
blob75ae114e35f8246499d9eedbfa9484b98157f6d1
1 /*
2 Unix SMB/CIFS implementation.
4 generalised event loop handling
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.
10 Copyright (C) Stefan Metzmacher 2005-2009
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
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.
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.
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/>.
30 struct tevent_req {
31 /**
32 * @brief What to do on completion
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.
37 struct {
38 /**
39 * @brief Completion function
40 * Completion function, to be filled by the API user
42 tevent_req_fn fn;
43 /**
44 * @brief Private data for the completion function
46 void *private_data;
47 /**
48 * @brief The completion function name, for flow tracing.
50 const char *fn_name;
51 } async;
53 /**
54 * @brief Private state pointer for the actual implementation
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.
60 void *data;
62 /**
63 * @brief A function to overwrite the default print function
65 * The implementation doing the work may want to implement a
66 * custom function to print the text representation of the async
67 * request.
69 tevent_req_print_fn private_print;
71 /**
72 * @brief A function to cancel the request
74 * The implementation might want to set a function
75 * that is called when the tevent_req_cancel() function
76 * was called.
78 struct {
79 tevent_req_cancel_fn fn;
80 const char *fn_name;
81 } private_cancel;
83 /**
84 * @brief A function to cleanup the request
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.
90 struct {
91 tevent_req_cleanup_fn fn;
92 const char *fn_name;
93 enum tevent_req_state state;
94 } private_cleanup;
96 /**
97 * @brief Internal state of the request
99 * Callers should only access this via functions and never directly.
101 struct {
103 * @brief The talloc type of the data pointer
105 * This is filled by the tevent_req_create() macro.
107 * This for debugging only.
109 const char *private_type;
112 * @brief The location where the request was created
114 * This uses the __location__ macro via the tevent_req_create()
115 * macro.
117 * This for debugging only.
119 const char *create_location;
122 * @brief The location where the request was finished
124 * This uses the __location__ macro via the tevent_req_done(),
125 * tevent_req_error() or tevent_req_nomem() macro.
127 * This for debugging only.
129 const char *finish_location;
132 * @brief The location where the request was canceled
134 * This uses the __location__ macro via the
135 * tevent_req_cancel() macro.
137 * This for debugging only.
139 const char *cancel_location;
142 * @brief The external state - will be queried by the caller
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.
148 enum tevent_req_state state;
151 * @brief status code when finished
153 * This status can be queried in the async completion function. It
154 * will be set to 0 when everything went fine.
156 uint64_t error;
159 * @brief the immediate event used by tevent_req_post
162 struct tevent_immediate *trigger;
165 * @brief An event context which will be used to
166 * defer the _tevent_req_notify_callback().
168 struct tevent_context *defer_callback_ev;
171 * @brief the timer event if tevent_req_set_endtime was used
174 struct tevent_timer *timer;
177 * @brief The place where profiling data is kept
179 struct tevent_req_profile *profile;
181 size_t call_depth;
182 } internal;
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;
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;
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;
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;
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;
289 struct tevent_threaded_context {
290 struct tevent_threaded_context *next, *prev;
292 #ifdef HAVE_PTHREAD
293 pthread_mutex_t event_ctx_mutex;
294 #endif
295 struct tevent_context *event_ctx;
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;
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)) \
311 tevent_debug((__ev), (__level), (__fmt), __VA_ARGS__); \
313 } while(0)
315 void tevent_abort(struct tevent_context *ev, const char *reason);
317 void tevent_common_check_double_free(TALLOC_CTX *ptr, const char *reason);
319 struct tevent_context {
320 /* the specific events implementation */
321 const struct tevent_ops *ops;
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.
330 /* list of signal events - used by common code */
331 struct tevent_signal *signal_events;
333 /* List of threaded job indicators */
334 struct tevent_threaded_context *threaded_contexts;
336 /* list of immediate events - used by common code */
337 struct tevent_immediate *immediate_events;
339 /* list of fd events - used by common code */
340 struct tevent_fd *fd_events;
342 /* list of timed events - used by common code */
343 struct tevent_timer *timer_events;
345 /* List of scheduled immediates */
346 pthread_mutex_t scheduled_mutex;
347 struct tevent_immediate *scheduled_immediates;
349 /* this is private for the events_ops implementation */
350 void *additional_data;
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
359 /* debugging operations */
360 struct tevent_debug_ops debug_ops;
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;
370 struct {
371 struct {
372 tevent_trace_callback_t callback;
373 void *private_data;
374 } point;
376 struct {
377 tevent_trace_fd_callback_t callback;
378 void *private_data;
379 } fde;
381 struct {
382 tevent_trace_signal_callback_t callback;
383 void *private_data;
384 } se;
386 struct {
387 tevent_trace_timer_callback_t callback;
388 void *private_data;
389 } te;
391 struct {
392 tevent_trace_immediate_callback_t callback;
393 void *private_data;
394 } im;
396 struct {
397 tevent_trace_queue_callback_t callback;
398 void *private_data;
399 } qe;
400 } tracing;
402 struct {
404 * This is used on the main event context
406 struct tevent_wrapper_glue *list;
409 * This is used on the wrapper event context
411 struct tevent_wrapper_glue *glue;
412 } wrapper;
415 * an optimization pointer into timer_events
416 * used by used by common code via
417 * tevent_common_add_timer_v2()
419 struct tevent_timer *last_zero_timer;
421 #ifdef HAVE_PTHREAD
422 struct tevent_context *prev, *next;
423 #endif
426 int tevent_common_context_destructor(struct tevent_context *ev);
427 int tevent_common_loop_wait(struct tevent_context *ev,
428 const char *location);
430 struct tevent_common_fd_buf {
431 char buf[128];
434 const char *tevent_common_fd_str(struct tevent_common_fd_buf *buf,
435 const char *description,
436 const struct tevent_fd *fde);
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);
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);
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);
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);
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);
503 struct tevent_context *tevent_wrapper_main_ev(struct tevent_context *ev);
505 struct tevent_wrapper_ops;
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;
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);
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
534 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)
540 if (tevent_thread_call_depth_state_g.cb != NULL) {
541 tevent_thread_call_depth_state_g.cb(
542 tevent_thread_call_depth_state_g.cb_private,
543 cmd,
544 req,
545 depth,
546 fname);
550 void tevent_trace_point_callback(struct tevent_context *ev,
551 enum tevent_trace_point);
553 void tevent_trace_fd_callback(struct tevent_context *ev,
554 struct tevent_fd *fde,
555 enum tevent_event_trace_point);
557 void tevent_trace_signal_callback(struct tevent_context *ev,
558 struct tevent_signal *se,
559 enum tevent_event_trace_point);
561 void tevent_trace_timer_callback(struct tevent_context *ev,
562 struct tevent_timer *te,
563 enum tevent_event_trace_point);
565 void tevent_trace_immediate_callback(struct tevent_context *ev,
566 struct tevent_immediate *im,
567 enum tevent_event_trace_point);
569 void tevent_trace_queue_callback(struct tevent_context *ev,
570 struct tevent_queue_entry *qe,
571 enum tevent_event_trace_point);
573 #include "tevent_dlinklist.h"
575 static inline void tevent_common_fd_mpx_reinit(struct tevent_fd *fde)
577 fde->mpx = (struct tevent_fd_mpx) { .fde = fde, };
580 static inline void tevent_common_fd_disarm(struct tevent_fd *fde)
582 if (fde->event_ctx != NULL) {
583 tevent_trace_fd_callback(fde->event_ctx, fde,
584 TEVENT_EVENT_TRACE_DETACH);
585 DLIST_REMOVE(fde->event_ctx->fd_events, fde);
586 fde->event_ctx = NULL;
588 tevent_common_fd_mpx_reinit(fde);
589 fde->wrapper = NULL;
593 * tevent_common_fd_mpx_primary() returns the fde that is responsible
594 * for the low level state.
596 * By default (when there's no multiplexing) it just returns 'any_fde'.
598 * Note it always returns a valid pointer.
600 static inline
601 struct tevent_fd *tevent_common_fd_mpx_primary(struct tevent_fd *any_fde)
603 struct tevent_fd *primary = NULL;
605 if (any_fde->mpx.primary != NULL) {
606 primary = any_fde->mpx.primary;
607 } else {
608 primary = any_fde;
611 return primary;
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.
620 static inline
621 void tevent_common_fd_mpx_update_flags(struct tevent_fd *update_fde)
623 struct tevent_fd *primary = tevent_common_fd_mpx_primary(update_fde);
624 struct tevent_fd_mpx *mpx = NULL;
625 uint16_t new_total_flags = 0;
627 if (!primary->mpx.has_mpx) {
628 primary->mpx.total_flags = primary->flags;
629 return;
632 for (mpx = primary->mpx.list; mpx != NULL; mpx = mpx->next) {
633 struct tevent_fd *mpx_fde = mpx->fde;
634 /* we don't care that mpx_fde might be == primary */
635 new_total_flags |= mpx_fde->flags;
638 primary->mpx.total_flags = new_total_flags;
642 * tevent_common_fd_mpx_flags() return the effective flags
643 * (TEVEND_FD_*) of the primary fde and all multiplexed fdes.
645 * Valid after tevent_common_fd_mpx_update_flags() was called
647 static inline
648 uint16_t tevent_common_fd_mpx_flags(struct tevent_fd *any_fde)
650 struct tevent_fd *primary = tevent_common_fd_mpx_primary(any_fde);
652 return primary->mpx.total_flags;
656 * tevent_common_fd_mpx_clear_writeable() clears TEVENT_FD_WRITE
657 * from all fdes belonging together.
659 static inline
660 void tevent_common_fd_mpx_clear_writeable(struct tevent_fd *any_fde)
662 struct tevent_fd *primary = tevent_common_fd_mpx_primary(any_fde);
663 struct tevent_fd_mpx *mpx = NULL;
665 primary->flags &= ~TEVENT_FD_WRITE;
667 for (mpx = primary->mpx.list; mpx != NULL; mpx = mpx->next) {
668 struct tevent_fd *mpx_fde = mpx->fde;
669 /* we don't care that mpx_fde might be == primary */
670 mpx_fde->flags &= ~TEVENT_FD_WRITE;
673 primary->mpx.total_flags &= ~TEVENT_FD_WRITE;
677 * tevent_common_fd_mpx_additional_flags() modifies
678 * fde->additional_flags for all fdes belonging together.
680 static inline
681 void tevent_common_fd_mpx_additional_flags(struct tevent_fd *any_fde,
682 uint64_t clear_flags,
683 uint64_t add_flags)
685 struct tevent_fd *primary = tevent_common_fd_mpx_primary(any_fde);
686 struct tevent_fd_mpx *mpx = NULL;
688 primary->additional_flags &= ~clear_flags;
689 primary->additional_flags |= add_flags;
691 for (mpx = primary->mpx.list; mpx != NULL; mpx = mpx->next) {
692 struct tevent_fd *mpx_fde = mpx->fde;
693 /* we don't care that mpx_fde might be == primary */
694 mpx_fde->additional_flags &= ~clear_flags;
695 mpx_fde->additional_flags |= add_flags;
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.
705 static inline
706 void tevent_common_fd_mpx_disarm_all(struct tevent_fd *any_fde)
708 struct tevent_fd *primary = tevent_common_fd_mpx_primary(any_fde);
709 struct tevent_fd_mpx *mpx = NULL, *next = NULL;
711 for (mpx = primary->mpx.list; mpx != NULL; mpx = next) {
712 struct tevent_fd *mpx_fde = mpx->fde;
714 next = mpx->next;
715 DLIST_REMOVE(primary->mpx.list, mpx);
717 if (mpx_fde == primary) {
718 /* primary is handled below */
719 continue;
722 tevent_common_fd_disarm(mpx_fde);
725 tevent_common_fd_disarm(primary);
729 * tevent_common_fd_mpx_select() selects the handler that
730 * should be called for the given low level event.
732 * Note it's important to pass the primary fde!
734 static inline
735 struct tevent_fd *tevent_common_fd_mpx_select(struct tevent_fd *primary,
736 uint16_t flags,
737 bool got_error)
739 struct tevent_fd_mpx *mpx = NULL;
740 struct tevent_fd *selected = NULL;
742 /* optimize for the single event case. */
743 if (!primary->mpx.has_mpx) {
745 * If we got an error, we won't report it if
746 * the caller only asked for TEVENT_FD_WRITE.
748 if (got_error &&
749 !(primary->flags & (TEVENT_FD_READ|TEVENT_FD_ERROR)))
751 return NULL;
754 if (flags & primary->flags) {
755 return primary;
758 return NULL;
761 for (mpx = primary->mpx.list; mpx != NULL; mpx = mpx->next) {
762 struct tevent_fd *mpx_fde = mpx->fde;
765 * If we got an error, we won't report it if
766 * the caller only asked for TEVENT_FD_WRITE.
768 if (got_error &&
769 !(mpx_fde->flags & (TEVENT_FD_READ|TEVENT_FD_ERROR)))
771 continue;
774 if (flags & mpx_fde->flags) {
775 selected = mpx_fde;
776 break;
780 if (selected == NULL) {
781 return NULL;
785 * Maintain fairness and demote the just selected fde
787 DLIST_DEMOTE_SHORT(primary->mpx.list, &selected->mpx);
788 return selected;
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.
796 * If another fde was found it is returned.
797 * NULL is returned to indicate no match
799 static inline
800 struct tevent_fd *tevent_common_fd_mpx_add(struct tevent_fd *add_fde)
802 struct tevent_context *ev = add_fde->event_ctx;
803 struct tevent_fd *add_primary = tevent_common_fd_mpx_primary(add_fde);
804 uint16_t add_flags = tevent_common_fd_mpx_flags(add_primary);
805 struct tevent_fd *mpx_fde = NULL;
806 struct tevent_fd *mpx_primary = NULL;
807 struct tevent_fd_mpx *tmp = NULL;
808 struct tevent_fd_mpx *next = NULL;
810 /* Find the existing fde that caused the EEXIST error. */
811 for (mpx_fde = ev->fd_events; mpx_fde; mpx_fde = mpx_fde->next) {
812 mpx_primary = tevent_common_fd_mpx_primary(mpx_fde);
814 if (mpx_primary->fd != add_primary->fd) {
815 mpx_primary = NULL;
816 continue;
819 if (mpx_primary == add_primary) {
820 mpx_primary = NULL;
821 continue;
824 if (add_flags != 0 &&
825 tevent_common_fd_mpx_flags(mpx_primary) == 0)
828 * only active events should match
830 mpx_primary = NULL;
831 continue;
833 break;
835 if (mpx_primary == NULL) {
836 tevent_debug(ev, TEVENT_DEBUG_FATAL,
837 "can't find multiplex fde for fd[%d]",
838 add_fde->fd);
839 return NULL;
843 * If add_primary is not in it's own list
844 * we add it in order to simplify the loop below.
847 if (add_primary->mpx.prev == NULL && add_primary->mpx.next == NULL) {
848 DLIST_ADD_END(add_primary->mpx.list, &add_primary->mpx);
852 * Add the new mpx_primary to its own list before others,
853 * if it is not already added.
855 if (mpx_primary->mpx.prev == NULL && mpx_primary->mpx.next == NULL) {
856 DLIST_ADD_END(mpx_primary->mpx.list, &mpx_primary->mpx);
860 * Now we clear all entries and move them to the
861 * new primary
863 for (tmp = add_primary->mpx.list; tmp != NULL; tmp = next) {
864 struct tevent_fd *tmp_fde = tmp->fde;
866 next = tmp->next;
868 DLIST_REMOVE(add_primary->mpx.list, tmp);
869 tevent_common_fd_mpx_reinit(tmp_fde);
870 DLIST_ADD_END(mpx_primary->mpx.list, tmp);
871 tmp->primary = mpx_primary;
872 tmp->has_mpx = true;
875 mpx_primary->mpx.has_mpx = true;
876 return mpx_primary;
880 * tevent_common_fd_mpx_update() calls tevent_common_fd_mpx_update_flags()
881 * and compares tevent_common_fd_mpx_flags() before and after.
883 * When there's a low level update needed the primary fde,
884 * otherwise NULL is returned.
886 static inline
887 struct tevent_fd *tevent_common_fd_mpx_update(struct tevent_fd *update_fde)
889 struct tevent_fd *primary = tevent_common_fd_mpx_primary(update_fde);
890 uint16_t old_total_flags;
891 uint16_t new_total_flags;
893 old_total_flags = primary->mpx.total_flags;
894 tevent_common_fd_mpx_update_flags(primary);
895 new_total_flags = primary->mpx.total_flags;
897 if (old_total_flags == new_total_flags) {
898 /* No update needed */
899 return NULL;
902 return primary;
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.
909 * The remaining primary or NULL is returned.
911 static inline
912 struct tevent_fd *tevent_common_fd_mpx_remove(struct tevent_fd *remove_fde)
914 struct tevent_fd *primary = tevent_common_fd_mpx_primary(remove_fde);
915 struct tevent_fd_mpx *mpx = NULL, *next = NULL;
916 struct tevent_fd *new_primary = NULL;
918 DLIST_REMOVE(primary->mpx.list, &remove_fde->mpx);
920 if (primary != remove_fde) {
921 tevent_common_fd_mpx_reinit(remove_fde);
922 return primary;
925 for (mpx = primary->mpx.list; mpx != NULL; mpx = next) {
926 struct tevent_fd *mpx_fde = mpx->fde;
928 next = mpx->next;
930 DLIST_REMOVE(primary->mpx.list, &mpx_fde->mpx);
931 tevent_common_fd_mpx_reinit(mpx_fde);
932 mpx->primary = new_primary;
933 if (new_primary == NULL) {
935 * Select the first one as the new primary and add
936 * itself as the first mpx-fde to the mpx list
938 new_primary = mpx_fde;
939 DLIST_ADD(new_primary->mpx.list, &mpx_fde->mpx);
940 continue;
942 new_primary->mpx.has_mpx = true;
943 mpx->has_mpx = true;
944 DLIST_ADD_END(new_primary->mpx.list, &mpx_fde->mpx);
947 /* primary == remove_fde */
948 tevent_common_fd_mpx_reinit(primary);
949 return new_primary;