From 5483a52daf9dca6aa6cbfafc7d6d050456d49dd3 Mon Sep 17 00:00:00 2001 From: Nedko Arnaudov Date: Mon, 26 Sep 2011 05:03:57 +0300 Subject: [PATCH] ladishd: async app supervisor save. async studio and project save. --- daemon/app_supervisor.c | 8 +- daemon/app_supervisor.h | 14 ++- daemon/cmd_save_project.c | 36 ++++++- daemon/cmd_save_studio.c | 92 ++++++++++++---- daemon/room.h | 13 ++- daemon/room_save.c | 220 +++++++++++++++++++++++++------------- 6 files changed, 278 insertions(+), 105 deletions(-) diff --git a/daemon/app_supervisor.c b/daemon/app_supervisor.c index 8bf525ca..f9eb6a8e 100644 --- a/daemon/app_supervisor.c +++ b/daemon/app_supervisor.c @@ -998,7 +998,11 @@ void ladish_app_supervisor_stop(ladish_app_supervisor_handle supervisor_handle) } } -void ladish_app_supervisor_save(ladish_app_supervisor_handle supervisor_handle) +void +ladish_app_supervisor_save( + ladish_app_supervisor_handle supervisor_handle, + void * context, + ladish_save_complete_callback callback) { struct list_head * node_ptr; struct ladish_app * app_ptr; @@ -1019,6 +1023,8 @@ void ladish_app_supervisor_save(ladish_app_supervisor_handle supervisor_handle) ladish_app_initiate_save(app_ptr); } + + callback(context, true); } const char * ladish_app_supervisor_get_name(ladish_app_supervisor_handle supervisor_handle) diff --git a/daemon/app_supervisor.h b/daemon/app_supervisor.h index 989296ce..057cbe3c 100644 --- a/daemon/app_supervisor.h +++ b/daemon/app_supervisor.h @@ -85,6 +85,14 @@ typedef bool (* ladish_app_supervisor_enum_callback)( pid_t pid, const uuid_t uuid); +/** + * Type of function that is called when save is complete + * + * @param[in] context User defined context that was supplied to ladish_app_supervisor_save() + * @param[in] success Whether save was successfull or not + */ +typedef void (* ladish_save_complete_callback)(void * context, bool success); + /** * Check whether app level string is valid. * @@ -194,10 +202,14 @@ ladish_app_supervisor_clear( * Initiate save for apps running at level higher than 0 * * @param[in] supervisor_handle supervisor object handle + * @param[in] context User defined context to be supplied when callback supplied throuth @c callback parameter is called + * @param[in] callback Callback to call when save is complete */ void ladish_app_supervisor_save( - ladish_app_supervisor_handle supervisor_handle); + ladish_app_supervisor_handle supervisor_handle, + void * context, + ladish_save_complete_callback callback); /** * Add app. Apps are added in stopped state diff --git a/daemon/cmd_save_project.c b/daemon/cmd_save_project.c index ac9293c3..72c32e9e 100644 --- a/daemon/cmd_save_project.c +++ b/daemon/cmd_save_project.c @@ -36,15 +36,43 @@ struct ladish_command_save_project uuid_t room_uuid; char * project_dir; char * project_name; + bool done; + bool success; }; #define cmd_ptr ((struct ladish_command_save_project *)command_context) +void ladish_room_project_complete(void * command_context, bool success) +{ + cmd_ptr->done = true; + cmd_ptr->success = success; + + if (!success) + { + ladish_notify_simple(LADISH_NOTIFY_URGENCY_HIGH, "Project save failed", LADISH_CHECK_LOG_TEXT); + } +} + static bool run(void * command_context) { ladish_room_handle room; - ASSERT(cmd_ptr->command.state == LADISH_COMMAND_STATE_PENDING); + if (cmd_ptr->command.state == LADISH_COMMAND_STATE_WAITING) + { + if (!cmd_ptr->done) + { + return true; + } + + cmd_ptr->command.state = LADISH_COMMAND_STATE_DONE; + return cmd_ptr->success; + } + + if (cmd_ptr->command.state != LADISH_COMMAND_STATE_PENDING) + { + ASSERT_NO_PASS; + return false; + } room = ladish_studio_find_room_by_uuid(cmd_ptr->room_uuid); if (room == NULL) @@ -54,9 +82,9 @@ static bool run(void * command_context) return false; } - ladish_room_save_project(room, cmd_ptr->project_dir, cmd_ptr->project_name); + cmd_ptr->command.state = LADISH_COMMAND_STATE_WAITING; - cmd_ptr->command.state = LADISH_COMMAND_STATE_DONE; + ladish_room_save_project(room, cmd_ptr->project_dir, cmd_ptr->project_name, cmd_ptr, ladish_room_project_complete); return true; } @@ -109,6 +137,8 @@ ladish_command_save_project( cmd_ptr->command.destructor = destructor; cmd_ptr->project_dir = project_dir_dup; cmd_ptr->project_name = project_name_dup; + cmd_ptr->done = false; + cmd_ptr->success = true; if (!ladish_cqueue_add_command(queue_ptr, &cmd_ptr->command)) { diff --git a/daemon/cmd_save_studio.c b/daemon/cmd_save_studio.c index 3d45c2de..cd7de8ab 100644 --- a/daemon/cmd_save_studio.c +++ b/daemon/cmd_save_studio.c @@ -184,11 +184,11 @@ struct ladish_command_save_studio { struct ladish_command command; char * studio_name; + bool done; + bool success; }; -#define cmd_ptr ((struct ladish_command_save_studio *)command_context) - -static bool run(void * command_context) +static bool ladish_save_studio_xml(struct ladish_command_save_studio * cmd_ptr) { struct list_head * node_ptr; struct jack_conf_parameter * parameter_ptr; @@ -203,25 +203,10 @@ static bool run(void * command_context) struct ladish_write_context save_context; bool renaming; - ASSERT(cmd_ptr->command.state == LADISH_COMMAND_STATE_PENDING); - time(×tamp); ctime_r(×tamp, timestamp_str); timestamp_str[24] = 0; - ret = false; - - ladish_app_supervisor_save(g_studio.app_supervisor); - - if (!ladish_studio_is_started()) - { - log_error("Cannot save not-started studio"); - ladish_notify_simple(LADISH_NOTIFY_URGENCY_HIGH, "Cannot save not-started studio", NULL); - goto exit; - } - - ladish_check_integrity(); - if (!ladish_studio_compose_filename(cmd_ptr->studio_name, &filename, &bak_filename)) { log_error("failed to compose studio filename"); @@ -408,8 +393,6 @@ static bool run(void * command_context) g_studio.persisted = true; g_studio.automatic = false; /* even if it was automatic, it is not anymore because it is saved */ - cmd_ptr->command.state = LADISH_COMMAND_STATE_DONE; - ret = true; if (renaming) @@ -449,12 +432,73 @@ free_filenames: ASSERT(g_studio.filename != NULL); exit: - if (!ret) + return ret; +} + +#define cmd_ptr ((struct ladish_command_save_studio *)context) + +static void ladish_studio_apps_save_complete(void * context, bool success) +{ + ASSERT(cmd_ptr->command.state == LADISH_COMMAND_STATE_WAITING); + + if (!success) { - ladish_notify_simple(LADISH_NOTIFY_URGENCY_HIGH, "Studio save failed", LADISH_CHECK_LOG_TEXT); + log_info("Studio apps save failed"); + goto fail; } - return ret; + log_info("Studio apps saved successfully"); + if (ladish_save_studio_xml(cmd_ptr)) + { + goto done; + } + +fail: + ladish_notify_simple(LADISH_NOTIFY_URGENCY_HIGH, "Studio save failed", LADISH_CHECK_LOG_TEXT); + cmd_ptr->success = false; + +done: + cmd_ptr->done = true; + return; +} + +#undef cmd_ptr + +#define cmd_ptr ((struct ladish_command_save_studio *)command_context) + +static bool run(void * command_context) +{ + if (cmd_ptr->command.state == LADISH_COMMAND_STATE_WAITING) + { + if (!cmd_ptr->done) + { + return true; + } + + cmd_ptr->command.state = LADISH_COMMAND_STATE_DONE; + return cmd_ptr->success; + } + + if (cmd_ptr->command.state != LADISH_COMMAND_STATE_PENDING) + { + ASSERT_NO_PASS; + return false; + } + + if (!ladish_studio_is_started()) + { + log_error("Cannot save not-started studio"); + ladish_notify_simple(LADISH_NOTIFY_URGENCY_HIGH, "Cannot save not-started studio", NULL); + return false; + } + + ladish_check_integrity(); + + cmd_ptr->command.state = LADISH_COMMAND_STATE_WAITING; + + ladish_app_supervisor_save(g_studio.app_supervisor, cmd_ptr, ladish_studio_apps_save_complete); + + return true; } static void destructor(void * command_context) @@ -490,6 +534,8 @@ bool ladish_command_save_studio(void * call_ptr, struct ladish_cqueue * queue_pt cmd_ptr->command.run = run; cmd_ptr->command.destructor = destructor; cmd_ptr->studio_name = studio_name_dup; + cmd_ptr->done = false; + cmd_ptr->success = true; if (!ladish_cqueue_add_command(queue_ptr, &cmd_ptr->command)) { diff --git a/daemon/room.h b/daemon/room.h index b8738adc..fb958ef5 100644 --- a/daemon/room.h +++ b/daemon/room.h @@ -2,7 +2,7 @@ /* * LADI Session Handler (ladish) * - * Copyright (C) 2010 Nedko Arnaudov + * Copyright (C) 2010,2011 Nedko Arnaudov * ************************************************************************** * This file contains interface of the room object @@ -86,7 +86,16 @@ ladish_room_add_port( uint32_t type, uint32_t flags); -bool ladish_room_save_project(ladish_room_handle room_handle, const char * project_dir, const char * project_name); +typedef void (* ladish_room_save_complete_callback)(void * context, bool success); + +bool +ladish_room_save_project( + ladish_room_handle room_handle, + const char * project_dir, + const char * project_name, + void * context, + ladish_room_save_complete_callback callback); + bool ladish_room_unload_project(ladish_room_handle room_handle); bool ladish_room_load_project(ladish_room_handle room_handle, const char * project_dir); diff --git a/daemon/room_save.c b/daemon/room_save.c index 763da153..4284d793 100644 --- a/daemon/room_save.c +++ b/daemon/room_save.c @@ -41,7 +41,58 @@ #define DEFAULT_PROJECT_BASE_DIR "/ladish-projects/" #define DEFAULT_PROJECT_BASE_DIR_LEN ((size_t)(sizeof(DEFAULT_PROJECT_BASE_DIR) - 1)) -static bool ladish_room_save_project_do(struct ladish_room * room_ptr) +struct ladish_room_save_context +{ + struct ladish_room * room; + char * project_dir; + char * project_name; + char * old_project_dir; + char * old_project_name; + + void * context; + ladish_room_save_complete_callback callback; +}; + +static void ladish_room_save_context_destroy(struct ladish_room_save_context * ctx_ptr) +{ + if (ctx_ptr->project_name != NULL && ctx_ptr->project_name != ctx_ptr->room->project_name) + { + free(ctx_ptr->room->project_name); + } + + if (ctx_ptr->project_dir != NULL && ctx_ptr->project_dir != ctx_ptr->room->project_dir) + { + free(ctx_ptr->room->project_dir); + } + + /* free strings that are allocated and stored only in the stack */ + if (ctx_ptr->project_name != NULL && ctx_ptr->project_name != ctx_ptr->room->project_name) + { + free(ctx_ptr->project_name); + } + + if (ctx_ptr->project_dir != NULL && ctx_ptr->project_dir != ctx_ptr->room->project_dir) + { + free(ctx_ptr->project_dir); + } + + free(ctx_ptr); +} + +static void ladish_room_save_complete(struct ladish_room_save_context * ctx_ptr, bool success) +{ + if (!success) + { + ctx_ptr->room->project_name = ctx_ptr->old_project_name; + ctx_ptr->room->project_dir = ctx_ptr->old_project_dir; + } + + ctx_ptr->callback(ctx_ptr->context, success); + + ladish_room_save_context_destroy(ctx_ptr); +} + +static bool ladish_room_save_project_xml(struct ladish_room * room_ptr) { bool ret; time_t timestamp; @@ -51,21 +102,12 @@ static bool ladish_room_save_project_do(struct ladish_room * room_ptr) char * bak_filename; int fd; - log_info("Saving project '%s' in room '%s' to '%s'", room_ptr->project_name, room_ptr->name, room_ptr->project_dir); - - ladish_check_integrity(); - time(×tamp); ctime_r(×tamp, timestamp_str); timestamp_str[24] = 0; ret = false; - if (!ensure_dir_exist(room_ptr->project_dir, 0777)) - { - goto exit; - } - uuid_generate(room_ptr->project_uuid); /* TODO: the uuid should be changed on "save as" but not on "rename" */ uuid_unparse(room_ptr->project_uuid, uuid_str); @@ -234,10 +276,6 @@ static bool ladish_room_save_project_do(struct ladish_room * room_ptr) goto close; } - ladish_app_supervisor_save(room_ptr->app_supervisor); - - ladish_room_emit_project_properties_changed(room_ptr); - ret = true; close: @@ -250,6 +288,54 @@ exit: return ret; } +#define ctx_ptr ((struct ladish_room_save_context *)context) + +static void ladish_room_apps_save_complete(void * context, bool success) +{ + log_info("Project '%s' apps in room '%s' %s to '%s'", ctx_ptr->room->project_name, ctx_ptr->room->name, success ? "saved successfully" : "failed to save", ctx_ptr->room->project_dir); + + if (!success) + { + ladish_room_save_complete(ctx_ptr, false); + return; + } + + if (!ladish_room_save_project_xml(ctx_ptr->room)) + { + ladish_room_save_complete(ctx_ptr, false); + /* TODO: try to rollback apps save stage */ + return; + } + + ladish_room_emit_project_properties_changed(ctx_ptr->room); + + ctx_ptr->room->project_state = ROOM_PROJECT_STATE_LOADED; + + ladish_room_save_complete(ctx_ptr, true); +} + +#undef ctx_ptr + +static bool ladish_room_save_project_do(struct ladish_room_save_context * ctx_ptr) +{ + log_info("Saving project '%s' in room '%s' to '%s'", ctx_ptr->room->project_name, ctx_ptr->room->name, ctx_ptr->room->project_dir); + + ladish_check_integrity(); + + if (!ensure_dir_exist(ctx_ptr->room->project_dir, 0777)) + { + goto fail; + } + + ladish_app_supervisor_save(ctx_ptr->room->app_supervisor, ctx_ptr, ladish_room_apps_save_complete); + + return true; + +fail: + ladish_room_save_complete(ctx_ptr, false); + return false; +} + /* TODO: base dir must be a runtime setting */ char * compose_project_dir_from_name(const char * project_name) { @@ -280,21 +366,31 @@ bool ladish_room_save_project( ladish_room_handle room_handle, const char * project_dir_param, - const char * project_name_param) + const char * project_name_param, + void * context, + ladish_room_save_complete_callback callback) { + struct ladish_room_save_context * ctx_ptr; bool first_time; bool dir_supplied; bool name_supplied; - char * project_dir; - char * project_name; - char * old_project_dir; - char * old_project_name; char * buffer; bool ret; ret = false; - project_name = NULL; - project_dir = NULL; + + ctx_ptr = malloc(sizeof(struct ladish_room_save_context)); + if (ctx_ptr == NULL) + { + log_error("malloc() failed to allocate memory for room save context struct"); + goto fail; + } + + ctx_ptr->room = room_ptr; + ctx_ptr->project_name = NULL; + ctx_ptr->project_dir = NULL; + ctx_ptr->context = context; + ctx_ptr->callback = callback; /* project has either both name and dir no none of them */ ASSERT((room_ptr->project_dir == NULL && room_ptr->project_name == NULL) || (room_ptr->project_dir != NULL && room_ptr->project_name != NULL)); @@ -308,13 +404,13 @@ ladish_room_save_project( if (!dir_supplied && !name_supplied) { log_error("Cannot save unnamed project in room '%s'", room_ptr->name); - goto exit; + goto destroy_ctx; } if (dir_supplied && name_supplied) { - project_dir = strdup(project_dir_param); - project_name = strdup(project_name_param); + ctx_ptr->project_dir = strdup(project_dir_param); + ctx_ptr->project_name = strdup(project_name_param); } else if (dir_supplied) { @@ -324,89 +420,63 @@ ladish_room_save_project( if (buffer == NULL) { log_error("strdup() failed for project dir"); - goto exit; + goto destroy_ctx; } - project_name = basename(buffer); - log_info("Project name for dir '%s' will be '%s'", project_dir_param, project_name); - project_name = strdup(project_name); + ctx_ptr->project_name = basename(buffer); + log_info("Project name for dir '%s' will be '%s'", project_dir_param, ctx_ptr->project_name); + ctx_ptr->project_name = strdup(ctx_ptr->project_name); free(buffer); - project_dir = strdup(project_dir_param); /* buffer cannot be used because it may be modified by basename() */ + ctx_ptr->project_dir = strdup(project_dir_param); /* buffer cannot be used because it may be modified by basename() */ } else if (name_supplied) { ASSERT(!dir_supplied); - project_dir = compose_project_dir_from_name(project_name_param); - if (!project_dir) + ctx_ptr->project_dir = compose_project_dir_from_name(project_name_param); + if (ctx_ptr->project_dir == NULL) { - goto exit; + goto destroy_ctx; } - log_info("Project dir for name '%s' will be '%s'", project_name_param, project_dir); + log_info("Project dir for name '%s' will be '%s'", project_name_param, ctx_ptr->project_dir); - project_name = strdup(project_name_param); + ctx_ptr->project_name = strdup(project_name_param); } else { ASSERT_NO_PASS; - goto exit; + goto destroy_ctx; } - ladish_app_supervisor_set_directory(room_ptr->app_supervisor, project_dir); + ladish_app_supervisor_set_directory(room_ptr->app_supervisor, ctx_ptr->project_dir); } else { ASSERT(room_ptr->project_name != NULL); ASSERT(room_ptr->project_dir != NULL); - project_name = name_supplied ? strdup(project_name_param) : room_ptr->project_name; - project_dir = dir_supplied ? strdup(project_dir_param) : room_ptr->project_dir; + ctx_ptr->project_name = name_supplied ? strdup(project_name_param) : room_ptr->project_name; + ctx_ptr->project_dir = dir_supplied ? strdup(project_dir_param) : room_ptr->project_dir; } - if (project_name == NULL || project_dir == NULL) + if (ctx_ptr->project_name == NULL || ctx_ptr->project_dir == NULL) { log_error("strdup() failed for project name or dir"); - goto exit; + goto destroy_ctx; } - old_project_dir = room_ptr->project_dir; - old_project_name = room_ptr->project_name; - room_ptr->project_name = project_name; - room_ptr->project_dir = project_dir; - ret = ladish_room_save_project_do(room_ptr); - if (!ret) - { - room_ptr->project_name = old_project_name; - room_ptr->project_dir = old_project_dir; - } - else - { - room_ptr->project_state = ROOM_PROJECT_STATE_LOADED; - } + ctx_ptr->old_project_dir = room_ptr->project_dir; + ctx_ptr->old_project_name = room_ptr->project_name; + room_ptr->project_name = ctx_ptr->project_name; + room_ptr->project_dir = ctx_ptr->project_dir; -exit: - if (project_name != NULL && project_name != room_ptr->project_name) - { - free(room_ptr->project_name); - } + return ladish_room_save_project_do(ctx_ptr); - if (project_dir != NULL && project_dir != room_ptr->project_dir) - { - free(room_ptr->project_dir); - } - - /* free strings that are allocated and stored only in the stack */ - if (project_name != NULL && project_name != room_ptr->project_name) - { - free(project_name); - } - if (project_dir != NULL && project_dir != room_ptr->project_dir) - { - free(project_dir); - } - - return ret; +destroy_ctx: + ladish_room_save_context_destroy(ctx_ptr); +fail: + return false; } #undef room_ptr