wayland-server: Add wl_client_add_destroy_late_listener
A late-destroy listener for a client is called after all the client's resources have been destroyed and the destroy callbacks emitted. This lives in parallel to the existing client destroy listener, called immediately before the client's objects get destroyed. Signed-off-by: Daniel Stone <daniels@collabora.com> Fixes: wayland/wayland#207
This commit is contained in:
parent
e886b456ab
commit
51d788de5b
|
@ -330,6 +330,14 @@ struct wl_listener *
|
|||
wl_client_get_destroy_listener(struct wl_client *client,
|
||||
wl_notify_func_t notify);
|
||||
|
||||
void
|
||||
wl_client_add_destroy_late_listener(struct wl_client *client,
|
||||
struct wl_listener *listener);
|
||||
|
||||
struct wl_listener *
|
||||
wl_client_get_destroy_late_listener(struct wl_client *client,
|
||||
wl_notify_func_t notify);
|
||||
|
||||
struct wl_resource *
|
||||
wl_client_get_object(struct wl_client *client, uint32_t id);
|
||||
|
||||
|
|
|
@ -79,6 +79,7 @@ struct wl_client {
|
|||
struct wl_list link;
|
||||
struct wl_map objects;
|
||||
struct wl_priv_signal destroy_signal;
|
||||
struct wl_priv_signal destroy_late_signal;
|
||||
pid_t pid;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
|
@ -547,6 +548,7 @@ wl_client_create(struct wl_display *display, int fd)
|
|||
goto err_map;
|
||||
|
||||
wl_priv_signal_init(&client->destroy_signal);
|
||||
wl_priv_signal_init(&client->destroy_late_signal);
|
||||
if (bind_display(client, display) < 0)
|
||||
goto err_map;
|
||||
|
||||
|
@ -864,6 +866,17 @@ wl_resource_get_class(struct wl_resource *resource)
|
|||
return resource->object.interface->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a listener to be called at the beginning of wl_client destruction
|
||||
*
|
||||
* The listener provided will be called when wl_client destroy has begun,
|
||||
* before any of that client's resources have been destroyed.
|
||||
*
|
||||
* There is no requirement to remove the link of the wl_listener when the
|
||||
* signal is emitted.
|
||||
*
|
||||
* \memberof wl_client
|
||||
*/
|
||||
WL_EXPORT void
|
||||
wl_client_add_destroy_listener(struct wl_client *client,
|
||||
struct wl_listener *listener)
|
||||
|
@ -878,6 +891,32 @@ wl_client_get_destroy_listener(struct wl_client *client,
|
|||
return wl_priv_signal_get(&client->destroy_signal, notify);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a listener to be called at the end of wl_client destruction
|
||||
*
|
||||
* The listener provided will be called when wl_client destroy is nearly
|
||||
* complete, after all of that client's resources have been destroyed.
|
||||
*
|
||||
* There is no requirement to remove the link of the wl_listener when the
|
||||
* signal is emitted.
|
||||
*
|
||||
* \memberof wl_client
|
||||
* \since 1.22.0
|
||||
*/
|
||||
WL_EXPORT void
|
||||
wl_client_add_destroy_late_listener(struct wl_client *client,
|
||||
struct wl_listener *listener)
|
||||
{
|
||||
wl_priv_signal_add(&client->destroy_late_signal, listener);
|
||||
}
|
||||
|
||||
WL_EXPORT struct wl_listener *
|
||||
wl_client_get_destroy_late_listener(struct wl_client *client,
|
||||
wl_notify_func_t notify)
|
||||
{
|
||||
return wl_priv_signal_get(&client->destroy_late_signal, notify);
|
||||
}
|
||||
|
||||
WL_EXPORT void
|
||||
wl_client_destroy(struct wl_client *client)
|
||||
{
|
||||
|
@ -890,6 +929,9 @@ wl_client_destroy(struct wl_client *client)
|
|||
wl_map_release(&client->objects);
|
||||
wl_event_source_remove(client->source);
|
||||
close(wl_connection_destroy(client->connection));
|
||||
|
||||
wl_priv_signal_final_emit(&client->destroy_late_signal, client);
|
||||
|
||||
wl_list_remove(&client->link);
|
||||
wl_list_remove(&client->resource_created_signal.listener_list);
|
||||
free(client);
|
||||
|
|
|
@ -41,6 +41,8 @@
|
|||
struct client_destroy_listener {
|
||||
struct wl_listener listener;
|
||||
bool done;
|
||||
struct wl_listener late_listener;
|
||||
bool late_done;
|
||||
};
|
||||
|
||||
static void
|
||||
|
@ -49,9 +51,20 @@ client_destroy_notify(struct wl_listener *l, void *data)
|
|||
struct client_destroy_listener *listener =
|
||||
wl_container_of(l, listener, listener);
|
||||
|
||||
assert(!listener->late_done);
|
||||
listener->done = true;
|
||||
}
|
||||
|
||||
static void
|
||||
client_late_destroy_notify(struct wl_listener *l, void *data)
|
||||
{
|
||||
struct client_destroy_listener *listener =
|
||||
wl_container_of(l, listener, late_listener);
|
||||
|
||||
assert(listener->done);
|
||||
listener->late_done = true;
|
||||
}
|
||||
|
||||
TEST(client_destroy_listener)
|
||||
{
|
||||
struct wl_display *display;
|
||||
|
@ -67,21 +80,32 @@ TEST(client_destroy_listener)
|
|||
|
||||
a.listener.notify = client_destroy_notify;
|
||||
a.done = false;
|
||||
a.late_listener.notify = client_late_destroy_notify;
|
||||
a.late_done = false;
|
||||
wl_client_add_destroy_listener(client, &a.listener);
|
||||
wl_client_add_destroy_late_listener(client, &a.late_listener);
|
||||
|
||||
assert(wl_client_get_destroy_listener(client, client_destroy_notify) ==
|
||||
&a.listener);
|
||||
assert(wl_client_get_destroy_late_listener(client, client_late_destroy_notify) ==
|
||||
&a.late_listener);
|
||||
|
||||
b.listener.notify = client_destroy_notify;
|
||||
b.done = false;
|
||||
b.late_listener.notify = client_late_destroy_notify;
|
||||
b.late_done = false;
|
||||
wl_client_add_destroy_listener(client, &b.listener);
|
||||
wl_client_add_destroy_late_listener(client, &b.late_listener);
|
||||
|
||||
wl_list_remove(&a.listener.link);
|
||||
wl_list_remove(&a.late_listener.link);
|
||||
|
||||
wl_client_destroy(client);
|
||||
|
||||
assert(!a.done);
|
||||
assert(!a.late_done);
|
||||
assert(b.done);
|
||||
assert(b.late_done);
|
||||
|
||||
close(s[0]);
|
||||
close(s[1]);
|
||||
|
|
Loading…
Reference in New Issue
Block a user