From 8d2a9fcf62744116c8dd6c9a0c8c19b71bdb90e3 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 19 Sep 2018 15:58:05 +0200 Subject: [PATCH] pipewire: fix leak of dbus interface Track loaded interfaces. Add a method to release the dbus interface when the core is destroyed. Free SDL resources in video-play example --- src/examples/video-play.c | 4 +++ src/pipewire/core.c | 6 +++- src/pipewire/pipewire.c | 72 +++++++++++++++++++++++++++++++++------ src/pipewire/pipewire.h | 1 + src/pipewire/private.h | 2 ++ 5 files changed, 74 insertions(+), 11 deletions(-) diff --git a/src/examples/video-play.c b/src/examples/video-play.c index 8ec70b823..b259a86b6 100644 --- a/src/examples/video-play.c +++ b/src/examples/video-play.c @@ -449,5 +449,9 @@ int main(int argc, char *argv[]) pw_core_destroy(data.core); pw_main_loop_destroy(data.loop); + SDL_DestroyTexture(data.texture); + SDL_DestroyRenderer(data.renderer); + SDL_DestroyWindow(data.window); + return 0; } diff --git a/src/pipewire/core.c b/src/pipewire/core.c index a844eb41e..6134a6ea3 100644 --- a/src/pipewire/core.c +++ b/src/pipewire/core.c @@ -391,12 +391,14 @@ struct pw_core *pw_core_new(struct pw_loop *main_loop, struct pw_properties *pro spa_graph_init(&this->rt.graph); spa_graph_set_callbacks(&this->rt.graph, &spa_graph_impl_default, NULL); + this->dbus_iface = pw_get_spa_dbus(this->main_loop); + this->support[0] = SPA_SUPPORT_INIT(SPA_TYPE__TypeMap, this->type.map); this->support[1] = SPA_SUPPORT_INIT(SPA_TYPE_LOOP__DataLoop, this->data_loop->loop); this->support[2] = SPA_SUPPORT_INIT(SPA_TYPE_LOOP__MainLoop, this->main_loop->loop); this->support[3] = SPA_SUPPORT_INIT(SPA_TYPE__LoopUtils, this->main_loop->utils); this->support[4] = SPA_SUPPORT_INIT(SPA_TYPE__Log, pw_log_get()); - this->support[5] = SPA_SUPPORT_INIT(SPA_TYPE__DBus, pw_get_spa_dbus(this->main_loop)); + this->support[5] = SPA_SUPPORT_INIT(SPA_TYPE__DBus, this->dbus_iface); this->n_support = 6; pw_log_debug("%p", this->support[5].data); @@ -494,6 +496,8 @@ void pw_core_destroy(struct pw_core *core) pw_data_loop_destroy(core->data_loop_impl); + pw_release_spa_dbus(core->dbus_iface); + pw_properties_free(core->properties); pw_map_clear(&core->globals); diff --git a/src/pipewire/pipewire.c b/src/pipewire/pipewire.c index 925e8af24..d1c6746b8 100644 --- a/src/pipewire/pipewire.c +++ b/src/pipewire/pipewire.c @@ -44,6 +44,19 @@ static struct support_info { uint32_t n_support; } support_info; +struct interface { + struct spa_list link; + struct spa_handle *handle; + uint32_t type; + void *iface; +}; + +struct registry { + struct spa_list interfaces; +}; + +static struct registry global_registry; + static bool open_support(const char *path, const char *lib, @@ -92,7 +105,7 @@ static const struct spa_handle_factory *get_factory(struct support_info *info, c return NULL; } -static void * +static struct interface * load_interface(struct support_info *info, const char *factory_name, const char *type) @@ -101,7 +114,8 @@ load_interface(struct support_info *info, struct spa_handle *handle; uint32_t type_id; const struct spa_handle_factory *factory; - void *iface; + struct interface *iface; + void *ptr; struct spa_type_map *map = NULL; factory = get_factory(info, factory_name); @@ -118,12 +132,22 @@ load_interface(struct support_info *info, map = pw_get_support_interface(SPA_TYPE__TypeMap); type_id = map ? spa_type_map_get_id(map, type) : 0; - if ((res = spa_handle_get_interface(handle, type_id, &iface)) < 0) { + if ((res = spa_handle_get_interface(handle, type_id, &ptr)) < 0) { fprintf(stderr, "can't get %s interface %d\n", type, res); goto interface_failed; } + + if ((iface = calloc(1, sizeof(struct interface))) == NULL) + goto alloc_failed; + + iface->handle = handle; + iface->type = type_id; + iface->iface = ptr; + spa_list_append(&global_registry.interfaces, &iface->link); + return iface; + alloc_failed: interface_failed: spa_handle_clear(handle); init_failed: @@ -175,6 +199,7 @@ void *pw_get_spa_dbus(struct pw_loop *loop) { struct support_info dbus_support_info; const char *str; + struct interface *iface; dbus_support_info.n_support = support_info.n_support; memcpy(dbus_support_info.support, support_info.support, @@ -186,11 +211,36 @@ void *pw_get_spa_dbus(struct pw_loop *loop) if ((str = getenv("SPA_PLUGIN_DIR")) == NULL) str = PLUGINDIR; - if (open_support(str, "support/libspa-dbus", &dbus_support_info)) - return load_interface(&dbus_support_info, "dbus", SPA_TYPE__DBus); - + if (open_support(str, "support/libspa-dbus", &dbus_support_info)) { + iface = load_interface(&dbus_support_info, "dbus", SPA_TYPE__DBus); + if (iface != NULL) + return iface->iface; + } return NULL; } +static struct interface *find_interface(void *iface) +{ + struct interface *i; + spa_list_for_each(i, &global_registry.interfaces, link) { + if (i->iface == iface) + return i; + } + return NULL; +} + +int pw_release_spa_dbus(void *dbus) +{ + struct interface *iface; + + if ((iface = find_interface(dbus)) == NULL) + return -ENOENT; + + spa_list_remove(&iface->link); + spa_handle_clear(iface->handle); + free(iface->handle); + free(iface); + return 0; +} /** Initialize PipeWire * @@ -207,7 +257,7 @@ void *pw_get_spa_dbus(struct pw_loop *loop) void pw_init(int *argc, char **argv[]) { const char *str; - void *iface; + struct interface *iface; struct support_info *info = &support_info; if ((str = getenv("PIPEWIRE_DEBUG"))) @@ -219,15 +269,17 @@ void pw_init(int *argc, char **argv[]) if (support_info.n_support > 0) return; + spa_list_init(&global_registry.interfaces); + if (open_support(str, "support/libspa-support", info)) { iface = load_interface(info, "mapper", SPA_TYPE__TypeMap); if (iface != NULL) - info->support[info->n_support++] = SPA_SUPPORT_INIT(SPA_TYPE__TypeMap, iface); + info->support[info->n_support++] = SPA_SUPPORT_INIT(SPA_TYPE__TypeMap, iface->iface); iface = load_interface(info, "logger", SPA_TYPE__Log); if (iface != NULL) { - info->support[info->n_support++] = SPA_SUPPORT_INIT(SPA_TYPE__Log, iface); - pw_log_set(iface); + info->support[info->n_support++] = SPA_SUPPORT_INIT(SPA_TYPE__Log, iface->iface); + pw_log_set(iface->iface); } } pw_log_info("version %s", pw_get_library_version()); diff --git a/src/pipewire/pipewire.h b/src/pipewire/pipewire.h index dcf705ea8..16bc28463 100644 --- a/src/pipewire/pipewire.h +++ b/src/pipewire/pipewire.h @@ -134,6 +134,7 @@ void * pw_get_support_interface(const char *type); void *pw_get_spa_dbus(struct pw_loop *loop); +int pw_release_spa_dbus(void *dbus); const struct spa_handle_factory * pw_get_support_factory(const char *factory_name); diff --git a/src/pipewire/private.h b/src/pipewire/private.h index 2b2682abb..a9b189af6 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -183,6 +183,8 @@ struct pw_core { struct pw_loop *data_loop; /**< data loop for data passing */ struct pw_data_loop *data_loop_impl; + void *dbus_iface; + struct spa_support support[16]; /**< support for spa plugins */ uint32_t n_support; /**< number of support items */