From b6ad45bb74c7d6b8e90cabb460d948a80c9d5f18 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 15 Nov 2016 17:06:09 +0100 Subject: [PATCH] track client resources --- pinos/server/client-node.c | 36 ++++++--- pinos/server/client-node.h | 6 +- pinos/server/client.c | 71 +++++++++-------- pinos/server/client.h | 34 +++++++-- pinos/server/core.c | 8 +- pinos/server/core.h | 6 +- pinos/server/daemon.c | 6 +- pinos/server/link.c | 152 +++++++++++++++++++++++++++++++------ pinos/server/link.h | 2 +- pinos/server/main-loop.c | 2 - pinos/server/node.c | 17 +++-- pinos/server/node.h | 2 +- pinos/server/registry.c | 2 + pinos/server/registry.h | 1 + 14 files changed, 253 insertions(+), 92 deletions(-) diff --git a/pinos/server/client-node.c b/pinos/server/client-node.c index 7fcd53345..d24698842 100644 --- a/pinos/server/client-node.c +++ b/pinos/server/client-node.c @@ -1274,7 +1274,6 @@ proxy_clear (SpaProxy *this) /** * pinos_client_node_new: * @daemon: a #PinosDaemon - * @client: the client owner * @name: a name * @properties: extra properties * @@ -1284,7 +1283,6 @@ proxy_clear (SpaProxy *this) */ PinosClientNode * pinos_client_node_new (PinosCore *core, - PinosClient *client, const gchar *name, PinosProperties *properties) { @@ -1323,16 +1321,15 @@ pinos_client_node_new (PinosCore *core, return this; } -void -pinos_client_node_destroy (PinosClientNode * this) +static void +on_node_remove (PinosNode *node, + gpointer data, + SpaResult res) { + PinosClientNode *this = data; PinosClientNodeImpl *impl = SPA_CONTAINER_OF (this, PinosClientNodeImpl, this); - pinos_log_debug ("client-node %p: destroy", impl); - pinos_signal_emit (&this->destroy_signal, this); - - pinos_node_destroy (this->node); - + pinos_log_debug ("client-node %p: finalize", node); proxy_clear (&impl->proxy); if (impl->ctrl_fd != -1) @@ -1342,6 +1339,27 @@ pinos_client_node_destroy (PinosClientNode * this) free (impl); } + +SpaResult +pinos_client_node_destroy (PinosClientNode * this) +{ + PinosClientNodeImpl *impl = SPA_CONTAINER_OF (this, PinosClientNodeImpl, this); + SpaResult res; + + pinos_log_debug ("client-node %p: destroy", impl); + pinos_signal_emit (&this->destroy_signal, this); + + res = pinos_node_destroy (this->node); + + pinos_main_loop_defer (this->node->core->main_loop, + this->node, + res, + (PinosDeferFunc) on_node_remove, + this); + + return res; +} + /** * pinos_client_node_get_ctrl_socket: * @node: a #PinosClientNode diff --git a/pinos/server/client-node.h b/pinos/server/client-node.h index 10e677c41..5be81bbbf 100644 --- a/pinos/server/client-node.h +++ b/pinos/server/client-node.h @@ -26,6 +26,9 @@ extern "C" { #endif +#define PINOS_CLIENT_NODE_URI "http://pinos.org/ns/client-node" +#define PINOS_CLIENT_NODE_PREFIX PINOS_CLIENT_NODE_URI "#" + typedef struct _PinosClientNode PinosClientNode; /** @@ -41,10 +44,9 @@ struct _PinosClientNode { }; PinosClientNode * pinos_client_node_new (PinosCore *core, - PinosClient *client, const gchar *name, PinosProperties *properties); -void pinos_client_node_destroy (PinosClientNode *node); +SpaResult pinos_client_node_destroy (PinosClientNode *node); SpaResult pinos_client_node_get_ctrl_socket (PinosClientNode *node, int *fd); SpaResult pinos_client_node_get_data_socket (PinosClientNode *node, int *fd); diff --git a/pinos/server/client.c b/pinos/server/client.c index 260d81dc4..31771e2b6 100644 --- a/pinos/server/client.c +++ b/pinos/server/client.c @@ -31,7 +31,6 @@ typedef struct guint id; PinosClient1 *iface; - GList *objects; } PinosClientImpl; static void @@ -86,44 +85,50 @@ client_watch_name (PinosClient *this) (GDestroyNotify) pinos_client_destroy); } -void -pinos_client_add_object (PinosClient *client, - PinosObject *object) +PinosResource * +pinos_client_add_resource (PinosClient *client, + uint32_t type, + void *object, + PinosDestroy destroy) { - PinosClientImpl *impl = SPA_CONTAINER_OF (client, PinosClientImpl, this); + PinosResource *resource; - g_return_if_fail (client); - g_return_if_fail (object); + resource = calloc (1, sizeof (PinosResource)); + resource->core = client->core; + resource->id = 0; + resource->type = type; + resource->object = object; + resource->destroy = destroy; - impl->objects = g_list_prepend (impl->objects, object); + pinos_signal_init (&resource->destroy_signal); + + pinos_log_debug ("client %p: add resource %p", client, resource); + + spa_list_insert (client->resource_list.prev, &resource->link); + + return resource; } void -pinos_client_remove_object (PinosClient *client, - PinosObject *object) +pinos_client_remove_resource (PinosClient *client, + PinosResource *resource) { - PinosClientImpl *impl = SPA_CONTAINER_OF (client, PinosClientImpl, this); + pinos_log_debug ("client %p: resource %p destroy", client, resource); + pinos_signal_emit (&resource->destroy_signal, resource); - g_return_if_fail (client); - g_return_if_fail (object); + spa_list_remove (&resource->link); - impl->objects = g_list_remove (impl->objects, object); - pinos_object_destroy (object); + if (resource->destroy) + resource->destroy (resource->object); + + free (resource); } bool -pinos_client_has_object (PinosClient *client, - PinosObject *object) +pinos_client_has_resource (PinosClient *client, + PinosResource *resource) { - PinosClientImpl *impl = SPA_CONTAINER_OF (client, PinosClientImpl, this); - GList *found; - - g_return_val_if_fail (client, false); - g_return_val_if_fail (object, false); - - found = g_list_find (impl->objects, object); - - return found != NULL; + return false; } /** @@ -153,6 +158,7 @@ pinos_client_new (PinosCore *core, this->sender = strdup (sender); this->properties = properties; + spa_list_init (&this->resource_list); pinos_signal_init (&this->destroy_signal); impl->iface = pinos_client1_skeleton_new (); @@ -170,20 +176,19 @@ pinos_client_new (PinosCore *core, * * Trigger removal of @client */ -void +SpaResult pinos_client_destroy (PinosClient * client) { PinosClientImpl *impl = SPA_CONTAINER_OF (client, PinosClientImpl, this); - GList *copy; + PinosResource *resource, *tmp; pinos_log_debug ("client %p: destroy", client); pinos_signal_emit (&client->destroy_signal, client); - spa_list_remove (&client->list); + spa_list_for_each_safe (resource, tmp, &client->resource_list, link) + pinos_client_remove_resource (client, resource); - copy = g_list_copy (impl->objects); - g_list_free_full (copy, NULL); - g_list_free (impl->objects); + spa_list_remove (&client->list); free (client->sender); if (client->properties) @@ -191,4 +196,6 @@ pinos_client_destroy (PinosClient * client) g_clear_object (&impl->iface); free (impl); + + return SPA_RESULT_OK; } diff --git a/pinos/server/client.h b/pinos/server/client.h index ef14d6def..820dc34da 100644 --- a/pinos/server/client.h +++ b/pinos/server/client.h @@ -28,10 +28,25 @@ extern "C" { #define PINOS_CLIENT_PREFIX PINOS_CLIENT_URI "#" typedef struct _PinosClient PinosClient; +typedef struct _PinosResource PinosResource; + +typedef void (*PinosDestroy) (void *object); #include #include +struct _PinosResource { + PinosCore *core; + SpaList link; + uint32_t id; + uint32_t type; + void *object; + PinosDestroy destroy; + + PINOS_SIGNAL (destroy_signal, (PinosListener *listener, + PinosResource *resource)); +}; + /** * PinosClient: * @@ -45,6 +60,8 @@ struct _PinosClient { char *sender; PinosProperties *properties; + SpaList resource_list; + PINOS_SIGNAL (destroy_signal, (PinosListener *listener, PinosClient *client)); }; @@ -52,15 +69,18 @@ struct _PinosClient { PinosClient * pinos_client_new (PinosCore *core, const gchar *sender, PinosProperties *properties); -void pinos_client_destroy (PinosClient *client); +SpaResult pinos_client_destroy (PinosClient *client); -void pinos_client_add_object (PinosClient *client, - PinosObject *object); -void pinos_client_remove_object (PinosClient *client, - PinosObject *object); -bool pinos_client_has_object (PinosClient *client, - PinosObject *object); +PinosResource * pinos_client_add_resource (PinosClient *client, + uint32_t type, + void *object, + PinosDestroy destroy); + +void pinos_client_remove_resource (PinosClient *client, + PinosResource *resource); +bool pinos_client_has_resource (PinosClient *client, + PinosResource *resource); #ifdef __cplusplus } diff --git a/pinos/server/core.c b/pinos/server/core.c index b3400fecf..1917611e5 100644 --- a/pinos/server/core.c +++ b/pinos/server/core.c @@ -98,7 +98,9 @@ pinos_core_add_global (PinosCore *core, global->object = object; global->skel = skel; - spa_list_insert (core->global_list.prev, &global->list); + pinos_signal_init (&global->destroy_signal); + + spa_list_insert (core->global_list.prev, &global->link); pinos_signal_emit (&core->global_added, core, global); return global; @@ -108,8 +110,10 @@ void pinos_core_remove_global (PinosCore *core, PinosGlobal *global) { + pinos_signal_emit (&global->destroy_signal, global); + + spa_list_remove (&global->link); pinos_signal_emit (&core->global_removed, core, global); - spa_list_remove (&global->list); free (global); } diff --git a/pinos/server/core.h b/pinos/server/core.h index 212a6351a..bf24bd52d 100644 --- a/pinos/server/core.h +++ b/pinos/server/core.h @@ -40,11 +40,14 @@ typedef struct _PinosGlobal PinosGlobal; struct _PinosGlobal { PinosCore *core; - SpaList list; + SpaList link; uint32_t id; uint32_t type; void *object; + PINOS_SIGNAL (destroy_signal, (PinosListener *listener, + PinosGlobal *global)); + PinosObjectSkeleton *skel; const char *object_path; }; @@ -74,7 +77,6 @@ struct _PinosCore { PINOS_SIGNAL (destroy_signal, (PinosListener *listener, PinosCore *core)); - PINOS_SIGNAL (global_added, (PinosListener *listener, PinosCore *core, PinosGlobal *global)); diff --git a/pinos/server/daemon.c b/pinos/server/daemon.c index 563ece1b8..ea4e0f2ae 100644 --- a/pinos/server/daemon.c +++ b/pinos/server/daemon.c @@ -343,7 +343,6 @@ handle_create_client_node (PinosDaemon1 *interface, props = pinos_properties_from_variant (arg_properties); node = pinos_client_node_new (this->core, - client, arg_name, props); @@ -353,7 +352,10 @@ handle_create_client_node (PinosDaemon1 *interface, if ((res = pinos_client_node_get_data_socket (node, &data_fd)) < 0) goto no_socket; - //pinos_client_add_object (client, &node->object); + pinos_client_add_resource (client, + this->core->registry.uri.client_node, + node, + (PinosDestroy) pinos_client_node_destroy); object_path = node->node->global->object_path; pinos_log_debug ("daemon %p: add client-node %p, %s", impl, node, object_path); diff --git a/pinos/server/link.c b/pinos/server/link.c index 9ac1d35f2..5fcfb1f1d 100644 --- a/pinos/server/link.c +++ b/pinos/server/link.c @@ -42,6 +42,8 @@ typedef struct PinosLink1 *iface; + uint32_t seq; + SpaFormat **format_filter; PinosProperties *properties; @@ -622,8 +624,11 @@ on_port_unlinked (PinosPort *port, PinosLink *this, SpaResult res, gulong id) { pinos_signal_emit (&this->core->port_unlinked, this, port); - if (this->input == NULL || this->output == NULL) + if (this->input == NULL || this->output == NULL) { pinos_link_update_state (this, PINOS_LINK_STATE_UNLINKED); + pinos_link_destroy (this); + } + } static void @@ -636,10 +641,14 @@ on_port_destroy (PinosLink *this, if (port == this->input) { pinos_log_debug ("link %p: input port destroyed %p", this, port); + pinos_signal_remove (&impl->input_port_destroy); + pinos_signal_remove (&impl->input_async_complete); this->input = NULL; other = this->output; } else if (port == this->output) { pinos_log_debug ("link %p: output port destroyed %p", this, port); + pinos_signal_remove (&impl->output_port_destroy); + pinos_signal_remove (&impl->output_async_complete); this->output = NULL; other = this->input; } else @@ -667,7 +676,6 @@ on_input_port_destroy (PinosListener *listener, PinosLinkImpl *impl = SPA_CONTAINER_OF (listener, PinosLinkImpl, input_port_destroy); on_port_destroy (&impl->this, port); - pinos_signal_remove (listener); } static void @@ -725,14 +733,14 @@ pinos_link_new (PinosCore *core, &impl->input_port_destroy, on_input_port_destroy); - pinos_signal_add (&this->output->destroy_signal, - &impl->output_port_destroy, - on_output_port_destroy); - pinos_signal_add (&this->input->node->async_complete, &impl->input_async_complete, on_input_async_complete_notify); + pinos_signal_add (&this->output->destroy_signal, + &impl->output_port_destroy, + on_output_port_destroy); + pinos_signal_add (&this->output->node->async_complete, &impl->output_async_complete, on_output_async_complete_notify); @@ -754,38 +762,134 @@ pinos_link_new (PinosCore *core, return this; } -/** - * pinos_link_destroy: - * @link: a #PinosLink - * - * Trigger removal of @link - */ -void -pinos_link_destroy (PinosLink * this) +static void +clear_port_buffers (PinosLink *link, PinosPort *port) { + if (!port->allocated) { + pinos_log_debug ("link %p: clear buffers on port %p", link, port); + spa_node_port_use_buffers (port->node->node, + port->direction, + port->port_id, + NULL, 0); + port->buffers = NULL; + port->n_buffers = 0; + } +} + +static SpaResult +do_link_remove_done (SpaPoll *poll, + bool async, + uint32_t seq, + size_t size, + void *data, + void *user_data) +{ + PinosLink *this = user_data; PinosLinkImpl *impl = SPA_CONTAINER_OF (this, PinosLinkImpl, this); - pinos_log_debug ("link %p: destroy", impl); - pinos_signal_emit (&this->destroy_signal, this); - if (this->input) { - pinos_signal_remove (&impl->input_port_destroy); - pinos_signal_remove (&impl->input_async_complete); + spa_list_remove (&this->input_link); + this->input->node->n_used_input_links--; + + if (this->input->node->n_used_input_links == 0 && + this->input->node->n_used_output_links == 0) + pinos_node_report_idle (this->input->node); + + clear_port_buffers (this, this->input); + this->input = NULL; } if (this->output) { - pinos_signal_remove (&impl->output_port_destroy); - pinos_signal_remove (&impl->output_async_complete); + spa_list_remove (&this->output_link); + this->output->node->n_used_output_links--; + + if (this->output->node->n_used_input_links == 0 && + this->output->node->n_used_output_links == 0) + pinos_node_report_idle (this->output->node); + + clear_port_buffers (this, this->output); + this->output = NULL; } pinos_main_loop_defer_cancel (this->core->main_loop, this, 0); - pinos_core_remove_global (this->core, this->global); - spa_list_remove (&this->list); - g_clear_object (&impl->iface); if (impl->allocated) pinos_memblock_free (&impl->buffer_mem); free (impl); + + return SPA_RESULT_OK; +} + +static SpaResult +do_link_remove (SpaPoll *poll, + bool async, + uint32_t seq, + size_t size, + void *data, + void *user_data) +{ + SpaResult res; + PinosLink *this = user_data; + + if (this->rt.input) { + spa_list_remove (&this->rt.input_link); + this->rt.input = NULL; + } + if (this->rt.output) { + spa_list_remove (&this->rt.output_link); + this->rt.output = NULL; + } + + res = spa_poll_invoke (this->core->main_loop->poll, + do_link_remove_done, + seq, + 0, + NULL, + this); + return res; +} + +/** + * pinos_link_destroy: + * @link: a #PinosLink + * + * Trigger removal of @link + */ +SpaResult +pinos_link_destroy (PinosLink * this) +{ + SpaResult res = SPA_RESULT_OK; + PinosLinkImpl *impl = SPA_CONTAINER_OF (this, PinosLinkImpl, this); + + pinos_log_debug ("link %p: destroy", impl); + pinos_signal_emit (&this->destroy_signal, this); + + pinos_core_remove_global (this->core, this->global); + spa_list_remove (&this->list); + + if (this->input) { + pinos_signal_remove (&impl->input_port_destroy); + pinos_signal_remove (&impl->input_async_complete); + + res = spa_poll_invoke (&this->input->node->data_loop->poll, + do_link_remove, + impl->seq++, + 0, + NULL, + this); + } + if (this->output) { + pinos_signal_remove (&impl->output_port_destroy); + pinos_signal_remove (&impl->output_async_complete); + + res = spa_poll_invoke (&this->output->node->data_loop->poll, + do_link_remove, + impl->seq++, + 0, + NULL, + this); + } + return res; } diff --git a/pinos/server/link.h b/pinos/server/link.h index a03289b67..3e473ad92 100644 --- a/pinos/server/link.h +++ b/pinos/server/link.h @@ -79,7 +79,7 @@ PinosLink * pinos_link_new (PinosCore *core, PinosPort *input, SpaFormat **format_filter, PinosProperties *properties); -void pinos_link_destroy (PinosLink *link); +SpaResult pinos_link_destroy (PinosLink *link); bool pinos_link_activate (PinosLink *link); bool pinos_link_deactivate (PinosLink *link); diff --git a/pinos/server/main-loop.c b/pinos/server/main-loop.c index 936cfa8ee..8fce203c9 100644 --- a/pinos/server/main-loop.c +++ b/pinos/server/main-loop.c @@ -225,9 +225,7 @@ process_work_queue (PinosMainLoop *this) impl->work_id = 0; - pinos_log_debug ("main-loop %p: %p %p", this, impl->work_list.next, &impl->work_list); spa_list_for_each_safe (item, tmp, &impl->work_list, link) { - pinos_log_debug ("main-loop %p: %p %p %d %p", this, &item->link, impl->work_list.next, item->sync, item->obj); if (item->sync) { if (&item->link == impl->work_list.next) { pinos_log_debug ("main-loop %p: found sync item %p", this, item->obj); diff --git a/pinos/server/node.c b/pinos/server/node.c index bc4849a94..11429c53f 100644 --- a/pinos/server/node.c +++ b/pinos/server/node.c @@ -399,7 +399,6 @@ handle_remove (PinosNode1 *interface, PinosNode *this = user_data; pinos_log_debug ("node %p: remove", this); - pinos_node_destroy (this); g_dbus_method_invocation_return_value (invocation, g_variant_new ("()")); @@ -585,9 +584,10 @@ do_node_remove (SpaPoll *poll, * Remove @node. This will stop the transfer on the node and * free the resources allocated by @node. */ -void +SpaResult pinos_node_destroy (PinosNode * this) { + SpaResult res; PinosNodeImpl *impl = SPA_CONTAINER_OF (this, PinosNodeImpl, this); pinos_log_debug ("node %p: destroy", impl); @@ -596,12 +596,13 @@ pinos_node_destroy (PinosNode * this) spa_list_remove (&this->list); pinos_core_remove_global (this->core, this->global); - spa_poll_invoke (&this->data_loop->poll, - do_node_remove, - impl->seq++, - 0, - NULL, - this); + res = spa_poll_invoke (&this->data_loop->poll, + do_node_remove, + impl->seq++, + 0, + NULL, + this); + return res; } /** diff --git a/pinos/server/node.h b/pinos/server/node.h index 1ae29185a..24024a0a8 100644 --- a/pinos/server/node.h +++ b/pinos/server/node.h @@ -95,7 +95,7 @@ PinosNode * pinos_node_new (PinosCore *core, SpaNode *node, SpaClock *clock, PinosProperties *properties); -void pinos_node_destroy (PinosNode *node); +SpaResult pinos_node_destroy (PinosNode *node); void pinos_node_set_data_loop (PinosNode *node, diff --git a/pinos/server/registry.c b/pinos/server/registry.c index f9dba5f67..76c801284 100644 --- a/pinos/server/registry.c +++ b/pinos/server/registry.c @@ -26,6 +26,7 @@ #include "pinos/server/node.h" #include "pinos/server/node-factory.h" #include "pinos/server/client.h" +#include "pinos/server/client-node.h" #include "spa/include/spa/monitor.h" @@ -40,6 +41,7 @@ pinos_registry_init (PinosRegistry *reg) reg->uri.node_factory = spa_id_map_get_id (reg->map, PINOS_NODE_FACTORY_URI); reg->uri.link = spa_id_map_get_id (reg->map, PINOS_LINK_URI); reg->uri.client = spa_id_map_get_id (reg->map, PINOS_CLIENT_URI); + reg->uri.client_node = spa_id_map_get_id (reg->map, PINOS_CLIENT_NODE_URI); reg->uri.spa_node = spa_id_map_get_id (reg->map, SPA_NODE_URI); reg->uri.spa_clock = spa_id_map_get_id (reg->map, SPA_CLOCK_URI); diff --git a/pinos/server/registry.h b/pinos/server/registry.h index 560b4fc0d..7efd657e9 100644 --- a/pinos/server/registry.h +++ b/pinos/server/registry.h @@ -41,6 +41,7 @@ typedef struct { uint32_t node_factory; uint32_t link; uint32_t client; + uint32_t client_node; uint32_t spa_node; uint32_t spa_clock;