daemon: better handling for non-direct childs. Fixes #62
If the first JACK client that appears has pid different from the one of the child process, send SIGUSR1 on L1 save to this first grandchild. This changeset fixes the "run L1 app in terminal" issue and the similar issue with dash (the default shell on Debian and Ubuntu, that for simple commandlines does fork() and exec() instead of just exec(), like bash does. This changeset also fixes the situation with complex commandlines that result in only one JACK client. The complex commandlines that result in multiple processes creating JACK clients are handled by sending the SIGUSR1 to the first process that creates JACK client. In future this could be improved by sending SIGUSR1 to all of them but it is probably better to avoid such situations by creating one app per JACK-creating process.
This commit is contained in:
parent
6e2e650bb5
commit
698bf81a3b
|
@ -46,6 +46,7 @@ struct ladish_app
|
|||
bool terminal;
|
||||
uint8_t level;
|
||||
pid_t pid;
|
||||
pid_t firstborn_pid;
|
||||
bool zombie; /* if true, remove when stopped */
|
||||
bool autorun;
|
||||
unsigned int state;
|
||||
|
@ -261,6 +262,7 @@ ladish_app_supervisor_add(
|
|||
app_ptr->terminal = terminal;
|
||||
app_ptr->level = level;
|
||||
app_ptr->pid = 0;
|
||||
app_ptr->firstborn_pid = 0;
|
||||
|
||||
app_ptr->id = supervisor_ptr->next_id++;
|
||||
uuid_generate(app_ptr->uuid);
|
||||
|
@ -288,15 +290,49 @@ ladish_app_supervisor_add(
|
|||
return (ladish_app_handle)app_ptr;
|
||||
}
|
||||
|
||||
static void ladish_app_send_signal(struct ladish_app * app_ptr, int sig)
|
||||
static void ladish_app_send_signal(struct ladish_app * app_ptr, int sig, bool prefer_firstborn)
|
||||
{
|
||||
pid_t pid;
|
||||
const char * signal_name;
|
||||
|
||||
ASSERT(app_ptr->state = LADISH_APP_STATE_STARTED);
|
||||
if (app_ptr->pid <= 0)
|
||||
{
|
||||
ASSERT_NO_PASS;
|
||||
return;
|
||||
}
|
||||
kill(app_ptr->pid, sig);
|
||||
|
||||
if (prefer_firstborn && app_ptr->firstborn_pid != 0)
|
||||
{
|
||||
pid = app_ptr->firstborn_pid;
|
||||
}
|
||||
else
|
||||
{
|
||||
pid = app_ptr->pid;
|
||||
}
|
||||
|
||||
switch (sig)
|
||||
{
|
||||
case SIGTERM:
|
||||
signal_name = "SIGTERM";
|
||||
break;
|
||||
case SIGKILL:
|
||||
signal_name = "SIGKILL";
|
||||
break;
|
||||
case SIGUSR1:
|
||||
signal_name = "SIGUSR1";
|
||||
break;
|
||||
default:
|
||||
signal_name = strsignal(sig);
|
||||
if (signal_name == NULL)
|
||||
{
|
||||
signal_name = "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
log_info("sending signal %d (%s) to '%s' with pid %u", sig, signal_name, app_ptr->name, (unsigned int)pid);
|
||||
|
||||
kill(pid, sig);
|
||||
}
|
||||
|
||||
void ladish_app_supervisor_clear(ladish_app_supervisor_handle supervisor_handle)
|
||||
|
@ -317,7 +353,7 @@ void ladish_app_supervisor_clear(ladish_app_supervisor_handle supervisor_handle)
|
|||
if (app_ptr->pid != 0)
|
||||
{
|
||||
log_info("terminating '%s'...", app_ptr->name);
|
||||
ladish_app_send_signal(app_ptr, SIGTERM);
|
||||
ladish_app_send_signal(app_ptr, SIGTERM, false);
|
||||
app_ptr->zombie = true;
|
||||
app_ptr->state = LADISH_APP_STATE_STOPPING;
|
||||
}
|
||||
|
@ -374,6 +410,7 @@ bool ladish_app_supervisor_child_exit(ladish_app_supervisor_handle supervisor_ha
|
|||
log_info("exit of child '%s' detected.", app_ptr->name);
|
||||
|
||||
app_ptr->pid = 0;
|
||||
app_ptr->firstborn_pid = 0;
|
||||
if (app_ptr->zombie)
|
||||
{
|
||||
remove_app_internal(supervisor_ptr, app_ptr);
|
||||
|
@ -419,6 +456,14 @@ ladish_app_supervisor_enum(
|
|||
return true;
|
||||
}
|
||||
|
||||
static inline void ladish_app_save_L1_internal(struct ladish_app * app_ptr)
|
||||
{
|
||||
if (app_ptr->level == 1)
|
||||
{
|
||||
ladish_app_send_signal(app_ptr, SIGUSR1, true);
|
||||
}
|
||||
}
|
||||
|
||||
#define app_ptr ((struct ladish_app *)app_handle)
|
||||
|
||||
bool ladish_app_supervisor_start_app(ladish_app_supervisor_handle supervisor_handle, ladish_app_handle app_handle)
|
||||
|
@ -472,23 +517,49 @@ void ladish_app_get_uuid(ladish_app_handle app_handle, uuid_t uuid)
|
|||
|
||||
void ladish_app_stop(ladish_app_handle app_handle)
|
||||
{
|
||||
ladish_app_send_signal(app_ptr, SIGTERM);
|
||||
ladish_app_send_signal(app_ptr, SIGTERM, false);
|
||||
app_ptr->state = LADISH_APP_STATE_STOPPING;
|
||||
}
|
||||
|
||||
void ladish_app_kill(ladish_app_handle app_handle)
|
||||
{
|
||||
ladish_app_send_signal(app_ptr, SIGKILL);
|
||||
ladish_app_send_signal(app_ptr, SIGKILL, false);
|
||||
app_ptr->state = LADISH_APP_STATE_KILL;
|
||||
}
|
||||
|
||||
void ladish_app_save_L1(ladish_app_handle app_handle)
|
||||
{
|
||||
if (app_ptr->level == 1)
|
||||
ladish_app_save_L1_internal(app_ptr);
|
||||
}
|
||||
|
||||
void ladish_app_add_pid(ladish_app_handle app_handle, pid_t pid)
|
||||
{
|
||||
if (app_ptr->pid == 0)
|
||||
{
|
||||
log_info("sending SIGUSR1 to '%s' with pid %u", app_ptr->name, (unsigned int)app_ptr->pid);
|
||||
ladish_app_send_signal(app_ptr, SIGUSR1);
|
||||
log_error("Associating pid with stopped app does not make sense");
|
||||
ASSERT_NO_PASS;
|
||||
return;
|
||||
}
|
||||
|
||||
if (pid <= 1) /* catch -1, 0 and 1 */
|
||||
{
|
||||
log_error("Refusing domination by ignoring pid %d", (int)pid);
|
||||
ASSERT_NO_PASS;
|
||||
return;
|
||||
}
|
||||
|
||||
if (app_ptr->pid == pid)
|
||||
{ /* The top level process that is already known */
|
||||
return;
|
||||
}
|
||||
|
||||
if (app_ptr->firstborn_pid != 0)
|
||||
{ /* Ignore non-first children */
|
||||
return;
|
||||
}
|
||||
|
||||
log_info("First grandchild with pid %u", (unsigned int)pid);
|
||||
app_ptr->firstborn_pid = pid;
|
||||
}
|
||||
|
||||
#undef app_ptr
|
||||
|
@ -530,7 +601,7 @@ void ladish_app_supervisor_stop(ladish_app_supervisor_handle supervisor_handle)
|
|||
if (app_ptr->pid != 0)
|
||||
{
|
||||
log_info("terminating '%s'...", app_ptr->name);
|
||||
ladish_app_send_signal(app_ptr, SIGTERM);
|
||||
ladish_app_send_signal(app_ptr, SIGTERM, false);
|
||||
app_ptr->autorun = true;
|
||||
app_ptr->state = LADISH_APP_STATE_STOPPING;
|
||||
}
|
||||
|
@ -556,11 +627,7 @@ void ladish_app_supervisor_save_L1(ladish_app_supervisor_handle supervisor_handl
|
|||
continue;
|
||||
}
|
||||
|
||||
if (app_ptr->level == 1)
|
||||
{
|
||||
log_info("sending SIGUSR1 to '%s' with pid %u", app_ptr->name, (unsigned int)app_ptr->pid);
|
||||
ladish_app_send_signal(app_ptr, SIGUSR1);
|
||||
}
|
||||
ladish_app_save_L1_internal(app_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -368,6 +368,14 @@ void ladish_app_kill(ladish_app_handle app_handle);
|
|||
*/
|
||||
void ladish_app_save_L1(ladish_app_handle app_handle);
|
||||
|
||||
/**
|
||||
* Associate pid with app.
|
||||
*
|
||||
* @param[in] app_handle Handle of app
|
||||
* @param[in] pid PID to associate with the app
|
||||
*/
|
||||
void ladish_app_add_pid(ladish_app_handle app_handle, pid_t pid);
|
||||
|
||||
/**
|
||||
* D-Bus interface descriptor for the app supervisor interface. The call context must be a ::ladish_app_supervisor_handle
|
||||
*/
|
||||
|
|
|
@ -55,19 +55,19 @@ UUID_DEFINE(g_a2j_uuid,0xBE,0x23,0xA2,0x42,0xE2,0xB2,0x11,0xDE,0xB7,0x95,0x00,0x
|
|||
struct app_find_context
|
||||
{
|
||||
pid_t pid;
|
||||
char * app_name;
|
||||
uuid_t app_uuid;
|
||||
ladish_graph_handle graph;
|
||||
ladish_app_handle app;
|
||||
};
|
||||
|
||||
#define app_find_context_ptr ((struct app_find_context *)context)
|
||||
|
||||
static bool get_app_properties_from_supervisor(void * context, ladish_graph_handle graph, ladish_app_supervisor_handle app_supervisor)
|
||||
static bool lookup_app_in_supervisor(void * context, ladish_graph_handle graph, ladish_app_supervisor_handle app_supervisor)
|
||||
{
|
||||
pid_t pid;
|
||||
ladish_app_handle app;
|
||||
|
||||
ASSERT(app_find_context_ptr->app_name == NULL); /* we stop iteration when app is found */
|
||||
/* we stop iteration when app is found */
|
||||
ASSERT(app_find_context_ptr->app == NULL && app_find_context_ptr->graph == NULL);
|
||||
|
||||
//log_info("checking app supervisor \"%s\" for pid %llu", ladish_app_supervisor_get_name(app_supervisor), (unsigned long long)pid);
|
||||
|
||||
|
@ -93,43 +93,34 @@ static bool get_app_properties_from_supervisor(void * context, ladish_graph_hand
|
|||
return true; /* continue app supervisor iteration */
|
||||
}
|
||||
|
||||
app_find_context_ptr->app_name = strdup(ladish_app_get_name(app));
|
||||
if (app_find_context_ptr->app_name == NULL)
|
||||
{
|
||||
log_error("strdup() failed for app name '%s'", ladish_app_get_name(app));
|
||||
}
|
||||
else
|
||||
{
|
||||
ladish_app_get_uuid(app, app_find_context_ptr->app_uuid);
|
||||
app_find_context_ptr->pid = pid;
|
||||
app_find_context_ptr->graph = graph;
|
||||
}
|
||||
app_find_context_ptr->app = app;
|
||||
app_find_context_ptr->graph = graph;
|
||||
|
||||
return false; /* stop app supervisor iteration */
|
||||
}
|
||||
|
||||
#undef app_find_context_ptr
|
||||
|
||||
static char * get_app_properties(struct virtualizer * virtualizer_ptr, pid_t pid, ladish_graph_handle * graph_ptr, uuid_t app_uuid)
|
||||
static ladish_app_handle ladish_virtualizer_find_app_by_pid(struct virtualizer * virtualizer_ptr, pid_t pid, ladish_graph_handle * graph_ptr)
|
||||
{
|
||||
struct app_find_context context;
|
||||
|
||||
context.pid = (pid_t)pid;
|
||||
context.app_name = NULL;
|
||||
context.pid = pid;
|
||||
context.app = NULL;
|
||||
context.graph = NULL;
|
||||
uuid_clear(context.app_uuid);
|
||||
|
||||
ladish_studio_iterate_virtual_graphs(&context, get_app_properties_from_supervisor);
|
||||
ladish_studio_iterate_virtual_graphs(&context, lookup_app_in_supervisor);
|
||||
|
||||
if (context.app_name != NULL)
|
||||
{
|
||||
ASSERT(context.graph != NULL);
|
||||
ASSERT(!uuid_is_null(context.app_uuid));
|
||||
*graph_ptr = context.graph;
|
||||
uuid_copy(app_uuid, context.app_uuid);
|
||||
if (context.app == NULL)
|
||||
{ /* app not found */
|
||||
ASSERT(context.graph == NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return context.app_name;
|
||||
ASSERT(context.graph != NULL);
|
||||
*graph_ptr = context.graph;
|
||||
|
||||
return context.app;
|
||||
}
|
||||
|
||||
struct find_link_port_context
|
||||
|
@ -271,7 +262,7 @@ static void client_appeared(void * context, uint64_t id, const char * jack_name)
|
|||
ladish_client_handle client;
|
||||
const char * a2j_name;
|
||||
bool is_a2j;
|
||||
char * app_name;
|
||||
ladish_app_handle app;
|
||||
uuid_t app_uuid;
|
||||
const char * name;
|
||||
pid_t pid;
|
||||
|
@ -284,7 +275,7 @@ static void client_appeared(void * context, uint64_t id, const char * jack_name)
|
|||
is_a2j = a2j_name != NULL && strcmp(a2j_name, jack_name) == 0;
|
||||
|
||||
name = jack_name;
|
||||
app_name = NULL;
|
||||
app = NULL;
|
||||
graph = NULL;
|
||||
jmcore = false;
|
||||
|
||||
|
@ -305,11 +296,13 @@ static void client_appeared(void * context, uint64_t id, const char * jack_name)
|
|||
}
|
||||
else
|
||||
{
|
||||
app_name = get_app_properties(virtualizer_ptr, pid, &graph, app_uuid);
|
||||
if (app_name != NULL)
|
||||
app = ladish_virtualizer_find_app_by_pid(virtualizer_ptr, pid, &graph);
|
||||
if (app != NULL)
|
||||
{
|
||||
log_info("app name is '%s'", app_name);
|
||||
name = app_name;
|
||||
ladish_app_get_uuid(app, app_uuid);
|
||||
ASSERT(!uuid_is_null(app_uuid));
|
||||
name = ladish_app_get_name(app);
|
||||
log_info("app name is '%s'", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -337,7 +330,7 @@ static void client_appeared(void * context, uint64_t id, const char * jack_name)
|
|||
if (ladish_client_get_jack_id(client) != 0)
|
||||
{
|
||||
log_error("Ignoring client with duplicate name '%s' ('%s')", name, jack_name);
|
||||
goto free_app_name;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ladish_client_set_jack_id(client, id);
|
||||
|
@ -349,7 +342,7 @@ static void client_appeared(void * context, uint64_t id, const char * jack_name)
|
|||
if (!ladish_client_create(is_a2j ? g_a2j_uuid : NULL, &client))
|
||||
{
|
||||
log_error("ladish_client_create() failed. Ignoring client %"PRIu64" (%s)", id, jack_name);
|
||||
goto free_app_name;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ladish_client_set_jack_id(client, id);
|
||||
|
@ -358,7 +351,7 @@ static void client_appeared(void * context, uint64_t id, const char * jack_name)
|
|||
{
|
||||
log_error("ladish_graph_add_client() failed to add client %"PRIu64" (%s) to JACK graph", id, name);
|
||||
ladish_client_destroy(client);
|
||||
goto free_app_name;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
done:
|
||||
|
@ -367,10 +360,13 @@ done:
|
|||
virtualizer_ptr->system_client_id = id;
|
||||
}
|
||||
|
||||
if (app_name != NULL)
|
||||
if (app != NULL)
|
||||
{
|
||||
/* interlink client and app */
|
||||
ladish_app_add_pid(app, pid);
|
||||
ladish_client_set_pid(client, pid);
|
||||
ladish_client_set_app(client, app_uuid);
|
||||
|
||||
ASSERT(graph);
|
||||
ladish_client_set_vgraph(client, graph);
|
||||
virtualizer_ptr->our_clients_count++;
|
||||
|
@ -386,11 +382,8 @@ done:
|
|||
ladish_client_set_vgraph(client, g_studio.studio_graph);
|
||||
}
|
||||
|
||||
free_app_name:
|
||||
if (app_name != NULL)
|
||||
{
|
||||
free(app_name);
|
||||
}
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
static void client_disappeared(void * context, uint64_t id)
|
||||
|
|
Loading…
Reference in New Issue