summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWim Taymans <wtaymans@redhat.com>2019-12-19 13:39:05 +0100
committerWim Taymans <wtaymans@redhat.com>2019-12-19 15:25:21 +0100
commitd3db9d12bcaa7a66bf37b4ad0486564ffb288984 (patch)
tree2b8e3cdae0765a12ee1cd6bff108cb827fd3b077
parentf391353c7f6b9b23c1d7e39c2b73200f04d8effb (diff)
proxy: never free a proxy automatically
Never free a proxy without the application doing a pw_proxy_destroy. It's hard to use when proxies are freed randomly when the server removes the ids. You have to add destroy notify to all proxies and deal with the arbirary order in which proxies can be freed. Instead notify the client of the remove and let it destroy the proxies itself in the right order. This is in line with how wayland handles proxies. A pw_proxy_destroy() will now send a destroy to the server and mark the proxy as a zombie, waiting for the remove_id confirmation and then destroy the proxy. A server remove_id will mark the proxy as removed and emits the removed event. The app should then pw_proxy_destroy the proxy to free it. Leaks all proxies in the session manager because cleanup now needs to be handled by the app correctly.
-rw-r--r--src/examples/media-session/media-session.c23
-rw-r--r--src/pipewire/core.c12
-rw-r--r--src/pipewire/private.h1
-rw-r--r--src/pipewire/proxy.c52
-rw-r--r--src/pipewire/proxy.h4
5 files changed, 66 insertions, 26 deletions
diff --git a/src/examples/media-session/media-session.c b/src/examples/media-session/media-session.c
index d44c550d..80381688 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 fd4eb146..5423e7cc 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 06fc62b7..5e7f9af5 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 10915538..a7c92a7e 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 7aec20c7..b640211c 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);