link-factory: fix cleanup

If the link is destroyed, remove the listeners. Only remove the
resource listener when we actually have one.
If the resource is destroyed first, destroy the global.
If the global is destroyed first, make sure we don't destroy it
again when the resource is destroyed.
This commit is contained in:
Wim Taymans 2019-01-29 10:32:21 +01:00
parent beae1890d3
commit e63adfef25

View file

@ -49,18 +49,22 @@ struct factory_data {
struct link_data { struct link_data {
struct factory_data *data; struct factory_data *data;
struct pw_link *link;
struct spa_list l; struct spa_list l;
struct pw_link *link;
struct spa_hook link_listener; struct spa_hook link_listener;
struct pw_resource *resource;
struct spa_hook resource_listener; struct spa_hook resource_listener;
struct pw_global *global;
struct spa_hook global_listener;
}; };
static void resource_destroy(void *data) static void resource_destroy(void *data)
{ {
struct link_data *ld = data; struct link_data *ld = data;
spa_hook_remove(&ld->resource_listener); spa_hook_remove(&ld->resource_listener);
if (ld->link) ld->resource = NULL;
pw_link_destroy(ld->link); if (ld->global)
pw_global_destroy(ld->global);
} }
static const struct pw_resource_events resource_events = { static const struct pw_resource_events resource_events = {
@ -72,7 +76,10 @@ static void link_destroy(void *data)
{ {
struct link_data *ld = data; struct link_data *ld = data;
spa_list_remove(&ld->l); spa_list_remove(&ld->l);
ld->link = NULL; if (ld->global)
spa_hook_remove(&ld->global_listener);
if (ld->resource)
spa_hook_remove(&ld->resource_listener);
} }
static const struct pw_link_events link_events = { static const struct pw_link_events link_events = {
@ -80,6 +87,18 @@ static const struct pw_link_events link_events = {
.destroy = link_destroy .destroy = link_destroy
}; };
static void global_destroy(void *data)
{
struct link_data *ld = data;
spa_hook_remove(&ld->global_listener);
ld->global = NULL;
}
static const struct pw_global_events global_events = {
PW_VERSION_GLOBAL_EVENTS,
.destroy = global_destroy
};
static struct pw_port *get_port(struct pw_node *node, enum spa_direction direction) static struct pw_port *get_port(struct pw_node *node, enum spa_direction direction)
{ {
struct pw_port *p; struct pw_port *p;
@ -124,7 +143,6 @@ static void *create_object(void *_data,
uint32_t output_node_id, input_node_id; uint32_t output_node_id, input_node_id;
uint32_t output_port_id, input_port_id; uint32_t output_port_id, input_port_id;
struct link_data *ld; struct link_data *ld;
struct pw_resource *bound_resource;
char *error; char *error;
const char *str; const char *str;
int res; int res;
@ -209,15 +227,19 @@ static void *create_object(void *_data,
properties = NULL; properties = NULL;
res = pw_global_bind(pw_link_get_global(link), client, PW_PERM_RWX, PW_VERSION_LINK, new_id); ld->global = pw_link_get_global(link);
pw_global_add_listener(ld->global, &ld->global_listener, &global_events, ld);
res = pw_global_bind(ld->global, client, PW_PERM_RWX, PW_VERSION_LINK, new_id);
if (res < 0) if (res < 0)
goto no_bind; goto no_bind;
if (!linger) { if (!linger) {
if ((bound_resource = pw_client_find_resource(client, new_id)) == NULL) ld->resource = pw_client_find_resource(client, new_id);
if (ld->resource == NULL)
goto no_bind; goto no_bind;
pw_resource_add_listener(bound_resource, &ld->resource_listener, &resource_events, ld); pw_resource_add_listener(ld->resource, &ld->resource_listener, &resource_events, ld);
} }
return link; return link;