ladishd: do a better cleanup on project unload and on load failure. Partial fix for #117
The project state now is can now have more than one state. The project unload sequence now first removes all connections, then stopps all apps, and as last step - clears the graph. When project load fails, ladish_room_unload_project() is not called anymore, because unloading of room even without apps is now a multistep process. Instead, a new function, ladish_room_clear_project(), is introduced. It is called when project load fails and as last step in project unload.
This commit is contained in:
parent
a99c3e6408
commit
4b9da6ffae
|
@ -335,11 +335,12 @@ static void ladish_app_send_signal(struct ladish_app * app_ptr, int sig, bool pr
|
|||
kill(pid, sig);
|
||||
}
|
||||
|
||||
void ladish_app_supervisor_clear(ladish_app_supervisor_handle supervisor_handle)
|
||||
bool ladish_app_supervisor_clear(ladish_app_supervisor_handle supervisor_handle)
|
||||
{
|
||||
struct list_head * node_ptr;
|
||||
struct list_head * safe_node_ptr;
|
||||
struct ladish_app * app_ptr;
|
||||
bool lifeless;
|
||||
|
||||
if (supervisor_ptr->dir != NULL)
|
||||
{
|
||||
|
@ -347,6 +348,8 @@ void ladish_app_supervisor_clear(ladish_app_supervisor_handle supervisor_handle)
|
|||
supervisor_ptr->dir = NULL;
|
||||
}
|
||||
|
||||
lifeless = true;
|
||||
|
||||
list_for_each_safe(node_ptr, safe_node_ptr, &supervisor_ptr->applist)
|
||||
{
|
||||
app_ptr = list_entry(node_ptr, struct ladish_app, siblings);
|
||||
|
@ -356,6 +359,7 @@ void ladish_app_supervisor_clear(ladish_app_supervisor_handle supervisor_handle)
|
|||
ladish_app_send_signal(app_ptr, SIGTERM, false);
|
||||
app_ptr->zombie = true;
|
||||
app_ptr->state = LADISH_APP_STATE_STOPPING;
|
||||
lifeless = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -363,6 +367,8 @@ void ladish_app_supervisor_clear(ladish_app_supervisor_handle supervisor_handle)
|
|||
remove_app_internal(supervisor_ptr, app_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
return lifeless;
|
||||
}
|
||||
|
||||
void ladish_app_supervisor_destroy(ladish_app_supervisor_handle supervisor_handle)
|
||||
|
|
|
@ -155,8 +155,10 @@ ladish_app_supervisor_enum(
|
|||
* once it quits.
|
||||
*
|
||||
* @param[in] supervisor_handle supervisor object handle
|
||||
*
|
||||
* @return Whether there were no running apps
|
||||
*/
|
||||
void
|
||||
bool
|
||||
ladish_app_supervisor_clear(
|
||||
ladish_app_supervisor_handle supervisor_handle);
|
||||
|
||||
|
|
|
@ -2078,6 +2078,57 @@ void ladish_try_connect_hidden_connections(ladish_graph_handle graph_handle)
|
|||
}
|
||||
}
|
||||
|
||||
bool ladish_disconnect_visible_connections(ladish_graph_handle graph_handle)
|
||||
{
|
||||
struct list_head * node_ptr;
|
||||
struct ladish_graph_connection * connection_ptr;
|
||||
|
||||
if (graph_ptr->disconnect_handler == NULL)
|
||||
{
|
||||
ASSERT_NO_PASS;
|
||||
return false;
|
||||
}
|
||||
|
||||
ASSERT(graph_ptr->opath != NULL);
|
||||
|
||||
list_for_each(node_ptr, &graph_ptr->connections)
|
||||
{
|
||||
connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
|
||||
log_debug(
|
||||
"checking connection (%s, %s) '%s':'%s' (%s) to '%s':'%s' (%s)",
|
||||
connection_ptr->hidden ? "hidden" : "visible",
|
||||
connection_ptr->changing ? "changing" : "not changing",
|
||||
connection_ptr->port1_ptr->client_ptr->name,
|
||||
connection_ptr->port1_ptr->name,
|
||||
connection_ptr->port1_ptr->hidden ? "hidden" : "visible",
|
||||
connection_ptr->port2_ptr->client_ptr->name,
|
||||
connection_ptr->port2_ptr->name,
|
||||
connection_ptr->port2_ptr->hidden ? "hidden" : "visible");
|
||||
if (!connection_ptr->hidden &&
|
||||
!connection_ptr->changing &&
|
||||
!connection_ptr->port1_ptr->hidden &&
|
||||
!connection_ptr->port2_ptr->hidden)
|
||||
{
|
||||
log_info(
|
||||
"disconnecting '%s':'%s' from '%s':'%s'",
|
||||
connection_ptr->port1_ptr->client_ptr->name,
|
||||
connection_ptr->port1_ptr->name,
|
||||
connection_ptr->port2_ptr->client_ptr->name,
|
||||
connection_ptr->port2_ptr->name);
|
||||
|
||||
connection_ptr->changing = true;
|
||||
if (!graph_ptr->disconnect_handler(graph_ptr->context, graph_handle, connection_ptr->id))
|
||||
{
|
||||
connection_ptr->changing = false;
|
||||
log_error("disconnect failed.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ladish_graph_hide_non_virtual(ladish_graph_handle graph_handle)
|
||||
{
|
||||
struct list_head * node_ptr;
|
||||
|
@ -2431,11 +2482,10 @@ bool ladish_graph_is_persist(ladish_graph_handle graph_handle)
|
|||
return graph_ptr->persist;
|
||||
}
|
||||
|
||||
bool ladish_graph_looks_empty(ladish_graph_handle graph_handle)
|
||||
bool ladish_graph_has_visible_connections(ladish_graph_handle graph_handle)
|
||||
{
|
||||
struct list_head * node_ptr;
|
||||
struct ladish_graph_connection * connection_ptr;
|
||||
struct ladish_graph_client * client_ptr;
|
||||
|
||||
list_for_each(node_ptr, &graph_ptr->connections)
|
||||
{
|
||||
|
@ -2443,10 +2493,23 @@ bool ladish_graph_looks_empty(ladish_graph_handle graph_handle)
|
|||
|
||||
if (!connection_ptr->hidden)
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ladish_graph_looks_empty(ladish_graph_handle graph_handle)
|
||||
{
|
||||
struct list_head * node_ptr;
|
||||
struct ladish_graph_client * client_ptr;
|
||||
|
||||
if (ladish_graph_has_visible_connections(graph_handle))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
list_for_each(node_ptr, &graph_ptr->clients)
|
||||
{
|
||||
client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
|
||||
|
@ -2459,6 +2522,34 @@ bool ladish_graph_looks_empty(ladish_graph_handle graph_handle)
|
|||
return true;
|
||||
}
|
||||
|
||||
void ladish_graph_remove_hidden_objects(ladish_graph_handle graph_handle)
|
||||
{
|
||||
struct list_head * node_ptr;
|
||||
struct list_head * temp_node_ptr;
|
||||
struct ladish_graph_client * client_ptr;
|
||||
struct ladish_graph_connection * connection_ptr;
|
||||
|
||||
log_info("ladish_graph_remove_hidden_objects() called for graph '%s'", graph_ptr->opath != NULL ? graph_ptr->opath : "JACK");
|
||||
|
||||
list_for_each_safe(node_ptr, temp_node_ptr, &graph_ptr->connections)
|
||||
{
|
||||
connection_ptr = list_entry(node_ptr, struct ladish_graph_connection, siblings);
|
||||
if (connection_ptr->hidden)
|
||||
{
|
||||
ladish_graph_remove_connection_internal(graph_ptr, connection_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_safe(node_ptr, temp_node_ptr, &graph_ptr->clients)
|
||||
{
|
||||
client_ptr = list_entry(node_ptr, struct ladish_graph_client, siblings);
|
||||
if (client_ptr->hidden)
|
||||
{
|
||||
ladish_graph_remove_client_internal(graph_ptr, client_ptr, true, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Trick the world that graph objects disappear and the reapper so the new dict values are fetched */
|
||||
/* This is a nasty hack and should be removed once dict object can emit signals */
|
||||
void ladish_graph_trick_dicts(ladish_graph_handle graph_handle)
|
||||
|
|
|
@ -172,6 +172,7 @@ void ladish_graph_hide_client(ladish_graph_handle graph_handle, ladish_client_ha
|
|||
void ladish_graph_adjust_port(ladish_graph_handle graph_handle, ladish_port_handle port_handle, uint32_t type, uint32_t flags);
|
||||
void ladish_graph_show_connection(ladish_graph_handle graph_handle, uint64_t connection_id);
|
||||
void ladish_try_connect_hidden_connections(ladish_graph_handle graph_handle);
|
||||
bool ladish_disconnect_visible_connections(ladish_graph_handle graph_handle);
|
||||
void ladish_graph_hide_non_virtual(ladish_graph_handle graph_handle);
|
||||
void ladish_graph_get_port_uuid(ladish_graph_handle graph, ladish_port_handle port, uuid_t uuid_ptr);
|
||||
bool ladish_graph_client_has_visible_app_port(ladish_graph_handle graph, ladish_client_handle client, const uuid_t app_uuid);
|
||||
|
@ -225,6 +226,9 @@ void ladish_graph_clear_persist(ladish_graph_handle graph_handle);
|
|||
void ladish_graph_set_persist(ladish_graph_handle graph_handle);
|
||||
bool ladish_graph_is_persist(ladish_graph_handle graph_handle);
|
||||
bool ladish_graph_looks_empty(ladish_graph_handle graph_handle);
|
||||
bool ladish_graph_has_visible_connections(ladish_graph_handle graph_handle);
|
||||
|
||||
void ladish_graph_remove_hidden_objects(ladish_graph_handle graph_handle);
|
||||
|
||||
void ladish_graph_trick_dicts(ladish_graph_handle graph_handle);
|
||||
|
||||
|
|
110
daemon/room.c
110
daemon/room.c
|
@ -286,7 +286,7 @@ ladish_room_create(
|
|||
|
||||
room_ptr->project_name = NULL;
|
||||
room_ptr->project_dir = NULL;
|
||||
room_ptr->project_unloading = false;
|
||||
room_ptr->project_state = ROOM_PROJECT_STATE_UNLOADED;
|
||||
|
||||
if (template != NULL)
|
||||
{
|
||||
|
@ -654,49 +654,69 @@ ladish_remove_room_app(
|
|||
|
||||
bool ladish_room_unload_project(ladish_room_handle room_handle)
|
||||
{
|
||||
if (!room_ptr->project_unloading)
|
||||
switch (room_ptr->project_state)
|
||||
{
|
||||
case ROOM_PROJECT_STATE_UNLOADED:
|
||||
return true;
|
||||
|
||||
case ROOM_PROJECT_STATE_LOADED:
|
||||
if (!ladish_app_supervisor_has_apps(room_ptr->app_supervisor) &&
|
||||
!ladish_graph_has_visible_connections(room_ptr->graph))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
log_info("Disconnecting ports within room...");
|
||||
ladish_disconnect_visible_connections(room_ptr->graph);
|
||||
|
||||
room_ptr->project_state = ROOM_PROJECT_STATE_UNLOADING_CONNECTIONS;
|
||||
return false;
|
||||
|
||||
case ROOM_PROJECT_STATE_UNLOADING_CONNECTIONS:
|
||||
if (ladish_graph_has_visible_connections(room_ptr->graph))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
log_info("Ports within room disconnected");
|
||||
|
||||
if (!ladish_app_supervisor_has_apps(room_ptr->app_supervisor))
|
||||
{
|
||||
goto done;
|
||||
break;
|
||||
}
|
||||
|
||||
log_info("Stopping room apps...");
|
||||
ladish_graph_dump(room_ptr->graph);
|
||||
room_ptr->project_unloading = true;
|
||||
//ladish_graph_clear_persist(room_ptr->graph);
|
||||
ladish_app_supervisor_stop(room_ptr->app_supervisor);
|
||||
|
||||
room_ptr->project_state = ROOM_PROJECT_STATE_UNLOADING_APPS;
|
||||
return false;
|
||||
|
||||
case ROOM_PROJECT_STATE_UNLOADING_APPS:
|
||||
if (!ladish_app_supervisor_enum(room_ptr->app_supervisor, room_ptr, ladish_room_app_is_stopped))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* remove app clients, ports and connections */
|
||||
ladish_app_supervisor_enum(room_ptr->app_supervisor, room_ptr, ladish_remove_room_app);
|
||||
|
||||
ladish_app_supervisor_clear(room_ptr->app_supervisor);
|
||||
ASSERT(!ladish_app_supervisor_has_apps(room_ptr->app_supervisor));
|
||||
|
||||
//ladish_graph_set_persist(room_ptr->graph);
|
||||
|
||||
log_info("Room apps stopped.");
|
||||
break;
|
||||
|
||||
default:
|
||||
ASSERT_NO_PASS;
|
||||
log_error("unknown project state");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ladish_app_supervisor_enum(room_ptr->app_supervisor, room_ptr, ladish_room_app_is_stopped))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* remove app clients, ports and connections */
|
||||
ladish_app_supervisor_enum(room_ptr->app_supervisor, room_ptr, ladish_remove_room_app);
|
||||
|
||||
ladish_app_supervisor_clear(room_ptr->app_supervisor);
|
||||
ASSERT(!ladish_app_supervisor_has_apps(room_ptr->app_supervisor));
|
||||
|
||||
//ladish_graph_set_persist(room_ptr->graph);
|
||||
|
||||
log_info("Room apps stopped.");
|
||||
ladish_graph_dump(room_ptr->graph);
|
||||
room_ptr->project_unloading = false;
|
||||
|
||||
done:
|
||||
if (room_ptr->project_name != NULL)
|
||||
{
|
||||
free(room_ptr->project_name);
|
||||
room_ptr->project_name = NULL;
|
||||
}
|
||||
if (room_ptr->project_dir != NULL)
|
||||
{
|
||||
free(room_ptr->project_dir);
|
||||
room_ptr->project_dir = NULL;
|
||||
}
|
||||
ladish_room_clear_project(room_ptr);
|
||||
|
||||
ladish_room_emit_project_properties_changed(room_ptr);
|
||||
|
||||
|
@ -847,6 +867,32 @@ void ladish_room_emit_project_properties_changed(struct ladish_room * room_ptr)
|
|||
dbus_message_unref(message_ptr);
|
||||
}
|
||||
|
||||
void ladish_room_clear_project(struct ladish_room * room_ptr)
|
||||
{
|
||||
if (!ladish_app_supervisor_clear(room_ptr->app_supervisor))
|
||||
{
|
||||
ASSERT_NO_PASS;
|
||||
}
|
||||
|
||||
ASSERT(!ladish_app_supervisor_has_apps(room_ptr->app_supervisor));
|
||||
|
||||
ladish_graph_remove_hidden_objects(room_ptr->graph);
|
||||
|
||||
if (room_ptr->project_name != NULL)
|
||||
{
|
||||
free(room_ptr->project_name);
|
||||
room_ptr->project_name = NULL;
|
||||
}
|
||||
if (room_ptr->project_dir != NULL)
|
||||
{
|
||||
free(room_ptr->project_dir);
|
||||
room_ptr->project_dir = NULL;
|
||||
}
|
||||
|
||||
room_ptr->project_state = ROOM_PROJECT_STATE_UNLOADED;
|
||||
ladish_graph_dump(room_ptr->graph);
|
||||
}
|
||||
|
||||
/**********************************************************************************/
|
||||
/* D-Bus methods */
|
||||
/**********************************************************************************/
|
||||
|
|
|
@ -31,6 +31,11 @@
|
|||
|
||||
#define LADISH_PROJECT_FILENAME "/ladish-project.xml"
|
||||
|
||||
#define ROOM_PROJECT_STATE_UNLOADED 0
|
||||
#define ROOM_PROJECT_STATE_LOADED 1
|
||||
#define ROOM_PROJECT_STATE_UNLOADING_CONNECTIONS 2
|
||||
#define ROOM_PROJECT_STATE_UNLOADING_APPS 3
|
||||
|
||||
struct ladish_room
|
||||
{
|
||||
struct list_head siblings;
|
||||
|
@ -50,12 +55,13 @@ struct ladish_room
|
|||
ladish_client_handle client;
|
||||
bool started;
|
||||
|
||||
bool project_unloading;
|
||||
unsigned int project_state;
|
||||
uuid_t project_uuid;
|
||||
char * project_dir;
|
||||
char * project_name;
|
||||
};
|
||||
|
||||
void ladish_room_emit_project_properties_changed(struct ladish_room * room_ptr);
|
||||
void ladish_room_clear_project(struct ladish_room * room_ptr);
|
||||
|
||||
#endif /* #ifndef ROOM_INTERNAL_H__FAF5B68F_E419_442A_8F9B_C729BAC00422__INCLUDED */
|
||||
|
|
|
@ -662,9 +662,11 @@ bool ladish_room_load_project(ladish_room_handle room_handle, const char * proje
|
|||
|
||||
log_info("Loading project '%s' into room '%s'", project_dir, room_ptr->name);
|
||||
|
||||
ASSERT(room_ptr->project_state == ROOM_PROJECT_STATE_UNLOADED);
|
||||
ASSERT(room_ptr->project_dir == NULL);
|
||||
ASSERT(room_ptr->project_name == NULL);
|
||||
ASSERT(!ladish_app_supervisor_has_apps(room_ptr->app_supervisor));
|
||||
ASSERT(!ladish_graph_has_visible_connections(room_ptr->graph));
|
||||
|
||||
ret = false;
|
||||
|
||||
|
@ -767,9 +769,13 @@ free_path:
|
|||
exit:
|
||||
if (!ret)
|
||||
{
|
||||
ladish_room_unload_project(room_handle);
|
||||
ladish_room_clear_project(room_ptr);
|
||||
ladish_notify_simple(LADISH_NOTIFY_URGENCY_HIGH, "Project load failed", LADISH_CHECK_LOG_TEXT);
|
||||
}
|
||||
else
|
||||
{
|
||||
room_ptr->project_state = ROOM_PROJECT_STATE_LOADED;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue