diff options
| author | Simon Ser <contact@emersion.fr> | 2019-07-20 23:36:29 +0300 |
|---|---|---|
| committer | Simon Ser <contact@emersion.fr> | 2019-10-16 16:32:17 +0300 |
| commit | 39852f1146941fa93daf767b4ecfb41b2d11aaef (patch) | |
| tree | 57fc3cae4dd6f3ae5e30a71954b9ffb397d882e1 /src | |
| parent | wayland-shm: Don’t set SIGBUS handlers on unshrinkable fd (diff) | |
| download | wayland-39852f1146941fa93daf767b4ecfb41b2d11aaef.tar wayland-39852f1146941fa93daf767b4ecfb41b2d11aaef.tar.gz wayland-39852f1146941fa93daf767b4ecfb41b2d11aaef.tar.bz2 wayland-39852f1146941fa93daf767b4ecfb41b2d11aaef.tar.lz wayland-39852f1146941fa93daf767b4ecfb41b2d11aaef.tar.xz wayland-39852f1146941fa93daf767b4ecfb41b2d11aaef.tar.zst wayland-39852f1146941fa93daf767b4ecfb41b2d11aaef.zip | |
server: add wl_global_remove
This commit adds a new wl_global_remove function that just sends a global
remove event without destroying it. See [1] for details.
Removing a global is racy, because clients have no way to acknowledge they
received the removal event.
It's possible to mitigate the issue by sending the removal event, waiting a
little and then destructing the global for real. The "wait a little" part is
compositor policy.
[1]: https://gitlab.freedesktop.org/wayland/wayland/issues/10
Signed-off-by: Simon Ser <contact@emersion.fr>
Diffstat (limited to 'src')
| -rw-r--r-- | src/wayland-server-core.h | 3 | ||||
| -rw-r--r-- | src/wayland-server.c | 42 |
2 files changed, 43 insertions, 2 deletions
diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 68d7ddb..fd4fc3e 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -247,6 +247,9 @@ wl_global_create(struct wl_display *display, void *data, wl_global_bind_func_t bind); void +wl_global_remove(struct wl_global *global); + +void wl_global_destroy(struct wl_global *global); /** A filter function for wl_global objects diff --git a/src/wayland-server.c b/src/wayland-server.c index 8c537bb..c4c52ed 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -25,6 +25,7 @@ #define _GNU_SOURCE +#include <stdbool.h> #include <stdlib.h> #include <stdint.h> #include <stddef.h> @@ -112,6 +113,7 @@ struct wl_global { void *data; wl_global_bind_func_t bind; struct wl_list link; + bool removed; }; struct wl_resource { @@ -992,7 +994,7 @@ display_get_registry(struct wl_client *client, ®istry_resource->link); wl_list_for_each(global, &display->global_list, link) - if (wl_global_is_visible(client, global)) + if (wl_global_is_visible(client, global) && !global->removed) wl_resource_post_event(registry_resource, WL_REGISTRY_GLOBAL, global->name, @@ -1208,6 +1210,7 @@ wl_global_create(struct wl_display *display, global->version = version; global->data = data; global->bind = bind; + global->removed = false; wl_list_insert(display->global_list.prev, &global->link); wl_list_for_each(resource, &display->registry_resource_list, link) @@ -1220,15 +1223,50 @@ wl_global_create(struct wl_display *display, return global; } +/** Remove the global + * + * \param global The Wayland global. + * + * Broadcast a global remove event to all clients without destroying the + * global. This function can only be called once per global. + * + * wl_global_destroy() removes the global and immediately destroys it. On + * the other end, this function only removes the global, allowing clients + * that have not yet received the global remove event to continue to bind to + * it. + * + * This can be used by compositors to mitigate clients being disconnected + * because a global has been added and removed too quickly. Compositors can call + * wl_global_remove(), then wait an implementation-defined amount of time, then + * call wl_global_destroy(). Note that the destruction of a global is still + * racy, since clients have no way to acknowledge that they received the remove + * event. + * + * \since 1.17.90 + */ WL_EXPORT void -wl_global_destroy(struct wl_global *global) +wl_global_remove(struct wl_global *global) { struct wl_display *display = global->display; struct wl_resource *resource; + if (global->removed) + wl_abort("wl_global_remove: called twice on the same " + "global '%s@%"PRIu32"'", global->interface->name, + global->name); + wl_list_for_each(resource, &display->registry_resource_list, link) wl_resource_post_event(resource, WL_REGISTRY_GLOBAL_REMOVE, global->name); + + global->removed = true; +} + +WL_EXPORT void +wl_global_destroy(struct wl_global *global) +{ + if (!global->removed) + wl_global_remove(global); wl_list_remove(&global->link); free(global); } |
