Commit 3172b3f4 authored by Simon Ser's avatar Simon Ser

server: add wl_global_unregister

This commit adds a new wl_global_unregister function that just sends a global
removal 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. There's no way to fix this, since wl_registry is
frozen.

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]: wayland/wayland#10Signed-off-by: Simon Ser's avatarSimon Ser <contact@emersion.fr>
parent 9d63c9ff
Pipeline #50078 passed with stage
in 1 minute and 33 seconds
......@@ -246,6 +246,9 @@ wl_global_create(struct wl_display *display,
int version,
void *data, wl_global_bind_func_t bind);
void
wl_global_unregister(struct wl_global *global);
void
wl_global_destroy(struct wl_global *global);
......
......@@ -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 unregistered;
};
struct wl_resource {
......@@ -1202,6 +1204,7 @@ wl_global_create(struct wl_display *display,
global->version = version;
global->data = data;
global->bind = bind;
global->unregistered = false;
wl_list_insert(display->global_list.prev, &global->link);
wl_list_for_each(resource, &display->registry_resource_list, link)
......@@ -1214,15 +1217,40 @@ wl_global_create(struct wl_display *display,
return global;
}
/** Unregister the global
*
* \param global The Wayland global.
*
* wl_global_destroy() unregisters the global and immediately destroys it. On
* the otehr end, this function only unregisters the global, allowing clients
* that have not yet received the global removal event to continue to bind to
* it.
*
* This can be used by compositors to mitigate clients crashing because a
* global has been added and removed too quickly. Note that the destruction of
* a global is still racy, since clients have no way to acknoledge that they
* received the removal event.
*/
WL_EXPORT void
wl_global_destroy(struct wl_global *global)
wl_global_unregister(struct wl_global *global)
{
struct wl_display *display = global->display;
struct wl_resource *resource;
if (global->unregistered)
return;
wl_list_for_each(resource, &display->registry_resource_list, link)
wl_resource_post_event(resource, WL_REGISTRY_GLOBAL_REMOVE,
global->name);
global->unregistered = true;
}
WL_EXPORT void
wl_global_destroy(struct wl_global *global)
{
wl_global_unregister(global);
wl_list_remove(&global->link);
free(global);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment