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:
Nedko Arnaudov 2010-11-13 18:12:51 +02:00
parent a99c3e6408
commit 4b9da6ffae
7 changed files with 200 additions and 39 deletions

View File

@ -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)

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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 */
/**********************************************************************************/

View File

@ -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 */

View File

@ -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;
}