From e5f7e040dc911d2cea5edf1254057c140cdfff07 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 16 Sep 2020 13:20:19 +0200 Subject: [PATCH] loop: simplify before and after events Because the signal can't be removed from the callback we can simply iterate backwards and then forwards. The first added hook (the unlock/lock pair) is called last before going into the poll and first when leaving. This executes all other callbacks inside a locked situation. And removing them with the lock is not going to cause problems. --- spa/include/spa/support/loop.h | 21 ++++++++++++++++++--- spa/include/spa/utils/list.h | 8 ++++++++ spa/plugins/support/loop.c | 15 ++------------- 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/spa/include/spa/support/loop.h b/spa/include/spa/support/loop.h index 575dd2932..34ddaa89e 100644 --- a/spa/include/spa/support/loop.h +++ b/spa/include/spa/support/loop.h @@ -113,7 +113,9 @@ struct spa_loop_methods { #define spa_loop_invoke(l,...) spa_loop_method(l,invoke,0,##__VA_ARGS__) -/** Control hooks */ +/** Control hooks. These hooks can't be removed from their + * callbacks and must be removed from a safe place (when the loop + * is not running or when it is locked). */ struct spa_loop_control_hooks { #define SPA_VERSION_LOOP_CONTROL_HOOKS 0 uint32_t version; @@ -125,8 +127,21 @@ struct spa_loop_control_hooks { void (*after) (void *data); }; -#define spa_loop_control_hook_before(l) spa_hook_list_call_simple(l, struct spa_loop_control_hooks, before, 0) -#define spa_loop_control_hook_after(l) spa_hook_list_call_simple(l, struct spa_loop_control_hooks, after, 0) +#define spa_loop_control_hook_before(l) \ +({ \ + struct spa_hook_list *_l = l; \ + struct spa_hook *_h; \ + spa_list_for_each_reverse(_h, &_l->list, link) \ + spa_callbacks_call(&_h->cb, struct spa_loop_control_hooks, before, 0); \ +}) + +#define spa_loop_control_hook_after(l) \ +({ \ + struct spa_hook_list *_l = l; \ + struct spa_hook *_h; \ + spa_list_for_each(_h, &_l->list, link) \ + spa_callbacks_call(&_h->cb, struct spa_loop_control_hooks, after, 0); \ +}) /** * Control an event loop diff --git a/spa/include/spa/utils/list.h b/spa/include/spa/utils/list.h index 8f0cce7c7..90917ea23 100644 --- a/spa/include/spa/utils/list.h +++ b/spa/include/spa/utils/list.h @@ -98,9 +98,17 @@ static inline void spa_list_remove(struct spa_list *elem) !spa_list_is_end(pos, head, member); \ pos = spa_list_next(pos, member)) +#define spa_list_for_each_prev(pos, head, curr, member) \ + for (pos = spa_list_last(curr, __typeof__(*pos), member); \ + !spa_list_is_end(pos, head, member); \ + pos = spa_list_prev(pos, member)) + #define spa_list_for_each(pos, head, member) \ spa_list_for_each_next(pos, head, head, member) +#define spa_list_for_each_reverse(pos, head, member) \ + spa_list_for_each_prev(pos, head, head, member) + #define spa_list_for_each_safe_next(pos, tmp, head, curr, member) \ for (pos = spa_list_first(curr, __typeof__(*pos), member); \ tmp = spa_list_next(pos, member), \ diff --git a/spa/plugins/support/loop.c b/spa/plugins/support/loop.c index 02c5675a6..f9c166531 100644 --- a/spa/plugins/support/loop.c +++ b/spa/plugins/support/loop.c @@ -278,24 +278,13 @@ static int loop_iterate(void *object, int timeout) struct impl *impl = object; struct spa_loop *loop = &impl->loop; struct spa_poll_event ep[32]; - struct spa_list save; - struct spa_hook *hook; int i, nfds; - spa_list_init(&save); - spa_list_consume(hook, &impl->hooks_list.list, link) { - spa_list_remove(&hook->link); - spa_list_prepend(&save, &hook->link); - spa_callbacks_call(&hook->cb, struct spa_loop_control_hooks, before, 0); - } + spa_loop_control_hook_before(&impl->hooks_list); nfds = spa_system_pollfd_wait(impl->system, impl->poll_fd, ep, SPA_N_ELEMENTS(ep), timeout); - spa_list_consume(hook, &save, link) { - spa_list_remove(&hook->link); - spa_list_append(&impl->hooks_list.list, &hook->link); - spa_callbacks_call(&hook->cb, struct spa_loop_control_hooks, after, 0); - } + spa_loop_control_hook_after(&impl->hooks_list); if (SPA_UNLIKELY(nfds < 0)) return nfds;