From 16ca901d9a737880b32d31e025a02ce0de01c41e Mon Sep 17 00:00:00 2001 From: Nedko Arnaudov Date: Tue, 4 May 2010 23:48:23 +0300 Subject: [PATCH] daemon: new_app command This introduces no new functionality but changes the way new apps are started. Previously new app request were not queued, they were synchronous. Now they are queued and asynchronous. --- daemon/app_supervisor.c | 302 ++++++++++++++------------------------- daemon/app_supervisor.h | 7 +- daemon/cmd.h | 12 +- daemon/cmd_load_studio.c | 2 +- daemon/cmd_new_app.c | 230 +++++++++++++++++++++++++++++ daemon/studio.c | 33 +++++ daemon/studio.h | 1 + wscript | 1 + 8 files changed, 394 insertions(+), 194 deletions(-) create mode 100644 daemon/cmd_new_app.c diff --git a/daemon/app_supervisor.c b/daemon/app_supervisor.c index 7b5480b0..cb024e9e 100644 --- a/daemon/app_supervisor.c +++ b/daemon/app_supervisor.c @@ -24,7 +24,6 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include #include #include @@ -106,23 +105,6 @@ ladish_app_supervisor_create( return true; } -struct ladish_app * ladish_app_supervisor_find_app_by_name(struct ladish_app_supervisor * supervisor_ptr, const char * name) -{ - struct list_head * node_ptr; - struct ladish_app * app_ptr; - - list_for_each(node_ptr, &supervisor_ptr->applist) - { - app_ptr = list_entry(node_ptr, struct ladish_app, siblings); - if (strcmp(app_ptr->name, name) == 0) - { - return app_ptr; - } - } - - return NULL; -} - struct ladish_app * ladish_app_supervisor_find_app_by_id(struct ladish_app_supervisor * supervisor_ptr, uint64_t id) { struct list_head * node_ptr; @@ -140,70 +122,6 @@ struct ladish_app * ladish_app_supervisor_find_app_by_id(struct ladish_app_super return NULL; } -static -struct ladish_app * -add_app_internal( - struct ladish_app_supervisor * supervisor_ptr, - const char * name, - const char * commandline, - dbus_bool_t terminal, - dbus_bool_t autorun, - uint8_t level) -{ - struct ladish_app * app_ptr; - dbus_bool_t running; - - app_ptr = malloc(sizeof(struct ladish_app)); - if (app_ptr == NULL) - { - log_error("malloc of struct ladish_app failed"); - return NULL; - } - - app_ptr->name = strdup(name); - if (app_ptr->name == NULL) - { - log_error("strdup() failed for app name"); - free(app_ptr); - return NULL; - } - - app_ptr->commandline = strdup(commandline); - if (app_ptr->commandline == NULL) - { - log_error("strdup() failed for app commandline"); - free(app_ptr->name); - free(app_ptr); - return NULL; - } - - app_ptr->terminal = terminal; - app_ptr->level = level; - app_ptr->pid = 0; - - app_ptr->id = supervisor_ptr->next_id++; - app_ptr->zombie = false; - app_ptr->hidden = false; - app_ptr->autorun = autorun; - list_add_tail(&app_ptr->siblings, &supervisor_ptr->applist); - - running = false; - dbus_signal_emit( - g_dbus_connection, - supervisor_ptr->opath, - IFACE_APP_SUPERVISOR, - "AppAdded", - "ttsbby", - &supervisor_ptr->version, - &app_ptr->id, - &app_ptr->name, - &running, - &terminal, - &app_ptr->level); - - return app_ptr; -} - void remove_app_internal(struct ladish_app_supervisor * supervisor_ptr, struct ladish_app * app_ptr) { list_del(&app_ptr->siblings); @@ -253,6 +171,91 @@ void emit_app_state_changed(struct ladish_app_supervisor * supervisor_ptr, struc #define supervisor_ptr ((struct ladish_app_supervisor *)supervisor_handle) +const char * ladish_app_supervisor_get_opath(ladish_app_supervisor_handle supervisor_handle) +{ + return supervisor_ptr->opath; +} + +ladish_app_handle ladish_app_supervisor_find_app_by_name(ladish_app_supervisor_handle supervisor_handle, const char * name) +{ + struct list_head * node_ptr; + struct ladish_app * app_ptr; + + list_for_each(node_ptr, &supervisor_ptr->applist) + { + app_ptr = list_entry(node_ptr, struct ladish_app, siblings); + if (strcmp(app_ptr->name, name) == 0) + { + return (ladish_app_handle)app_ptr; + } + } + + return NULL; +} + +ladish_app_handle +ladish_app_supervisor_add( + ladish_app_supervisor_handle supervisor_handle, + const char * name, + bool autorun, + const char * command, + bool terminal, + uint8_t level) +{ + struct ladish_app * app_ptr; + dbus_bool_t running; + + app_ptr = malloc(sizeof(struct ladish_app)); + if (app_ptr == NULL) + { + log_error("malloc of struct ladish_app failed"); + return NULL; + } + + app_ptr->name = strdup(name); + if (app_ptr->name == NULL) + { + log_error("strdup() failed for app name"); + free(app_ptr); + return NULL; + } + + app_ptr->commandline = strdup(command); + if (app_ptr->commandline == NULL) + { + log_error("strdup() failed for app commandline"); + free(app_ptr->name); + free(app_ptr); + return NULL; + } + + app_ptr->terminal = terminal; + app_ptr->level = level; + app_ptr->pid = 0; + + app_ptr->id = supervisor_ptr->next_id++; + app_ptr->zombie = false; + app_ptr->hidden = false; + app_ptr->autorun = autorun; + list_add_tail(&app_ptr->siblings, &supervisor_ptr->applist); + + running = false; + dbus_signal_emit( + g_dbus_connection, + supervisor_ptr->opath, + IFACE_APP_SUPERVISOR, + "AppAdded", + "ttsbby", + &supervisor_ptr->version, + &app_ptr->id, + &app_ptr->name, + &running, + &terminal, + &app_ptr->level); + + return (ladish_app_handle)app_ptr; +} + void ladish_app_supervisor_clear(ladish_app_supervisor_handle supervisor_handle) { struct list_head * node_ptr; @@ -340,27 +343,26 @@ ladish_app_supervisor_enum( return true; } -bool -ladish_app_supervisor_add( - ladish_app_supervisor_handle supervisor_handle, - const char * name, - bool autorun, - const char * command, - bool terminal, - uint8_t level) -{ - struct ladish_app * app_ptr; +#define app_ptr ((struct ladish_app *)app_handle) - app_ptr = add_app_internal(supervisor_ptr, name, command, terminal, autorun, level); - if (app_ptr == NULL) +bool ladish_app_supervisor_run(ladish_app_supervisor_handle supervisor_handle, ladish_app_handle app_handle) +{ + if (!loader_execute(supervisor_ptr->name, app_ptr->name, "/", app_ptr->terminal, app_ptr->commandline, &app_ptr->pid)) { - log_error("add_app_internal() failed"); return false; } + emit_app_state_changed(supervisor_ptr, app_ptr); return true; } +void ladish_app_supervisor_remove(ladish_app_supervisor_handle supervisor_handle, ladish_app_handle app_handle) +{ + remove_app_internal(supervisor_ptr, app_ptr); +} + +#undef app_ptr + void ladish_app_supervisor_autorun(ladish_app_supervisor_handle supervisor_handle) { struct list_head * node_ptr; @@ -379,7 +381,7 @@ void ladish_app_supervisor_autorun(ladish_app_supervisor_handle supervisor_handl log_info("autorun('%s', %s, '%s') called", app_ptr->name, app_ptr->terminal ? "terminal" : "shell", app_ptr->commandline); - if (!loader_execute(supervisor_ptr->name, app_ptr->name, "/", app_ptr->terminal, app_ptr->commandline, &app_ptr->pid)) + if (!ladish_app_supervisor_run((ladish_app_supervisor_handle)supervisor_ptr, (ladish_app_handle)app_ptr)) { log_error("Execution of '%s' failed", app_ptr->commandline); return; @@ -554,21 +556,15 @@ static void run_custom(struct dbus_method_call * call_ptr) { dbus_bool_t terminal; const char * commandline; - const char * name_param; + const char * name; uint8_t level; - char * name; - char * name_buffer; - size_t len; - char * end; - unsigned int index; - struct ladish_app * app_ptr; if (!dbus_message_get_args( call_ptr->message, &g_dbus_error, DBUS_TYPE_BOOLEAN, &terminal, DBUS_TYPE_STRING, &commandline, - DBUS_TYPE_STRING, &name_param, + DBUS_TYPE_STRING, &name, DBUS_TYPE_BYTE, &level, DBUS_TYPE_INVALID)) { @@ -577,95 +573,19 @@ static void run_custom(struct dbus_method_call * call_ptr) return; } - log_info("run_custom('%s', %s, '%s', %"PRIu8") called", name_param, terminal ? "terminal" : "shell", commandline, level); + log_info("run_custom('%s', %s, '%s', %"PRIu8") called", name, terminal ? "terminal" : "shell", commandline, level); - if (*name_param) + if (ladish_command_new_app( + call_ptr, + ladish_studio_get_cmd_queue(), + supervisor_ptr->opath, + terminal, + commandline, + name, + level)) { - /* allocate and copy app name */ - len = strlen(name_param); - name_buffer = malloc(len + 100); - if (name_buffer == NULL) - { - lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "malloc of app name failed"); - return; - } - - name = name_buffer; - - strcpy(name, name_param); - - end = name + len; + method_return_new_void(call_ptr); } - else - { - /* allocate app name */ - len = strlen(commandline) + 100; - name_buffer = malloc(len); - if (name_buffer == NULL) - { - lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "malloc of app name failed"); - return; - } - - strcpy(name_buffer, commandline); - - /* use first word as name */ - end = name_buffer; - while (*end) - { - if (isspace(*end)) - { - *end = 0; - break; - } - - end++; - } - - name = strrchr(name_buffer, '/'); - if (name == NULL) - { - name = name_buffer; - } - else - { - name++; - } - } - - /* make the app name unique */ - index = 2; - while (ladish_app_supervisor_find_app_by_name(supervisor_ptr, name) != NULL) - { - sprintf(end, "-%u", index); - index++; - } - - app_ptr = add_app_internal(supervisor_ptr, name, commandline, terminal, true, level); - - free(name_buffer); - - if (app_ptr == NULL) - { - lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "add_app_internal() failed"); - return; - } - - if (studio_is_started()) - { - if (!loader_execute(supervisor_ptr->name, app_ptr->name, "/", terminal, commandline, &app_ptr->pid)) - { - lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "Execution of '%s' failed", commandline); - remove_app_internal(supervisor_ptr, app_ptr); - return; - } - - log_info("%s pid is %lu", app_ptr->name, (unsigned long)app_ptr->pid); - - emit_app_state_changed(supervisor_ptr, app_ptr); - } - - method_return_new_void(call_ptr); } static void start_app(struct dbus_method_call * call_ptr) @@ -698,7 +618,7 @@ static void start_app(struct dbus_method_call * call_ptr) } app_ptr->zombie = false; - if (!loader_execute(supervisor_ptr->name, app_ptr->name, "/", app_ptr->terminal, app_ptr->commandline, &app_ptr->pid)) + if (!ladish_app_supervisor_run((ladish_app_supervisor_handle)supervisor_ptr, (ladish_app_handle)app_ptr)) { lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "Execution of '%s' failed", app_ptr->commandline); return; diff --git a/daemon/app_supervisor.h b/daemon/app_supervisor.h index 7ea673e3..9154046b 100644 --- a/daemon/app_supervisor.h +++ b/daemon/app_supervisor.h @@ -30,6 +30,7 @@ #include "common.h" typedef struct ladish_app_supervisor_tag { int unused; } * ladish_app_supervisor_handle; +typedef struct ladish_app_tag { int unused; } * ladish_app_handle; bool ladish_app_supervisor_create( @@ -58,7 +59,7 @@ void ladish_app_supervisor_clear( ladish_app_supervisor_handle supervisor_handle); -bool +ladish_app_handle ladish_app_supervisor_add( ladish_app_supervisor_handle supervisor_handle, const char * name, @@ -82,6 +83,10 @@ ladish_app_supervisor_search_app( const char * ladish_app_supervisor_get_name(ladish_app_supervisor_handle supervisor_handle); unsigned int ladish_app_supervisor_get_running_app_count(ladish_app_supervisor_handle supervisor_handle); +ladish_app_handle ladish_app_supervisor_find_app_by_name(ladish_app_supervisor_handle supervisor_handle, const char * name); +const char * ladish_app_supervisor_get_opath(ladish_app_supervisor_handle supervisor_handle); +bool ladish_app_supervisor_run(ladish_app_supervisor_handle supervisor_handle, ladish_app_handle app_handle); +void ladish_app_supervisor_remove(ladish_app_supervisor_handle supervisor_handle, ladish_app_handle app_handle); extern const struct dbus_interface_descriptor g_iface_app_supervisor; diff --git a/daemon/cmd.h b/daemon/cmd.h index 02e2784a..5435348e 100644 --- a/daemon/cmd.h +++ b/daemon/cmd.h @@ -2,7 +2,7 @@ /* * LADI Session Handler (ladish) * - * Copyright (C) 2009 Nedko Arnaudov + * Copyright (C) 2009, 2010 Nedko Arnaudov * ************************************************************************** * This file contains interface to the command queue stuff @@ -70,4 +70,14 @@ bool ladish_command_stop_studio(void * call_ptr, struct ladish_cqueue * queue_pt bool ladish_command_unload_studio(void * call_ptr, struct ladish_cqueue * queue_ptr); bool ladish_command_exit(void * call_ptr, struct ladish_cqueue * queue_ptr); +bool +ladish_command_new_app( + void * call_ptr, + struct ladish_cqueue * queue_ptr, + const char * opath, + bool terminal, + const char * commandline, + const char * name, + uint8_t level); + #endif /* #ifndef CMD_H__28542C9B_7CB8_40F8_BBB6_DCE13CBB1E7F__INCLUDED */ diff --git a/daemon/cmd_load_studio.c b/daemon/cmd_load_studio.c index 5a5e0e51..74d61bfd 100644 --- a/daemon/cmd_load_studio.c +++ b/daemon/cmd_load_studio.c @@ -793,7 +793,7 @@ static void callback_elend(void * data, const char * el) log_info("application '%s' (%s, %s, level %u) with commandline '%s'", context_ptr->str, context_ptr->terminal ? "terminal" : "shell", context_ptr->autorun ? "autorun" : "stopped", (unsigned int)context_ptr->level, context_ptr->data); - if (!ladish_app_supervisor_add(g_studio.app_supervisor, context_ptr->str, context_ptr->autorun, context_ptr->data, context_ptr->terminal, context_ptr->level)) + if (ladish_app_supervisor_add(g_studio.app_supervisor, context_ptr->str, context_ptr->autorun, context_ptr->data, context_ptr->terminal, context_ptr->level) == NULL) { log_error("ladish_app_supervisor_add() failed."); context_ptr->error = XML_TRUE; diff --git a/daemon/cmd_new_app.c b/daemon/cmd_new_app.c new file mode 100644 index 00000000..9c448dd0 --- /dev/null +++ b/daemon/cmd_new_app.c @@ -0,0 +1,230 @@ +/* -*- Mode: C ; c-basic-offset: 2 -*- */ +/* + * LADI Session Handler (ladish) + * + * Copyright (C) 2010 Nedko Arnaudov + * + ************************************************************************** + * This file contains implementation of the "new app" command + ************************************************************************** + * + * LADI Session Handler is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * LADI Session Handler is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with LADI Session Handler. If not, see + * or write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include "cmd.h" +#include "studio.h" +#include "../dbus/error.h" + +struct ladish_command_new_app +{ + struct ladish_command command; /* must be the first member */ + char * opath; + bool terminal; + char * commandline; + char * name; + uint8_t level; +}; + +#define cmd_ptr ((struct ladish_command_new_app *)context) + +static bool run(void * context) +{ + char * name; + char * name_buffer; + size_t len; + char * end; + unsigned int index; + ladish_app_supervisor_handle supervisor; + ladish_app_handle app; + + ASSERT(cmd_ptr->command.state == LADISH_COMMAND_STATE_PENDING); + + log_info("new_app command. opath='%s', name='%s', %s, commandline='%s', level=%"PRIu8") called", cmd_ptr->opath, cmd_ptr->name, cmd_ptr->terminal ? "terminal" : "shell", cmd_ptr->commandline, cmd_ptr->level); + + supervisor = ladish_studio_find_app_supervisor(cmd_ptr->opath); + if (supervisor == NULL) + { + log_error("cannot find supervisor '%s' to run app '%s'", cmd_ptr->opath, cmd_ptr->name); + return false; + } + + if (*cmd_ptr->name) + { + /* allocate and copy app name */ + len = strlen(cmd_ptr->name); + name_buffer = malloc(len + 100); + if (name_buffer == NULL) + { + log_error("malloc of app name failed"); + return false; + } + + name = name_buffer; + + strcpy(name, cmd_ptr->name); + + end = name + len; + } + else + { + /* allocate app name */ + len = strlen(cmd_ptr->commandline) + 100; + name_buffer = malloc(len); + if (name_buffer == NULL) + { + log_error("malloc of app name failed"); + return false; + } + + strcpy(name_buffer, cmd_ptr->commandline); + + /* use first word as name */ + end = name_buffer; + while (*end) + { + if (isspace(*end)) + { + *end = 0; + break; + } + + end++; + } + + name = strrchr(name_buffer, '/'); + if (name == NULL) + { + name = name_buffer; + } + else + { + name++; + } + } + + /* make the app name unique */ + index = 2; + while (ladish_app_supervisor_find_app_by_name(supervisor, name) != NULL) + { + sprintf(end, "-%u", index); + index++; + } + + app = ladish_app_supervisor_add(supervisor, name, true, cmd_ptr->commandline, cmd_ptr->terminal, cmd_ptr->level); + + free(name_buffer); + + if (app == NULL) + { + log_error("ladish_app_supervisor_add() failed"); + return false; + } + + if (studio_is_started()) + { + if (!ladish_app_supervisor_run(supervisor, app)) + { + log_error("Execution of '%s' failed", cmd_ptr->commandline); + ladish_app_supervisor_remove(supervisor, app); + return false; + } + } + + cmd_ptr->command.state = LADISH_COMMAND_STATE_DONE; + return true; +} + +static void destructor(void * context) +{ + log_info("new_app command destructor"); + free(cmd_ptr->opath); + free(cmd_ptr->commandline); + free(cmd_ptr->name); +} + +#undef cmd_ptr + +bool +ladish_command_new_app( + void * call_ptr, + struct ladish_cqueue * queue_ptr, + const char * opath, + bool terminal, + const char * commandline, + const char * name, + uint8_t level) +{ + struct ladish_command_new_app * cmd_ptr; + char * opath_dup; + char * commandline_dup; + char * name_dup; + + opath_dup = strdup(opath); + if (opath_dup == NULL) + { + lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "strdup('%s') failed.", opath_dup); + goto fail; + } + + commandline_dup = strdup(commandline); + if (commandline_dup == NULL) + { + lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "strdup('%s') failed.", commandline_dup); + goto fail_free_opath; + } + + name_dup = strdup(name); + if (name_dup == NULL) + { + lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "strdup('%s') failed.", name_dup); + goto fail_free_commandline; + } + + cmd_ptr = ladish_command_new(sizeof(struct ladish_command_new_app)); + if (cmd_ptr == NULL) + { + lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "ladish_command_new() failed."); + goto fail_free_name; + } + + cmd_ptr->command.run = run; + cmd_ptr->command.destructor = destructor; + cmd_ptr->opath = opath_dup; + cmd_ptr->commandline = commandline_dup; + cmd_ptr->name = name_dup; + cmd_ptr->terminal = terminal; + cmd_ptr->level = level; + + if (!ladish_cqueue_add_command(queue_ptr, &cmd_ptr->command)) + { + lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "ladish_cqueue_add_command() failed."); + goto fail_destroy_command; + } + + return true; + +fail_destroy_command: + free(cmd_ptr); +fail_free_name: + free(name_dup); +fail_free_commandline: + free(commandline_dup); +fail_free_opath: + free(opath_dup); +fail: + return false; +} diff --git a/daemon/studio.c b/daemon/studio.c index 5c604023..90c7bafc 100644 --- a/daemon/studio.c +++ b/daemon/studio.c @@ -639,6 +639,39 @@ struct ladish_cqueue * ladish_studio_get_cmd_queue(void) return &g_studio.cmd_queue; } +struct ladish_studio_app_supervisor_match_context +{ + const char * opath; + ladish_app_supervisor_handle supervisor; +}; + +#define iterate_context_ptr ((struct ladish_studio_app_supervisor_match_context *)context) + +static bool ladish_studio_app_supervisor_match(void * context, ladish_graph_handle graph, ladish_app_supervisor_handle app_supervisor) +{ + ASSERT(strcmp(ladish_app_supervisor_get_opath(app_supervisor), ladish_graph_get_opath(graph)) == 0); + if (strcmp(ladish_app_supervisor_get_opath(app_supervisor), iterate_context_ptr->opath) == 0) + { + ASSERT(iterate_context_ptr->supervisor == NULL); + iterate_context_ptr->supervisor = app_supervisor; + return false; /* stop iteration */ + } + + return true; /* continue iteration */ +} + +#undef iterate_context_ptr + +ladish_app_supervisor_handle ladish_studio_find_app_supervisor(const char * opath) +{ + struct ladish_studio_app_supervisor_match_context ctx; + + ctx.opath = opath; + ctx.supervisor = NULL; + studio_iterate_virtual_graphs(&ctx, ladish_studio_app_supervisor_match); + return ctx.supervisor; +} + bool studios_iterate(void * call_ptr, void * context, bool (* callback)(void * call_ptr, void * context, const char * studio, uint32_t modtime)) { DIR * dir; diff --git a/daemon/studio.h b/daemon/studio.h index 1592dbd3..8f934cdf 100644 --- a/daemon/studio.h +++ b/daemon/studio.h @@ -50,6 +50,7 @@ studio_iterate_virtual_graphs( ladish_app_supervisor_handle app_supervisor)); void studio_stop_app_supervisors(void); +ladish_app_supervisor_handle ladish_studio_find_app_supervisor(const char * opath); struct ladish_cqueue * ladish_studio_get_cmd_queue(void); #endif /* #ifndef STUDIO_H__0BEDE85E_4FB3_4D74_BC08_C373A22409C0__INCLUDED */ diff --git a/wscript b/wscript index 8e88422c..0c849e71 100644 --- a/wscript +++ b/wscript @@ -228,6 +228,7 @@ def build(bld): 'cmd_start_studio.c', 'cmd_stop_studio.c', 'cmd_unload_studio.c', + 'cmd_new_app.c', 'cmd_exit.c', 'cqueue.c', 'app_supervisor.c',