diff options
author | Simon Ser <contact@emersion.fr> | 2022-01-31 23:09:26 +0100 |
---|---|---|
committer | Simon Ser <contact@emersion.fr> | 2022-03-28 19:06:16 +0000 |
commit | 962aefda42f7bbfb6d9b64b7b177e232213d8a59 (patch) | |
tree | 39c59be1e5ec8331f6e1a9742879349dee32374e /tests | |
parent | 868eb99eb07965f34461693d82c68dba503aec46 (diff) | |
download | wayland-962aefda42f7bbfb6d9b64b7b177e232213d8a59.tar.gz |
server: introduce wl_signal_emit_mutable
wl_signal_emit doesn't handle well situations where a listener removes
another listener. This can happen in practice: wlroots and Weston [1]
both have private helpers to workaround this defect.
wl_signal_emit can't be fixed without breaking the API. Instead,
introduce a new function. Callers need to make sure to always remove
listeners when they are free'd.
[1]: https://gitlab.freedesktop.org/wayland/weston/-/merge_requests/457
Signed-off-by: Simon Ser <contact@emersion.fr>
Signed-off-by: Alexandros Frantzis <alexandros.frantzis@collabora.com>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/signal-test.c | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/tests/signal-test.c b/tests/signal-test.c index 7bbaa9f..f7e1bd6 100644 --- a/tests/signal-test.c +++ b/tests/signal-test.c @@ -115,3 +115,44 @@ TEST(signal_emit_to_more_listeners) assert(3 * counter == count); } + +struct signal_emit_mutable_data { + int count; + struct wl_listener *remove_listener; +}; + +static void +signal_notify_mutable(struct wl_listener *listener, void *data) +{ + struct signal_emit_mutable_data *test_data = data; + test_data->count++; +} + +static void +signal_notify_and_remove_mutable(struct wl_listener *listener, void *data) +{ + struct signal_emit_mutable_data *test_data = data; + signal_notify_mutable(listener, test_data); + wl_list_remove(&test_data->remove_listener->link); +} + +TEST(signal_emit_mutable) +{ + struct signal_emit_mutable_data data = {0}; + + /* l2 will remove l3 before l3 is notified */ + struct wl_signal signal; + struct wl_listener l1 = {.notify = signal_notify_mutable}; + struct wl_listener l2 = {.notify = signal_notify_and_remove_mutable}; + struct wl_listener l3 = {.notify = signal_notify_mutable}; + + wl_signal_init(&signal); + wl_signal_add(&signal, &l1); + wl_signal_add(&signal, &l2); + wl_signal_add(&signal, &l3); + + data.remove_listener = &l3; + wl_signal_emit_mutable(&signal, &data); + + assert(data.count == 2); +} |