summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWim Taymans <wtaymans@redhat.com>2020-09-16 13:20:19 +0200
committerWim Taymans <wtaymans@redhat.com>2020-09-16 13:31:47 +0200
commite5f7e040dc911d2cea5edf1254057c140cdfff07 (patch)
treebb4b3c261b66b287b2643cd77e35f5a77ff9f160
parent854d01934312f2f25909a905dc535885ed90ad2e (diff)
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.
-rw-r--r--spa/include/spa/support/loop.h21
-rw-r--r--spa/include/spa/utils/list.h8
-rw-r--r--spa/plugins/support/loop.c15
3 files changed, 28 insertions, 16 deletions
diff --git a/spa/include/spa/support/loop.h b/spa/include/spa/support/loop.h
index 575dd293..34ddaa89 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 8f0cce7c..90917ea2 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 02c5675a..f9c16653 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;