context: cancel operations when globals are removed

Keep track of all the operations pending for a global and cancel them
when the global is removed.
This commit is contained in:
Wim Taymans 2019-03-12 12:15:28 +01:00
parent 3eb1a09cd2
commit cb7b25277b
4 changed files with 33 additions and 15 deletions

View file

@ -37,9 +37,17 @@ int pa_context_set_error(pa_context *c, int error) {
return error; return error;
} }
static void global_free(struct global *g) static void global_free(pa_context *c, struct global *g)
{ {
pa_operation *o, *t;
spa_list_remove(&g->link); spa_list_remove(&g->link);
spa_list_for_each_safe(o, t, &g->operations, owner_link)
pa_operation_cancel(o);
if (g->proxy)
spa_hook_remove(&g->proxy_proxy_listener);
if (g->props) if (g->props)
pw_properties_free(g->props); pw_properties_free(g->props);
if (g->destroy) if (g->destroy)
@ -60,7 +68,7 @@ static void context_unlink(pa_context *c)
PA_STREAM_FAILED : PA_STREAM_TERMINATED); PA_STREAM_FAILED : PA_STREAM_TERMINATED);
} }
spa_list_consume(g, &c->globals, link) spa_list_consume(g, &c->globals, link)
global_free(g); global_free(c, g);
spa_list_consume(o, &c->operations, link) spa_list_consume(o, &c->operations, link)
pa_operation_cancel(o); pa_operation_cancel(o);
@ -300,10 +308,11 @@ static void registry_event_global(void *data, uint32_t id, uint32_t parent_id,
g->parent_id = parent_id; g->parent_id = parent_id;
g->type = type; g->type = type;
g->props = props ? pw_properties_new_dict(props) : NULL; g->props = props ? pw_properties_new_dict(props) : NULL;
spa_list_init(&g->operations);
spa_list_append(&c->globals, &g->link); spa_list_append(&c->globals, &g->link);
if (set_mask(c, g) == 0) { if (set_mask(c, g) == 0) {
global_free(g); global_free(c, g);
return; return;
} }
@ -323,7 +332,7 @@ static void registry_event_global_remove(void *object, uint32_t id)
emit_event(c, g, PA_SUBSCRIPTION_EVENT_REMOVE); emit_event(c, g, PA_SUBSCRIPTION_EVENT_REMOVE);
pw_log_debug("context %p: free %d %p", c, id, g); pw_log_debug("context %p: free %d %p", c, id, g);
global_free(g); global_free(c, g);
} }
static const struct pw_registry_proxy_events registry_events = static const struct pw_registry_proxy_events registry_events =

View file

@ -217,7 +217,8 @@ struct global {
pa_subscription_mask_t mask; pa_subscription_mask_t mask;
pa_subscription_event_type_t event; pa_subscription_event_type_t event;
pa_operation *operation; struct spa_list operations;
void *info; void *info;
pw_destroy_t destroy; pw_destroy_t destroy;
@ -390,6 +391,9 @@ struct pa_operation
pa_context *context; pa_context *context;
pa_stream *stream; pa_stream *stream;
struct spa_list owner_link;
struct global *owner;
int seq; int seq;
pa_operation_state_t state; pa_operation_state_t state;

View file

@ -30,6 +30,7 @@
static void node_event_info(void *object, const struct pw_node_info *info) static void node_event_info(void *object, const struct pw_node_info *info)
{ {
struct global *g = object; struct global *g = object;
pa_operation *o;
uint32_t i; uint32_t i;
pw_log_debug("update %d", g->id); pw_log_debug("update %d", g->id);
@ -50,10 +51,8 @@ static void node_event_info(void *object, const struct pw_node_info *info)
} }
} }
} }
if (g->operation) { spa_list_for_each(o, &g->operations, owner_link)
pa_operation_sync(g->operation); pa_operation_sync(o);
g->operation = NULL;
}
} }
static void node_event_param(void *object, int seq, static void node_event_param(void *object, int seq,
@ -173,6 +172,7 @@ static void device_event_info(void *object, const struct pw_device_info *info)
{ {
struct global *g = object; struct global *g = object;
pa_card_info *i = &g->card_info.info; pa_card_info *i = &g->card_info.info;
pa_operation *o;
uint32_t n; uint32_t n;
pw_log_debug("update %d %"PRIu64, g->id, info->change_mask); pw_log_debug("update %d %"PRIu64, g->id, info->change_mask);
@ -208,10 +208,8 @@ static void device_event_info(void *object, const struct pw_device_info *info)
} }
} }
} }
if (g->operation) { spa_list_for_each(o, &g->operations, owner_link)
pa_operation_sync(g->operation); pa_operation_sync(o);
g->operation = NULL;
}
} }
static const struct pw_device_proxy_events device_events = { static const struct pw_device_proxy_events device_events = {
@ -265,6 +263,13 @@ static int ensure_global(pa_context *c, struct global *g, pa_operation *o)
const void *events; const void *events;
pw_destroy_t destroy; pw_destroy_t destroy;
if (o) {
if (o->owner)
spa_list_remove(&o->owner_link);
o->owner = g;
spa_list_append(&g->operations, &o->owner_link);
}
if (g->proxy != NULL) if (g->proxy != NULL)
return 0; return 0;
@ -303,8 +308,6 @@ static int ensure_global(pa_context *c, struct global *g, pa_operation *o)
pw_proxy_add_proxy_listener(g->proxy, &g->proxy_proxy_listener, events, g); pw_proxy_add_proxy_listener(g->proxy, &g->proxy_proxy_listener, events, g);
g->destroy = destroy; g->destroy = destroy;
if (o)
g->operation = o;
return 0; return 0;
} }

View file

@ -88,6 +88,8 @@ static void operation_unlink(pa_operation *o) {
} }
if (o->stream) if (o->stream)
pa_stream_unref(o->stream); pa_stream_unref(o->stream);
if (o->owner)
spa_list_remove(&o->owner_link);
o->stream = NULL; o->stream = NULL;
o->callback = NULL; o->callback = NULL;
o->userdata = NULL; o->userdata = NULL;