diff --git a/base-linux/include/base/pager.h b/base-linux/include/base/pager.h index b8aea16c04..8d7605feda 100644 --- a/base-linux/include/base/pager.h +++ b/base-linux/include/base/pager.h @@ -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 { }; diff --git a/base-linux/include/base/platform_env.h b/base-linux/include/base/platform_env.h index d18f891c9a..f7410e8025 100644 --- a/base-linux/include/base/platform_env.h +++ b/base-linux/include/base/platform_env.h @@ -412,13 +412,10 @@ namespace Genode { public: - Platform_env() - : - Platform_env_base(static_cap_cast(_parent().session("Env::ram_session", "")), - static_cap_cast(_parent().session("Env::cpu_session", "")), - static_cap_cast (_parent().session("Env::pd_session", ""))), - _heap(Platform_env_base::ram_session(), Platform_env_base::rm_session()) - { } + /** + * Constructor + */ + Platform_env(); /** * Destructor diff --git a/base-linux/src/base/env/platform_env.cc b/base-linux/src/base/env/platform_env.cc index 5b95854394..585ff0acbd 100644 --- a/base-linux/src/base/env/platform_env.cc +++ b/base-linux/src/base/env/platform_env.cc @@ -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(_parent().session("Env::ram_session", "")), + static_cap_cast(_parent().session("Env::cpu_session", "")), + static_cap_cast (_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 ** *****************************/ diff --git a/base-linux/src/base/process/process.cc b/base-linux/src/base/process/process.cc index 8d1fe4c4bb..64bb1053ec 100644 --- a/base-linux/src/base/process/process.cc +++ b/base-linux/src/base/process/process.cc @@ -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(_pd.cap())); lx_pd.assign_parent(parent_cap); diff --git a/base-linux/src/core/include/core_linux_syscalls.h b/base-linux/src/core/include/core_linux_syscalls.h index 81902a27a1..43de2b5ac2 100644 --- a/base-linux/src/core/include/core_linux_syscalls.h +++ b/base-linux/src/core/include/core_linux_syscalls.h @@ -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 ** *********************/ diff --git a/base-linux/src/core/include/platform_thread.h b/base-linux/src/core/include/platform_thread.h index 811e62d1b2..0b91ad4946 100644 --- a/base-linux/src/core/include/platform_thread.h +++ b/base-linux/src/core/include/platform_thread.h @@ -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::Element { private: + struct Registry + { + Lock _lock; + List _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); + } }; } diff --git a/base-linux/src/core/platform.cc b/base-linux/src/core/platform.cc index 017dd9b4e2..c3cfe7acf7 100644 --- a/base-linux/src/core/platform.cc +++ b/base-linux/src/core/platform.cc @@ -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); + } } } diff --git a/base-linux/src/core/platform_thread.cc b/base-linux/src/core/platform_thread.cc index fd47787f75..10e7b6a32c 100644 --- a/base-linux/src/core/platform_thread.cc +++ b/base-linux/src/core/platform_thread.cc @@ -26,10 +26,60 @@ using namespace Genode; typedef Token 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 ®istry; +} + + +/********************* + ** 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); } diff --git a/base-linux/src/core/target.mk b/base-linux/src/core/target.mk index a5746d4db0..234cd7af51 100644 --- a/base-linux/src/core/target.mk +++ b/base-linux/src/core/target.mk @@ -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