diff --git a/base-foc/src/core/include/cpu_session_component.h b/base-foc/src/core/include/cpu_session_component.h index 49dddc76f..a1dfbf5c0 100644 --- a/base-foc/src/core/include/cpu_session_component.h +++ b/base-foc/src/core/include/cpu_session_component.h @@ -47,14 +47,19 @@ namespace Genode { { private: - Platform_thread _platform_thread; - - bool _bound; /* pd binding flag */ + Platform_thread _platform_thread; + bool _bound; /* pd binding flag */ + Signal_context_capability _sigh; /* exception handler */ public: - Cpu_thread_component(const char *name, unsigned priority, addr_t) - : _platform_thread(name, priority), _bound(false) { } + Cpu_thread_component(const char *name, unsigned priority, addr_t utcb, + Signal_context_capability sigh) + : + _platform_thread(name, priority), _bound(false), _sigh(sigh) + { + update_exception_sigh(); + } /************************ @@ -64,6 +69,17 @@ namespace Genode { inline Platform_thread * platform_thread() { return &_platform_thread; } inline bool bound() const { return _bound; } inline void bound(bool b) { _bound = b; } + + void sigh(Signal_context_capability sigh) + { + sigh = sigh; + update_exception_sigh(); + } + + /** + * Propagate exception handler to platform thread + */ + void update_exception_sigh(); }; @@ -88,6 +104,12 @@ namespace Genode { created with this session */ + /** + * Exception handler that will be invoked unless overridden by a + * call of 'Cpu_session::exception_handler'. + */ + Signal_context_capability _default_exception_handler; + /** * Lookup thread in CPU session by its capability * diff --git a/base-linux/include/rm_session/client.h b/base-linux/include/rm_session/client.h index 81df0edba..d81ab2fae 100644 --- a/base-linux/include/rm_session/client.h +++ b/base-linux/include/rm_session/client.h @@ -46,8 +46,15 @@ namespace Genode { Pager_capability add_client(Thread_capability thread) { return _local()->add_client(thread); } - void fault_handler(Signal_context_capability handler) { - return _local()->fault_handler(handler); } + void fault_handler(Signal_context_capability handler) + { + /* + * On Linux, page faults are never reflected to RM clients. They + * are always handled by the kernel. If a segmentation fault + * occurs, this condition is being reflected as a CPU exception + * to the handler registered via 'Cpu_session::exception_handler'. + */ + } State state() { return _local()->state(); } diff --git a/base-linux/src/core/include/cpu_session_component.h b/base-linux/src/core/include/cpu_session_component.h index 5c5612fec..a682452d4 100644 --- a/base-linux/src/core/include/cpu_session_component.h +++ b/base-linux/src/core/include/cpu_session_component.h @@ -47,15 +47,19 @@ namespace Genode { { private: - Platform_thread _platform_thread; - - bool _bound; /* pd binding flag */ + Platform_thread _platform_thread; + bool _bound; /* pd binding flag */ + Signal_context_capability _sigh; /* exception handler */ public: - Cpu_thread_component(const char *name, unsigned priority, - addr_t utcb) - : _platform_thread(name, priority, utcb), _bound(false) { } + Cpu_thread_component(const char *name, unsigned priority, addr_t utcb, + Signal_context_capability sigh) + : + _platform_thread(name, priority, utcb), _bound(false), _sigh(sigh) + { + update_exception_sigh(); + } /************************ @@ -65,6 +69,17 @@ namespace Genode { inline Platform_thread * platform_thread() { return &_platform_thread; } inline bool bound() const { return _bound; } inline void bound(bool b) { _bound = b; } + + void sigh(Signal_context_capability sigh) + { + sigh = sigh; + update_exception_sigh(); + } + + /** + * Propagate exception handler to platform thread + */ + void update_exception_sigh(); }; @@ -83,6 +98,12 @@ namespace Genode { created with this session */ + /** + * Exception handler that will be invoked unless overridden by a + * call of 'Cpu_session::exception_handler'. + */ + Signal_context_capability _default_exception_handler; + /** * Lookup thread in CPU session by its capability * @@ -127,11 +148,9 @@ namespace Genode { ** CPU session interface ** ***************************/ - Thread_capability create_thread(Name const &, addr_t utcb); + Thread_capability create_thread(Name const &, addr_t); Ram_dataspace_capability utcb(Thread_capability thread); void kill_thread(Thread_capability); - Thread_capability first(); - Thread_capability next(Thread_capability); int set_pager(Thread_capability, Pager_capability); int start(Thread_capability, addr_t, addr_t); void pause(Thread_capability thread_cap); diff --git a/base-nova/src/core/include/cpu_session_component.h b/base-nova/src/core/include/cpu_session_component.h index c08e2275f..d68ae9952 100644 --- a/base-nova/src/core/include/cpu_session_component.h +++ b/base-nova/src/core/include/cpu_session_component.h @@ -47,14 +47,19 @@ namespace Genode { { private: - Platform_thread _platform_thread; - - bool _bound; /* pd binding flag */ + Platform_thread _platform_thread; + bool _bound; /* pd binding flag */ + Signal_context_capability _sigh; /* exception handler */ public: - Cpu_thread_component(const char *name, unsigned priority, addr_t) - : _platform_thread(name, priority), _bound(false) { } + Cpu_thread_component(const char *name, unsigned priority, addr_t utcb, + Signal_context_capability sigh) + : + _platform_thread(name, priority, utcb), _bound(false), _sigh(sigh) + { + update_exception_sigh(); + } /************************ @@ -64,6 +69,17 @@ namespace Genode { inline Platform_thread * platform_thread() { return &_platform_thread; } inline bool bound() const { return _bound; } inline void bound(bool b) { _bound = b; } + + void sigh(Signal_context_capability sigh) + { + sigh = sigh; + update_exception_sigh(); + } + + /** + * Propagate exception handler to platform thread + */ + void update_exception_sigh(); }; @@ -87,6 +103,11 @@ namespace Genode { unsigned _priority; /* priority of threads created with this session */ + /** + * Exception handler that will be invoked unless overridden by a + * call of 'Cpu_session::exception_handler'. + */ + Signal_context_capability _default_exception_handler; /** * Lookup thread in CPU session by its capability @@ -134,7 +155,6 @@ namespace Genode { Thread_capability create_thread(Name const &, addr_t); Ram_dataspace_capability utcb(Thread_capability thread); - void kill_thread(Thread_capability); int set_pager(Thread_capability, Pager_capability); int start(Thread_capability, addr_t, addr_t); @@ -150,9 +170,9 @@ namespace Genode { void affinity(Thread_capability, unsigned); - /*********************************** + /****************************** ** NOVA specific extensions ** - ***********************************/ + ******************************/ Native_capability native_cap(Thread_capability); Native_capability pause_sync(Thread_capability); diff --git a/base/include/cpu_session/cpu_session.h b/base/include/cpu_session/cpu_session.h index 98316c181..82a5797a3 100644 --- a/base/include/cpu_session/cpu_session.h +++ b/base/include/cpu_session/cpu_session.h @@ -147,6 +147,16 @@ namespace Genode { /** * Register signal handler for exceptions of the specified thread + * + * If 'thread' is an invalid capability, the default exception + * handler for the CPU session is set. This handler is used for + * all threads that have no explicitly installed exception handler. + * The new default signal handler will take effect for threads + * created after the call. + * + * On Linux, this exception is delivered when the process triggers + * a SIGCHLD. On other platforms, this exception is delivered on + * the occurrence of CPU exceptions such as division by zero. */ virtual void exception_handler(Thread_capability thread, Signal_context_capability handler) = 0; diff --git a/base/include/rm_session/rm_session.h b/base/include/rm_session/rm_session.h index 207909bc8..d324a7db7 100644 --- a/base/include/rm_session/rm_session.h +++ b/base/include/rm_session/rm_session.h @@ -166,6 +166,11 @@ namespace Genode { /** * Register signal handler for region-manager faults + * + * On Linux, this signal is never delivered because page-fault handling + * is performed by the Linux kernel. On microkernel platforms, + * unresolvable page faults (traditionally called segmentation fault) + * will result in the delivery of the signal. */ virtual void fault_handler(Signal_context_capability handler) = 0; diff --git a/base/src/core/cpu_session_component.cc b/base/src/core/cpu_session_component.cc index fd42a48be..b644c1d4b 100644 --- a/base/src/core/cpu_session_component.cc +++ b/base/src/core/cpu_session_component.cc @@ -25,6 +25,13 @@ using namespace Genode; +void Cpu_thread_component::update_exception_sigh() +{ + if (platform_thread()->pager()) + platform_thread()->pager()->exception_handler(_sigh); +}; + + Thread_capability Cpu_session_component::create_thread(Name const &name, addr_t utcb) { @@ -34,7 +41,8 @@ Thread_capability Cpu_session_component::create_thread(Name const &name, Cpu_thread_component *thread = 0; try { thread = new(&_thread_alloc) Cpu_thread_component(name.string(), - _priority, utcb); + _priority, utcb, + _default_exception_handler); } catch (Allocator::Out_of_memory) { throw Out_of_metadata(); } @@ -81,6 +89,7 @@ int Cpu_session_component::set_pager(Thread_capability thread_cap, if (!p) return -2; thread->platform_thread()->pager(p); + p->thread_cap(thread->cap()); return 0; @@ -93,6 +102,12 @@ int Cpu_session_component::start(Thread_capability thread_cap, Cpu_thread_component *thread = _lookup_thread(thread_cap); if (!thread) return -1; + /* + * If an exception handler was installed prior to the call of 'set_pager', + * we need to update the pager object with the current exception handler. + */ + thread->update_exception_sigh(); + return thread->platform_thread()->start((void *)ip, (void *)sp); } @@ -146,10 +161,27 @@ void Cpu_session_component::exception_handler(Thread_capability thread_cap, Signal_context_capability sigh_cap) { - Cpu_thread_component *thread = _lookup_thread(thread_cap); - if (!thread || !thread->platform_thread()->pager()) return; + /* + * By specifying an invalid thread capability, the caller sets the default + * exception handler for the CPU session. + */ + if (!thread_cap.valid()) { + _default_exception_handler = sigh_cap; + return; + } - thread->platform_thread()->pager()->exception_handler(sigh_cap); + /* + * If an invalid signal handler is specified for a valid thread, we revert + * the signal handler to the CPU session's default signal handler. + */ + if (!sigh_cap.valid()) { + sigh_cap = _default_exception_handler; + } + + Cpu_thread_component *thread = _lookup_thread(thread_cap); + if (!thread) return; + + thread->sigh(sigh_cap); } diff --git a/base/src/core/include/cpu_session_component.h b/base/src/core/include/cpu_session_component.h index dc9c982be..9ea97fefc 100644 --- a/base/src/core/include/cpu_session_component.h +++ b/base/src/core/include/cpu_session_component.h @@ -46,15 +46,19 @@ namespace Genode { { private: - Platform_thread _platform_thread; - - bool _bound; /* pd binding flag */ + Platform_thread _platform_thread; + bool _bound; /* pd binding flag */ + Signal_context_capability _sigh; /* exception handler */ public: - Cpu_thread_component(const char *name, unsigned priority, - addr_t utcb) - : _platform_thread(name, priority, utcb), _bound(false) { } + Cpu_thread_component(const char *name, unsigned priority, addr_t utcb, + Signal_context_capability sigh) + : + _platform_thread(name, priority, utcb), _bound(false), _sigh(sigh) + { + update_exception_sigh(); + } /************************ @@ -64,6 +68,17 @@ namespace Genode { inline Platform_thread * platform_thread() { return &_platform_thread; } inline bool bound() const { return _bound; } inline void bound(bool b) { _bound = b; } + + void sigh(Signal_context_capability sigh) + { + sigh = sigh; + update_exception_sigh(); + } + + /** + * Propagate exception handler to platform thread + */ + void update_exception_sigh(); }; @@ -82,6 +97,12 @@ namespace Genode { created with this session */ + /** + * Exception handler that will be invoked unless overridden by a + * call of 'Cpu_session::exception_handler'. + */ + Signal_context_capability _default_exception_handler; + /** * Lookup thread in CPU session by its capability *