base-linux: reflect SIGCHLD as Cpu_session signal

With this patch, core responds to SIGCHLD signals of terminating Genode
processes by reflecting these events as exceptions to the CPU session
interface. This way, Genode processes become able to respond to
terminating Genode child processes.
This commit is contained in:
Norman Feske 2013-01-03 16:23:11 +01:00
parent 38272b9172
commit 693d657e6a
9 changed files with 170 additions and 28 deletions

View File

@ -26,20 +26,20 @@ namespace Genode {
struct Pager_object
{
Thread_capability _thread_cap;
Thread_capability _thread_cap;
Signal_context_capability _sigh;
virtual ~Pager_object() { }
void exception_handler(Signal_context_capability) { }
void exception_handler(Signal_context_capability sigh) { _sigh = sigh; }
public:
/**
* Remember thread cap so that rm_session can tell thread that
* rm_client is gone.
*/
Thread_capability thread_cap() { return _thread_cap; } const
void thread_cap(Thread_capability cap) { _thread_cap = cap; }
/**
* Remember thread cap so that rm_session can tell thread that
* rm_client is gone.
*/
Thread_capability thread_cap() { return _thread_cap; } const
void thread_cap(Thread_capability cap) { _thread_cap = cap; }
};
class Pager_activation_base { };

View File

@ -412,13 +412,10 @@ namespace Genode {
public:
Platform_env()
:
Platform_env_base(static_cap_cast<Ram_session>(_parent().session("Env::ram_session", "")),
static_cap_cast<Cpu_session>(_parent().session("Env::cpu_session", "")),
static_cap_cast<Pd_session> (_parent().session("Env::pd_session", ""))),
_heap(Platform_env_base::ram_session(), Platform_env_base::rm_session())
{ }
/**
* Constructor
*/
Platform_env();
/**
* Destructor

View File

@ -20,6 +20,9 @@
using namespace Genode;
/****************************************************
** Support for Platform_env_base::Rm_session_mmap **
****************************************************/
@ -95,7 +98,9 @@ void Platform_env::Local_parent::close(Session_capability session)
Platform_env::Local_parent::Local_parent(Parent_capability parent_cap)
: Parent_client(parent_cap) { }
: Parent_client(parent_cap)
{
}
/******************
@ -142,6 +147,19 @@ Platform_env::Local_parent &Platform_env::_parent()
}
Platform_env::Platform_env()
:
Platform_env_base(static_cap_cast<Ram_session>(_parent().session("Env::ram_session", "")),
static_cap_cast<Cpu_session>(_parent().session("Env::cpu_session", "")),
static_cap_cast<Pd_session> (_parent().session("Env::pd_session", ""))),
_heap(Platform_env_base::ram_session(), Platform_env_base::rm_session())
{
/* register TID and PID of the main thread at core */
cpu_session()->thread_id(parent()->main_thread_cap(),
lx_getpid(), lx_gettid());
}
/*****************************
** Support for IPC library **
*****************************/

View File

@ -61,7 +61,7 @@ Process::Process(Dataspace_capability elf_data_ds_cap,
Native_pd_args const *pd_args)
:
_pd(name, pd_args),
_cpu_session_client(Cpu_session_capability()),
_cpu_session_client(cpu_session_cap),
_rm_session_client(Rm_session_capability())
{
/* check for dynamic program header */
@ -73,6 +73,15 @@ Process::Process(Dataspace_capability elf_data_ds_cap,
elf_data_ds_cap = _dynamic_linker_cap;
}
/*
* Register main thread at core
*
* At this point in time, we do not yet know the TID and PID of the new
* thread. Those information will be provided to core by the constructor of
* the 'Platform_env' of the new process.
*/
_thread0_cap = _cpu_session_client.create_thread(name);
Linux_pd_session_client lx_pd(static_cap_cast<Linux_pd_session>(_pd.cap()));
lx_pd.assign_parent(parent_cap);

View File

@ -102,6 +102,20 @@ inline int lx_setgid(unsigned int gid)
}
/**
* Query PID of any terminated child
*
* This function is called be core after having received a SIGCHLD signal to
* determine the PID of a terminated Genode process.
*
* \return PID of terminated process or -1 if no process was terminated
*/
inline int lx_pollpid()
{
return lx_syscall(SYS_waitpid, -1 /* any PID */, (int *)0, 1 /* WNOHANG */);
}
/*********************
** Chroot handling **
*********************/

View File

@ -22,10 +22,39 @@
namespace Genode {
class Platform_thread
class Platform_thread;
/*
* We hold all Platform_thread objects in a list in order to be able to
* reflect SIGCHLD as exception signals. When a SIGCHILD occurs, we
* determine the PID of the terminated child process via 'waitpid'. We use
* the list to find the 'Platform_thread' matching the TID, wherei, in
* turn, we find the exception handler's 'Signal_context_capability'.
*/
class Platform_thread : public List<Platform_thread>::Element
{
private:
struct Registry
{
Lock _lock;
List<Platform_thread> _list;
void insert(Platform_thread *thread);
void remove(Platform_thread *thread);
/**
* Trigger exception handler for 'Platform_thread' with matching PID.
*/
void submit_exception(unsigned long pid);
};
/**
* Return singleton instance of 'Platform_thread::Registry'
*/
static Registry *_registry();
unsigned long _tid;
unsigned long _pid;
char _name[32];
@ -35,6 +64,12 @@ namespace Genode {
*/
Native_connection_state _ncs;
/*
* Dummy pager object that is solely used for storing the
* 'Signal_context_capability' for the thread's exception handler.
*/
Pager_object _pager;
public:
/**
@ -62,7 +97,7 @@ namespace Genode {
/**
* Dummy implementation of platform-thread interface
*/
Pager_object *pager() { return 0; }
Pager_object *pager() { return &_pager; }
void pager(Pager_object *) { }
int start(void *ip, void *sp) { return 0; }
@ -98,6 +133,14 @@ namespace Genode {
* Return server-side socket descriptor
*/
int server_sd();
/**
* Notify Genode::Signal handler about sigchld
*/
static void submit_exception(int pid)
{
_registry()->submit_exception(pid);
}
};
}

View File

@ -31,8 +31,10 @@ using namespace Genode;
* Memory pool used for for core-local meta data
*/
static char _core_mem[80*1024*1024];
static Lock _wait_for_exit_lock(Lock::LOCKED); /* exit() sync */
static bool _do_exit = false;
static Lock _wait_for_exit_lock(Lock::LOCKED); /* wakeup of '_wait_for_exit' */
static bool _do_exit = false; /* exit condition */
static void sigint_handler(int signum)
@ -45,7 +47,6 @@ static void sigint_handler(int signum)
static void sigchld_handler(int signnum)
{
_wait_for_exit_lock.unlock();
raw_write_str("sigchld_handler called\n");
}
@ -93,11 +94,19 @@ void Platform::wait_for_exit()
return;
/*
* If we received a SIGCHLD, we go through the list of our children to
* catch any pending terminated children.
* Reflect SIGCHLD as exception signal to the signal context of the CPU
* session of the process. Because multiple children could have been
* terminated, we iterate until 'pollpid' (wrapper around 'waitpid')
* returns -1.
*/
for (;;) {
int const pid = lx_pollpid();
PINF("we should check for pending terminated children");
if (pid == -1)
break;
Platform_thread::submit_exception(pid);
}
}
}

View File

@ -26,10 +26,60 @@ using namespace Genode;
typedef Token<Scanner_policy_identifier_with_underline> Tid_token;
/*******************************
** Platform_thread::Registry **
*******************************/
void Platform_thread::Registry::insert(Platform_thread *thread)
{
Lock::Guard guard(_lock);
_list.insert(thread);
}
void Platform_thread::Registry::remove(Platform_thread *thread)
{
Lock::Guard guard(_lock);
_list.remove(thread);
}
void Platform_thread::Registry::submit_exception(unsigned long pid)
{
Lock::Guard guard(_lock);
/* traverse list to find 'Platform_thread' with matching PID */
for (Platform_thread *curr = _list.first(); curr; curr = curr->next()) {
if (curr->_tid == pid) {
Signal_context_capability sigh = curr->_pager._sigh;
if (sigh.valid())
Signal_transmitter(sigh).submit();
return;
}
}
}
Platform_thread::Registry *Platform_thread::_registry()
{
static Platform_thread::Registry registry;
return &registry;
}
/*********************
** Platform_thread **
*********************/
Platform_thread::Platform_thread(const char *name, unsigned, addr_t)
: _tid(-1), _pid(-1)
{
strncpy(_name, name, min(sizeof(_name), strlen(name)));
_registry()->insert(this);
}
@ -42,6 +92,8 @@ Platform_thread::~Platform_thread()
if (_ncs.server_sd)
lx_close(_ncs.server_sd);
_registry()->remove(this);
}

View File

@ -1,6 +1,6 @@
TARGET = core
REQUIRES = linux
LIBS = cxx ipc heap core_printf child lock raw_server syscall
LIBS = cxx ipc heap core_printf child lock raw_server syscall raw_signal
GEN_CORE_DIR = $(BASE_DIR)/src/core