diff --git a/daemon/cmd_delete_room.c b/daemon/cmd_delete_room.c index 802cb485..7dac8be9 100644 --- a/daemon/cmd_delete_room.c +++ b/daemon/cmd_delete_room.c @@ -27,6 +27,7 @@ #include "cmd.h" #include "studio_internal.h" #include "../dbus/error.h" +#include "../proxies/jmcore_proxy.h" struct ladish_command_delete_room { @@ -34,6 +35,37 @@ struct ladish_command_delete_room char * name; }; +static +bool +uninit_room_ports( + void * context, + void * client_iteration_context_ptr, + ladish_client_handle client_handle, + const char * client_name, + ladish_port_handle port_handle, + const char * port_name, + uint32_t port_type, + uint32_t port_flags) +{ + uuid_t uuid_in_room; + char uuid_in_room_str[37]; + + if (ladish_port_is_link(port_handle)) + { + log_info("link port %s", port_name); + + ladish_graph_get_port_uuid(ladish_room_get_graph(context), port_handle, uuid_in_room); + uuid_unparse(uuid_in_room, uuid_in_room_str); + jmcore_proxy_destroy_link(uuid_in_room_str); + } + else + { + log_info("jack port %s", port_name); + } + + return true; +} + #define cmd_ptr ((struct ladish_command_delete_room *)context) static bool run(void * context) @@ -43,44 +75,78 @@ static bool run(void * context) uuid_t room_uuid; ladish_client_handle room_client; unsigned int running_app_count; + ladish_app_supervisor_handle supervisor; + ladish_graph_handle graph; - ASSERT(cmd_ptr->command.state == LADISH_COMMAND_STATE_PENDING); - - log_info("Delete studio room request (%s)", cmd_ptr->name); + if (cmd_ptr->command.state == LADISH_COMMAND_STATE_PENDING) + { + log_info("Delete studio room request (%s)", cmd_ptr->name); + } list_for_each(node_ptr, &g_studio.rooms) { room = ladish_room_from_list_node(node_ptr); if (strcmp(ladish_room_get_name(room), cmd_ptr->name) == 0) { - running_app_count = ladish_app_supervisor_get_running_app_count(ladish_room_get_app_supervisor(room)); - if (running_app_count != 0) - { - /* TODO: instead of rejecting the room deletion, use the command queue and wait for room apps to stop. - This requires proper "project in room" implementation because project needs to be - unloaded anyway and unloading project should initiate and wait apps termination */ - log_error("Cannot delete room \"%s\" because it has %u app(s) running", cmd_ptr->name, running_app_count); - return false; - } - - list_del(node_ptr); - ladish_studio_emit_room_disappeared(room); - - ladish_room_get_uuid(room, room_uuid); - room_client = ladish_graph_find_client_by_uuid(g_studio.studio_graph, room_uuid); - ASSERT(room_client != NULL); - ladish_graph_remove_client(g_studio.studio_graph, room_client); - ladish_client_destroy(room_client); - - ladish_room_destroy(room); - - cmd_ptr->command.state = LADISH_COMMAND_STATE_DONE; - return true; + goto found; } } log_error("Cannot delete room with name \"%s\" because it is unknown", cmd_ptr->name); return false; + +found: + supervisor = ladish_room_get_app_supervisor(room); + graph = ladish_room_get_graph(room); + ladish_room_get_uuid(room, room_uuid); + room_client = ladish_graph_find_client_by_uuid(g_studio.studio_graph, room_uuid); + ASSERT(room_client != NULL); + + if (cmd_ptr->command.state == LADISH_COMMAND_STATE_PENDING) + { + ladish_graph_clear_persist(graph); + ladish_graph_iterate_nodes(ladish_room_get_graph(room), false, room, NULL, uninit_room_ports, NULL); + ladish_app_supervisor_stop(supervisor); + + cmd_ptr->command.state = LADISH_COMMAND_STATE_WAITING; + return true; + } + + ASSERT(cmd_ptr->command.state == LADISH_COMMAND_STATE_WAITING); + + running_app_count = ladish_app_supervisor_get_running_app_count(supervisor); + if (running_app_count != 0) + { + log_info("there are %u running app(s) in room \"%s\"", running_app_count, cmd_ptr->name); + return true; + } + + if (!ladish_graph_is_empty(graph)) + { + log_info("the room \"%s\" graph is still not empty", cmd_ptr->name); + return true; + } + + if (!ladish_graph_is_client_looks_empty(g_studio.studio_graph, room_client)) + { + log_info("the room \"%s\" studio client still does not look empty", cmd_ptr->name); + return true; + } + + /* ladish_graph_dump(graph); */ + /* ladish_graph_dump(g_studio.studio_graph); */ + /* ladish_graph_dump(g_studio.jack_graph); */ + + list_del(node_ptr); + ladish_studio_emit_room_disappeared(room); + + ladish_graph_remove_client(g_studio.studio_graph, room_client); + ladish_client_destroy(room_client); + + ladish_room_destroy(room); + + cmd_ptr->command.state = LADISH_COMMAND_STATE_DONE; + return true; } static void destructor(void * context) diff --git a/daemon/graph.c b/daemon/graph.c index 02c16408..fd1e04e8 100644 --- a/daemon/graph.c +++ b/daemon/graph.c @@ -77,6 +77,7 @@ struct ladish_graph uint64_t next_client_id; uint64_t next_port_id; uint64_t next_connection_id; + bool persist; void * context; ladish_graph_connect_request_handler connect_handler; @@ -640,6 +641,8 @@ bool ladish_graph_create(ladish_graph_handle * graph_handle_ptr, const char * op graph_ptr->connect_handler = NULL; graph_ptr->disconnect_handler = NULL; + graph_ptr->persist = true; + *graph_handle_ptr = (ladish_graph_handle)graph_ptr; return true; } @@ -2159,6 +2162,21 @@ void ladish_graph_dump(ladish_graph_handle graph_handle) } } +void ladish_graph_clear_persist(ladish_graph_handle graph_handle) +{ + graph_ptr->persist = false; +} + +bool ladish_graph_is_persist(ladish_graph_handle graph_handle) +{ + return graph_ptr->persist; +} + +bool ladish_graph_is_empty(ladish_graph_handle graph_handle) +{ + return list_empty(&graph_ptr->clients) && list_empty(&graph_ptr->ports) && list_empty(&graph_ptr->connections); +} + #undef graph_ptr #define graph_ptr ((struct ladish_graph *)context) diff --git a/daemon/graph.h b/daemon/graph.h index 369d2510..b3840d7b 100644 --- a/daemon/graph.h +++ b/daemon/graph.h @@ -194,6 +194,10 @@ ladish_graph_iterate_connections( void * callback_context, bool (* callback)(void * context, ladish_port_handle port1_handle, ladish_port_handle port2_handle, ladish_dict_handle dict)); +void ladish_graph_clear_persist(ladish_graph_handle graph_handle); +bool ladish_graph_is_persist(ladish_graph_handle graph_handle); +bool ladish_graph_is_empty(ladish_graph_handle graph_handle); + extern const struct dbus_interface_descriptor g_interface_patchbay; #endif /* #ifndef PATCHBAY_H__30334B9A_8847_4E8C_AFF9_73DB13406C8E__INCLUDED */ diff --git a/daemon/virtualizer.c b/daemon/virtualizer.c index 1dd5b56b..6d73f559 100644 --- a/daemon/virtualizer.c +++ b/daemon/virtualizer.c @@ -375,6 +375,7 @@ static void client_disappeared(void * context, uint64_t id) { ladish_client_handle client; pid_t pid; + ladish_graph_handle vgraph; log_info("client_disappeared(%"PRIu64")", id); @@ -387,12 +388,7 @@ static void client_disappeared(void * context, uint64_t id) log_info("client disappeared: '%s'", ladish_graph_get_client_name(virtualizer_ptr->jack_graph, client)); - if (ladish_client_get_vgraph(client) == NULL) - { /* remove jmcore clients, the are not persisted in the jack graph */ - ladish_graph_remove_client(virtualizer_ptr->jack_graph, client); - ladish_client_destroy(client); - return; - } + vgraph = ladish_client_get_vgraph(client); pid = ladish_client_get_pid(client); if (pid != 0 && pid != jmcore_proxy_get_pid_cached()) @@ -405,7 +401,7 @@ static void client_disappeared(void * context, uint64_t id) virtualizer_ptr->system_client_id = 0; } - if (true) /* if client is supposed to be persisted */ + if (vgraph != NULL && ladish_graph_is_persist(vgraph)) /* if client is supposed to be persisted */ { ladish_client_set_jack_id(client, 0); ladish_graph_hide_client(virtualizer_ptr->jack_graph, client); @@ -743,15 +739,15 @@ static void port_disappeared(void * context, uint64_t client_id, uint64_t port_i if (vgraph == NULL) { log_error("Cannot find vgraph for disappeared jmcore port"); + ASSERT_NO_PASS; + return; } - else - { - jmcore = true; - ladish_graph_remove_port_by_jack_id(virtualizer_ptr->jack_graph, port_id, true, true); - } + + jmcore = true; + ladish_graph_remove_port_by_jack_id(virtualizer_ptr->jack_graph, port_id, true, true); } - if (true) /* if client is supposed to be persisted */ + if (ladish_graph_is_persist(vgraph)) /* if port is supposed to be persisted */ { if (!jmcore) {