diff --git a/src/examples/media-session/media-session.c b/src/examples/media-session/media-session.c index d44c550d8..80381688b 100644 --- a/src/examples/media-session/media-session.c +++ b/src/examples/media-session/media-session.c @@ -237,9 +237,14 @@ int sm_object_remove_data(struct sm_object *obj, const char *id) int sm_object_destroy(struct sm_object *obj) { pw_log_debug(NAME" %p: object %d", obj->session, obj->id); - pw_proxy_destroy(obj->proxy); - if (obj->handle) + if (obj->proxy) { + pw_proxy_destroy(obj->proxy); + obj->proxy = NULL; + } + if (obj->handle) { pw_proxy_destroy(obj->handle); + obj->handle = NULL; + } return 0; } @@ -958,10 +963,10 @@ static void bound_proxy(void *data, uint32_t id) } static const struct pw_proxy_events proxy_events = { - PW_VERSION_PROXY_EVENTS, - .destroy = destroy_proxy, - .done = done_proxy, - .bound = bound_proxy, + PW_VERSION_PROXY_EVENTS, + .destroy = destroy_proxy, + .done = done_proxy, + .bound = bound_proxy, }; int sm_object_sync_update(struct sm_object *obj) @@ -1617,7 +1622,8 @@ static void core_error(void *data, uint32_t id, int seq, int res, const char *me id, seq, res, spa_strerror(res), message); if (id == 0) { - pw_main_loop_quit(impl->loop); + if (res == -EPIPE) + pw_main_loop_quit(impl->loop); } } @@ -1673,6 +1679,9 @@ static void session_shutdown(struct impl *impl) sm_media_session_emit_remove(impl, obj); sm_media_session_emit_destroy(impl); + + pw_proxy_destroy((struct pw_proxy*)impl->registry); + pw_core_disconnect(impl->policy_core); } int main(int argc, char *argv[]) diff --git a/src/pipewire/core.c b/src/pipewire/core.c index fd4eb146a..5423e7cce 100644 --- a/src/pipewire/core.c +++ b/src/pipewire/core.c @@ -164,7 +164,7 @@ void *pw_core_get_user_data(struct pw_core *core) return core->user_data; } -static int destroy_proxy(void *object, void *data) +static int remove_proxy(void *object, void *data) { struct pw_core *core = data; struct pw_proxy *p = object; @@ -172,8 +172,10 @@ static int destroy_proxy(void *object, void *data) if (object == NULL) return 0; - if (object != core) + if (object != core) { + p->core = NULL; pw_proxy_remove(p); + } return 0; } @@ -197,7 +199,7 @@ static void proxy_core_destroy(void *data) spa_list_for_each_safe(filter, f2, &core->filter_list, link) pw_filter_disconnect(filter); - pw_map_for_each(&core->objects, destroy_proxy, core); + pw_map_for_each(&core->objects, remove_proxy, core); pw_map_reset(&core->objects); spa_list_consume(stream, &core->stream_list, link) @@ -206,7 +208,7 @@ static void proxy_core_destroy(void *data) pw_filter_destroy(filter); pw_protocol_client_disconnect(core->conn); - core->client = NULL; + pw_proxy_destroy((struct pw_proxy*)core->client); pw_mempool_destroy(core->pool); @@ -439,6 +441,8 @@ struct pw_mempool * pw_core_get_mempool(struct pw_core *core) SPA_EXPORT int pw_core_disconnect(struct pw_core *core) { + pw_log_debug(NAME" %p: disconnect", core); pw_proxy_remove(&core->proxy); + pw_proxy_destroy(&core->proxy); return 0; } diff --git a/src/pipewire/private.h b/src/pipewire/private.h index 06fc62b7c..5e7f9af5a 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -724,6 +724,7 @@ struct pw_resource { #define pw_proxy_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_proxy_events, m, v, ##__VA_ARGS__) #define pw_proxy_emit_destroy(p) pw_proxy_emit(p, destroy, 0) #define pw_proxy_emit_bound(p,g) pw_proxy_emit(p, bound, 0, g) +#define pw_proxy_emit_removed(p) pw_proxy_emit(p, removed, 0) #define pw_proxy_emit_done(p,s) pw_proxy_emit(p, done, 0, s) #define pw_proxy_emit_error(p,s,r,m) pw_proxy_emit(p, error, 0, s, r, m) diff --git a/src/pipewire/proxy.c b/src/pipewire/proxy.c index 109155382..a7c92a7e9 100644 --- a/src/pipewire/proxy.c +++ b/src/pipewire/proxy.c @@ -220,38 +220,58 @@ void pw_proxy_add_object_listener(struct pw_proxy *proxy, SPA_EXPORT void pw_proxy_destroy(struct pw_proxy *proxy) { + pw_log_debug(NAME" %p: destroy id:%u removed:%u zombie:%u ref:%u", proxy, + proxy->id, proxy->removed, proxy->zombie, proxy->refcount); + assert(!proxy->destroyed); proxy->destroyed = true; - pw_log_debug(NAME" %p: destroy id:%u removed:%u zombie:%u", proxy, - proxy->id, proxy->removed, proxy->zombie); - - if (!proxy->zombie) { - proxy->zombie = true; - pw_proxy_emit_destroy(proxy); - } if (!proxy->removed) { - /* if the server did not remove this proxy, remove ourselves - * from the proxy objects and schedule a destroy. */ - if (proxy->core && !proxy->core->destroyed) { + /* if the server did not remove this proxy, schedule a + * destroy if we can */ + if (proxy->core) { pw_core_destroy(proxy->core, proxy); + proxy->refcount++; } else { proxy->removed = true; } } if (proxy->removed) { - if (proxy->core && !proxy->core->destroyed) + if (proxy->core) pw_map_remove(&proxy->core->objects, proxy->id); - - pw_proxy_unref(proxy); } + + if (!proxy->zombie) { + /* mark zombie and emit destroyed. No more + * events will be emited on zombie objects */ + proxy->zombie = true; + pw_proxy_emit_destroy(proxy); + } + pw_proxy_unref(proxy); } +/** called when cleaning up or when the server removed the resource. Can + * be called multiple times */ void pw_proxy_remove(struct pw_proxy *proxy) { - proxy->removed = true; - proxy->destroyed = false; - pw_proxy_destroy(proxy); + assert(proxy->refcount > 0); + + pw_log_debug(NAME" %p: remove id:%u removed:%u destroyed:%u zombie:%u", proxy, + proxy->id, proxy->removed, proxy->destroyed, proxy->zombie); + + proxy->refcount++; + if (!proxy->removed) { + /* mark removed and emit the removed signal only once and + * only when not already destroyed */ + proxy->removed = true; + if (!proxy->destroyed) + pw_proxy_emit_removed(proxy); + } + if (proxy->destroyed) { + proxy->destroyed = false; + pw_proxy_destroy(proxy); + } + pw_proxy_unref(proxy); } SPA_EXPORT @@ -262,6 +282,8 @@ void pw_proxy_unref(struct pw_proxy *proxy) return; pw_log_debug(NAME" %p: free %u", proxy, proxy->id); + /** client must explicitly destroy all proxies */ + assert(proxy->destroyed); free(proxy); } diff --git a/src/pipewire/proxy.h b/src/pipewire/proxy.h index 7aec20c78..b640211c9 100644 --- a/src/pipewire/proxy.h +++ b/src/pipewire/proxy.h @@ -113,6 +113,10 @@ struct pw_proxy_events { /** a proxy is bound to a global id */ void (*bound) (void *data, uint32_t global_id); + /** a proxy is removed from the server. Use pw_proxy_destroy to + * free the proxy. */ + void (*removed) (void *data); + /** a reply to a sync method completed */ void (*done) (void *data, int seq);