From b222fe2a4a4acddf00443af91c17dd860bfacdd8 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 6 May 2025 00:30:24 +0200 Subject: [PATCH] util/signal: Introduce wlr_signal_emit_final wlr_signal_emit_final is conceptually similar to wl_signal_emit_mutable (i.e., our old wlr_signal_emit_safe), but instead of running all listeners that were added at the time the signal emit started, we run until the list is empty, removing entries as we go along. This ensures that newly added signals are run all the same. --- include/util/signal.h | 8 ++++++++ types/output/output.c | 3 ++- util/meson.build | 1 + util/signal.c | 18 ++++++++++++++++++ 4 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 include/util/signal.h create mode 100644 util/signal.c diff --git a/include/util/signal.h b/include/util/signal.h new file mode 100644 index 000000000..714b56f44 --- /dev/null +++ b/include/util/signal.h @@ -0,0 +1,8 @@ +#ifndef UTIL_SIGNAL_H +#define UTIL_SIGNAL_H + +#include + +void wlr_signal_emit_final(struct wl_signal *signal, void *data); + +#endif diff --git a/types/output/output.c b/types/output/output.c index a352a5e59..b7d2ae707 100644 --- a/types/output/output.c +++ b/types/output/output.c @@ -11,6 +11,7 @@ #include "types/wlr_output.h" #include "util/env.h" #include "util/global.h" +#include "util/signal.h" #define OUTPUT_VERSION 4 @@ -377,7 +378,7 @@ void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, } void wlr_output_finish(struct wlr_output *output) { - wl_signal_emit_mutable(&output->events.destroy, output); + wlr_signal_emit_final(&output->events.destroy, output); wlr_addon_set_finish(&output->addons); assert(wl_list_empty(&output->events.frame.listener_list)); diff --git a/util/meson.build b/util/meson.build index fbdd54bbb..e7b3ffa1b 100644 --- a/util/meson.build +++ b/util/meson.build @@ -10,6 +10,7 @@ wlr_files += files( 'region.c', 'set.c', 'shm.c', + 'signal.c', 'time.c', 'token.c', 'transform.c', diff --git a/util/signal.c b/util/signal.c new file mode 100644 index 000000000..531a51b7e --- /dev/null +++ b/util/signal.c @@ -0,0 +1,18 @@ +#include "util/signal.h" + +void wlr_signal_emit_final(struct wl_signal *signal, void *data) { + + // We need to run all listeners one final time. To support all types of list mutations and to + // ensure that all listeners including those added during this execution is run, we run until + // the list is empty, removing listeners just before we run them. To not affect the behavior of + // the listener, we re-initialize the listener's link element. + while (signal->listener_list.next != &signal->listener_list) { + struct wl_list *pos = signal->listener_list.next; + struct wl_listener *l = wl_container_of(pos, l, link); + + wl_list_remove(pos); + wl_list_init(pos); + + l->notify(l, data); + } +}