mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-19 03:06:39 +00:00
core: Introduce default CPU exception handler
The CPU session interfaces comes with the ability to install an exception handler per thread. This patch enhances the feature with the provision of a default signal handler that is used if no thread-specific handler is installed. The default signal handler can be set by specifying an invalid thread capability and a valid signal context capability. Furthermore, this patch relaxes the requirement of the order of the calls of 'exception_handler' and 'set_pager'. Originally, the exception handler could be installed not before setting a pager. Now, we remember the installed exception handler in the 'Cpu_thread' and propagate to to the platform thread at a later time.
This commit is contained in:
parent
9b24115c08
commit
9f82764316
@ -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
|
||||
*
|
||||
|
@ -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(); }
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user