From 38272b9172dba8e9fc96e201f39fa124ecb0bd0c Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Thu, 3 Jan 2013 13:20:24 +0100 Subject: [PATCH] base-linux: let core catch SIGCHLD signals --- base-linux/src/base/thread/thread_linux.cc | 5 --- .../src/core/include/core_linux_syscalls.h | 7 +++- base-linux/src/core/platform.cc | 42 ++++++++++++++++--- base-linux/src/core/thread_linux.cc | 11 +++-- base-linux/src/platform/linux_syscalls.h | 1 + 5 files changed, 51 insertions(+), 15 deletions(-) diff --git a/base-linux/src/base/thread/thread_linux.cc b/base-linux/src/base/thread/thread_linux.cc index 312a58194a..e819a40d63 100644 --- a/base-linux/src/base/thread/thread_linux.cc +++ b/base-linux/src/base/thread/thread_linux.cc @@ -48,11 +48,6 @@ void Thread_base::_thread_start() */ lx_sigaction(LX_SIGUSR1, empty_signal_handler); - /* - * Prevent children from becoming zombies. (SIG_IGN = 1) - */ - lx_sigaction(LX_SIGCHLD, (void (*)(int))1); - Thread_base * const thread = Thread_base::myself(); /* inform core about the new thread and process ID of the new thread */ diff --git a/base-linux/src/core/include/core_linux_syscalls.h b/base-linux/src/core/include/core_linux_syscalls.h index 2bf00b00d2..81902a27a1 100644 --- a/base-linux/src/core/include/core_linux_syscalls.h +++ b/base-linux/src/core/include/core_linux_syscalls.h @@ -80,7 +80,12 @@ inline int lx_kill(int pid, int signal) inline int lx_create_process(int (*entry)(void *), void *stack, void *arg) { - int flags = CLONE_VFORK | SIGCHLD; + /* + * The low byte of the flags denotes the signal to be sent to the parent + * when the process terminates. We want core to receive SIGCHLD signals on + * this condition. + */ + int const flags = CLONE_VFORK | LX_SIGCHLD; return lx_clone((int (*)(void *))entry, stack, flags, arg); } diff --git a/base-linux/src/core/platform.cc b/base-linux/src/core/platform.cc index ed402d06c7..017dd9b4e2 100644 --- a/base-linux/src/core/platform.cc +++ b/base-linux/src/core/platform.cc @@ -32,11 +32,20 @@ using namespace Genode; */ static char _core_mem[80*1024*1024]; static Lock _wait_for_exit_lock(Lock::LOCKED); /* exit() sync */ +static bool _do_exit = false; -static void signal_handler(int signum) +static void sigint_handler(int signum) { _wait_for_exit_lock.unlock(); + _do_exit = true; +} + + +static void sigchld_handler(int signnum) +{ + _wait_for_exit_lock.unlock(); + raw_write_str("sigchld_handler called\n"); } @@ -44,7 +53,10 @@ Platform::Platform() : _core_mem_alloc(0) { /* catch control-c */ - lx_sigaction(2, signal_handler); + lx_sigaction(LX_SIGINT, sigint_handler); + + /* catch SIGCHLD */ + lx_sigaction(LX_SIGCHLD, sigchld_handler); /* create resource directory under /tmp */ lx_mkdir(resource_path(), S_IRWXU); @@ -64,9 +76,29 @@ Platform::Platform() void Platform::wait_for_exit() { - /* block until exit condition is satisfied */ - try { _wait_for_exit_lock.lock(); } - catch (Blocking_canceled) { }; + for (;;) { + + /* + * Block until a signal occurs. + */ + try { _wait_for_exit_lock.lock(); } + catch (Blocking_canceled) { }; + + /* + * Each time, the '_wait_for_exit_lock' gets unlocked, we could have + * received either a SIGINT or SIGCHLD. If a SIGINT was received, the + * '_exit' condition will be set. + */ + if (_do_exit) + return; + + /* + * If we received a SIGCHLD, we go through the list of our children to + * catch any pending terminated children. + */ + + PINF("we should check for pending terminated children"); + } } diff --git a/base-linux/src/core/thread_linux.cc b/base-linux/src/core/thread_linux.cc index c608a11d03..98bd68d43e 100644 --- a/base-linux/src/core/thread_linux.cc +++ b/base-linux/src/core/thread_linux.cc @@ -27,15 +27,18 @@ static void empty_signal_handler(int) { } void Thread_base::_thread_start() { /* - * Set signal handler such that canceled system calls get not - * transparently retried after a signal gets received. + * Set signal handler such that canceled system calls get not transparently + * retried after a signal gets received. */ lx_sigaction(LX_SIGUSR1, empty_signal_handler); /* - * Prevent children from becoming zombies. (SIG_IGN = 1) + * Deliver SIGCHLD signals to no thread other than the main thread. Core's + * main thread will handle the signals while executing the 'wait_for_exit' + * function, which is known to not hold any locks that would interfere with + * the handling of the signal. */ - lx_sigaction(LX_SIGCHLD, (void (*)(int))1); + lx_sigsetmask(LX_SIGCHLD, false); Thread_base::myself()->entry(); Thread_base::myself()->_join_lock.unlock(); diff --git a/base-linux/src/platform/linux_syscalls.h b/base-linux/src/platform/linux_syscalls.h index 7e5d0ff98c..34c631f1c7 100644 --- a/base-linux/src/platform/linux_syscalls.h +++ b/base-linux/src/platform/linux_syscalls.h @@ -237,6 +237,7 @@ inline Genode::addr_t lx_vm_reserve(Genode::addr_t base, Genode::size_t size) ***********************************************************************/ enum { + LX_SIGINT = 2, /* used by core to catch Control-C */ LX_SIGUSR1 = 10, /* used for cancel-blocking mechanism */ LX_SIGCHLD = 17, /* child process changed state, i.e., terminated */ LX_SIGCANCEL = 32, /* accoring to glibc, this equals SIGRTMIN,