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.
This commit is contained in:
Nedko Arnaudov 2010-05-04 23:48:23 +03:00
parent ac74633473
commit 16ca901d9a
8 changed files with 394 additions and 194 deletions

View File

@ -24,7 +24,6 @@
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <ctype.h>
#include <sys/types.h>
#include <signal.h>
@ -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;

View File

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

View File

@ -2,7 +2,7 @@
/*
* LADI Session Handler (ladish)
*
* Copyright (C) 2009 Nedko Arnaudov <nedko@arnaudov.name>
* Copyright (C) 2009, 2010 Nedko Arnaudov <nedko@arnaudov.name>
*
**************************************************************************
* 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 */

View File

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

230
daemon/cmd_new_app.c Normal file
View File

@ -0,0 +1,230 @@
/* -*- Mode: C ; c-basic-offset: 2 -*- */
/*
* LADI Session Handler (ladish)
*
* Copyright (C) 2010 Nedko Arnaudov <nedko@arnaudov.name>
*
**************************************************************************
* 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 <http://www.gnu.org/licenses/>
* or write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <ctype.h>
#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;
}

View File

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

View File

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

View File

@ -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',