summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Ser <contact@emersion.fr>2019-07-20 23:36:29 +0300
committerSimon Ser <contact@emersion.fr>2019-10-16 16:32:17 +0300
commit39852f1146941fa93daf767b4ecfb41b2d11aaef (patch)
tree57fc3cae4dd6f3ae5e30a71954b9ffb397d882e1
parentwayland-shm: Don’t set SIGBUS handlers on unshrinkable fd (diff)
downloadwayland-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>
-rw-r--r--src/wayland-server-core.h3
-rw-r--r--src/wayland-server.c42
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,
&registry_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);
}