mirror of
https://github.com/awesomeWM/awesome
synced 2024-11-16 07:47:22 +01:00
Reap children even across a restart
In Unix, so that a process can learn about the exit status of the child processes that it started, children become zombie processes until the parents collects their exit information. We use glib both for starting and for collecting processes. However, when awesome is restarted, the new instance inherits children, but does not know about them and does not inherit them. Fix this by explicitly tracking a list of running child processes and by serialising them across a restart via an environment variable. The new awesome instance can then watch for these child processes, but besides that it ignores them and does not use their exit status in any way. Thanks to Colin Walters for the hint with serialising the list of processes. Fixes: https://github.com/awesomeWM/awesome/issues/1193 Signed-off-by: Uli Schlachter <psychon@znc.in>
This commit is contained in:
parent
0707f52ebf
commit
e54361a374
3 changed files with 64 additions and 1 deletions
|
@ -115,6 +115,8 @@ awesome_atexit(bool restart)
|
|||
/* Disconnect *after* closing lua */
|
||||
xcb_cursor_context_free(globalconf.cursor_ctx);
|
||||
xcb_disconnect(globalconf.connection);
|
||||
|
||||
spawn_before_exit(restart);
|
||||
}
|
||||
|
||||
/** Restore the client order after a restart */
|
||||
|
|
62
spawn.c
62
spawn.c
|
@ -62,6 +62,12 @@
|
|||
/** 20 seconds timeout */
|
||||
#define AWESOME_SPAWN_TIMEOUT 20.0
|
||||
|
||||
static int
|
||||
compare_pids(const void *a, const void *b)
|
||||
{
|
||||
return *(GPid *) a - *(GPid *)b;
|
||||
}
|
||||
|
||||
/** Wrapper for unrefing startup sequence.
|
||||
*/
|
||||
static inline void
|
||||
|
@ -73,7 +79,11 @@ a_sn_startup_sequence_unref(SnStartupSequence **sss)
|
|||
DO_ARRAY(SnStartupSequence *, SnStartupSequence, a_sn_startup_sequence_unref)
|
||||
|
||||
/** The array of startup sequence running */
|
||||
SnStartupSequence_array_t sn_waits;
|
||||
static SnStartupSequence_array_t sn_waits;
|
||||
|
||||
DO_BARRAY(GPid, pid, DO_NOTHING, compare_pids)
|
||||
|
||||
static pid_array_t running_children;
|
||||
|
||||
/** Remove a SnStartupSequence pointer from an array and forget about it.
|
||||
* \param s The startup sequence to found, remove and unref.
|
||||
|
@ -256,6 +266,20 @@ spawn_start_notify(client_t *c, const char * startup_id)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
remove_running_child(GPid pid, gint status, gpointer user_data)
|
||||
{
|
||||
(void) status;
|
||||
(void) user_data;
|
||||
|
||||
GPid *pid_in_array = pid_array_lookup(&running_children, &pid);
|
||||
if (pid_in_array != NULL) {
|
||||
pid_array_remove(&running_children, pid_in_array);
|
||||
} else {
|
||||
warn("(Partially) unknown child %d exited?!", (int) pid);
|
||||
}
|
||||
}
|
||||
|
||||
/** Initialize program spawner.
|
||||
*/
|
||||
void
|
||||
|
@ -267,6 +291,40 @@ spawn_init(void)
|
|||
globalconf.default_screen,
|
||||
spawn_monitor_event,
|
||||
NULL, NULL);
|
||||
|
||||
const char* children = getenv("AWESOME_RUNNING_CHILDREN");
|
||||
while (children != NULL) {
|
||||
int pid, length;
|
||||
if (sscanf(children, "%d%n", &pid, &length) != 1)
|
||||
break;
|
||||
children += length;
|
||||
if (*children == ',')
|
||||
children++;
|
||||
|
||||
pid_array_insert(&running_children, pid);
|
||||
g_child_watch_add((GPid) pid, remove_running_child, NULL);
|
||||
}
|
||||
unsetenv("AWESOME_RUNNING_CHILDREN");
|
||||
}
|
||||
|
||||
/** Called right before exit, serialise state in case of a restart.
|
||||
*/
|
||||
void
|
||||
spawn_before_exit(bool restart)
|
||||
{
|
||||
if (!restart)
|
||||
return;
|
||||
|
||||
buffer_t buffer;
|
||||
buffer_init(&buffer);
|
||||
foreach(pid, running_children) {
|
||||
if(buffer.len != 0)
|
||||
buffer_addc(&buffer, ',');
|
||||
buffer_addf(&buffer, "%d", (int) *pid);
|
||||
}
|
||||
if(buffer.len != 0)
|
||||
setenv("AWESOME_RUNNING_CHILDREN", buffer.s, 1);
|
||||
buffer_wipe(&buffer);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -345,6 +403,7 @@ child_exit_callback(GPid pid, gint status, gpointer user_data)
|
|||
{
|
||||
lua_State *L = globalconf_get_lua_State();
|
||||
int exit_callback = GPOINTER_TO_INT(user_data);
|
||||
remove_running_child(pid, status, user_data);
|
||||
|
||||
/* 'Decode' the exit status */
|
||||
if (WIFEXITED(status)) {
|
||||
|
@ -458,6 +517,7 @@ luaA_spawn(lua_State *L)
|
|||
int exit_callback = LUA_REFNIL;
|
||||
/* Only do this down here to avoid leaks in case of errors */
|
||||
luaA_registerfct(L, 6, &exit_callback);
|
||||
pid_array_insert(&running_children, pid);
|
||||
g_child_watch_add(pid, child_exit_callback, GINT_TO_POINTER(exit_callback));
|
||||
}
|
||||
|
||||
|
|
1
spawn.h
1
spawn.h
|
@ -27,6 +27,7 @@
|
|||
#include <lua.h>
|
||||
|
||||
void spawn_init(void);
|
||||
void spawn_before_exit(bool);
|
||||
void spawn_start_notify(client_t *, const char *);
|
||||
int luaA_spawn(lua_State *);
|
||||
|
||||
|
|
Loading…
Reference in a new issue