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
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/>.
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.
39 * @brief Completion function
40 * Completion function, to be filled by the API user
44 * @brief Private data for the completion function
48 * @brief The completion function name, for flow tracing.
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.
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
69 tevent_req_print_fn private_print
;
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
79 tevent_req_cancel_fn fn
;
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.
91 tevent_req_cleanup_fn fn
;
93 enum tevent_req_state state
;
97 * @brief Internal state of the request
99 * Callers should only access this via functions and never directly.
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()
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.
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
;
185 struct tevent_req_profile
{
186 struct tevent_req_profile
*prev
, *next
;
187 struct tevent_req_profile
*parent
;
188 const char *req_name
;
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
;
196 struct tevent_req_profile
*subprofiles
;
200 struct tevent_fd
*prev
, *next
;
201 struct tevent_context
*event_ctx
;
202 struct tevent_wrapper_glue
*wrapper
;
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 */
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 */
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
;
229 struct tevent_timer
{
230 struct tevent_timer
*prev
, *next
;
231 struct tevent_context
*event_ctx
;
232 struct tevent_wrapper_glue
*wrapper
;
235 struct timeval next_event
;
236 tevent_timer_handler_t handler
;
237 /* this is private for the specific handler */
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 */
248 struct tevent_immediate
{
249 struct tevent_immediate
*prev
, *next
;
250 struct tevent_context
*event_ctx
;
251 struct tevent_wrapper_glue
*wrapper
;
254 struct tevent_context
*detach_ev_ctx
;
255 tevent_immediate_handler_t handler
;
256 /* this is private for the specific handler */
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 */
269 struct tevent_signal
{
270 struct tevent_signal
*prev
, *next
;
271 struct tevent_context
*event_ctx
;
272 struct tevent_wrapper_glue
*wrapper
;
277 tevent_signal_handler_t handler
;
278 /* this is private for the specific handler */
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 */
289 struct tevent_threaded_context
{
290 struct tevent_threaded_context
*next
, *prev
;
293 pthread_mutex_t event_ctx_mutex
;
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);
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__); \
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
359 /* debugging operations */
360 struct tevent_debug_ops debug_ops
;
362 /* info about the nesting status */
366 tevent_nesting_hook hook_fn
;
372 tevent_trace_callback_t callback
;
377 tevent_trace_fd_callback_t callback
;
382 tevent_trace_signal_callback_t callback
;
387 tevent_trace_timer_callback_t callback
;
392 tevent_trace_immediate_callback_t callback
;
397 tevent_trace_queue_callback_t callback
;
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
;
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
;
422 struct tevent_context
*prev
, *next
;
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
{
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
,
443 tevent_fd_handler_t handler
,
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
,
454 struct tevent_timer
*tevent_common_add_timer(struct tevent_context
*ev
,
456 struct timeval next_event
,
457 tevent_timer_handler_t handler
,
459 const char *handler_name
,
460 const char *location
);
461 struct tevent_timer
*tevent_common_add_timer_v2(struct tevent_context
*ev
,
463 struct timeval next_event
,
464 tevent_timer_handler_t handler
,
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
,
473 void tevent_common_schedule_immediate(struct tevent_immediate
*im
,
474 struct tevent_context
*ev
,
475 tevent_immediate_handler_t handler
,
477 const char *handler_name
,
478 const char *location
);
479 int tevent_common_invoke_immediate_handler(struct tevent_immediate
*im
,
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
,
493 tevent_signal_handler_t handler
,
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
,
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
;
513 const struct tevent_wrapper_ops
*ops
;
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);
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
,
534 static inline void tevent_thread_call_depth_notify(
535 enum tevent_thread_call_depth_cmd cmd
,
536 struct tevent_req
*req
,
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
,
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
);
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.
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
;
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
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
;
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
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.
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.
681 void tevent_common_fd_mpx_additional_flags(struct tevent_fd
*any_fde
,
682 uint64_t clear_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.
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
;
715 DLIST_REMOVE(primary
->mpx
.list
, mpx
);
717 if (mpx_fde
== primary
) {
718 /* primary is handled below */
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!
735 struct tevent_fd
*tevent_common_fd_mpx_select(struct tevent_fd
*primary
,
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.
749 !(primary
->flags
& (TEVENT_FD_READ
|TEVENT_FD_ERROR
)))
754 if (flags
& primary
->flags
) {
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.
769 !(mpx_fde
->flags
& (TEVENT_FD_READ
|TEVENT_FD_ERROR
)))
774 if (flags
& mpx_fde
->flags
) {
780 if (selected
== NULL
) {
785 * Maintain fairness and demote the just selected fde
787 DLIST_DEMOTE_SHORT(primary
->mpx
.list
, &selected
->mpx
);
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
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
) {
819 if (mpx_primary
== add_primary
) {
824 if (add_flags
!= 0 &&
825 tevent_common_fd_mpx_flags(mpx_primary
) == 0)
828 * only active events should match
835 if (mpx_primary
== NULL
) {
836 tevent_debug(ev
, TEVENT_DEBUG_FATAL
,
837 "can't find multiplex fde for fd[%d]",
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
863 for (tmp
= add_primary
->mpx
.list
; tmp
!= NULL
; tmp
= next
) {
864 struct tevent_fd
*tmp_fde
= tmp
->fde
;
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
;
875 mpx_primary
->mpx
.has_mpx
= true;
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.
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 */
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.
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
);
925 for (mpx
= primary
->mpx
.list
; mpx
!= NULL
; mpx
= next
) {
926 struct tevent_fd
*mpx_fde
= mpx
->fde
;
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
);
942 new_primary
->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
);