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:
|
private:
|
||||||
|
|
||||||
Platform_thread _platform_thread;
|
Platform_thread _platform_thread;
|
||||||
|
bool _bound; /* pd binding flag */
|
||||||
bool _bound; /* pd binding flag */
|
Signal_context_capability _sigh; /* exception handler */
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Cpu_thread_component(const char *name, unsigned priority, addr_t)
|
Cpu_thread_component(const char *name, unsigned priority, addr_t utcb,
|
||||||
: _platform_thread(name, priority), _bound(false) { }
|
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 Platform_thread * platform_thread() { return &_platform_thread; }
|
||||||
inline bool bound() const { return _bound; }
|
inline bool bound() const { return _bound; }
|
||||||
inline void bound(bool b) { _bound = b; }
|
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
|
created with this
|
||||||
session */
|
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
|
* Lookup thread in CPU session by its capability
|
||||||
*
|
*
|
||||||
|
@ -46,8 +46,15 @@ namespace Genode {
|
|||||||
Pager_capability add_client(Thread_capability thread) {
|
Pager_capability add_client(Thread_capability thread) {
|
||||||
return _local()->add_client(thread); }
|
return _local()->add_client(thread); }
|
||||||
|
|
||||||
void fault_handler(Signal_context_capability handler) {
|
void fault_handler(Signal_context_capability handler)
|
||||||
return _local()->fault_handler(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() {
|
State state() {
|
||||||
return _local()->state(); }
|
return _local()->state(); }
|
||||||
|
@ -47,15 +47,19 @@ namespace Genode {
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Platform_thread _platform_thread;
|
Platform_thread _platform_thread;
|
||||||
|
bool _bound; /* pd binding flag */
|
||||||
bool _bound; /* pd binding flag */
|
Signal_context_capability _sigh; /* exception handler */
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Cpu_thread_component(const char *name, unsigned priority,
|
Cpu_thread_component(const char *name, unsigned priority, addr_t utcb,
|
||||||
addr_t utcb)
|
Signal_context_capability sigh)
|
||||||
: _platform_thread(name, priority, utcb), _bound(false) { }
|
:
|
||||||
|
_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 Platform_thread * platform_thread() { return &_platform_thread; }
|
||||||
inline bool bound() const { return _bound; }
|
inline bool bound() const { return _bound; }
|
||||||
inline void bound(bool b) { _bound = b; }
|
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
|
created with this
|
||||||
session */
|
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
|
* Lookup thread in CPU session by its capability
|
||||||
*
|
*
|
||||||
@ -127,11 +148,9 @@ namespace Genode {
|
|||||||
** CPU session interface **
|
** 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);
|
Ram_dataspace_capability utcb(Thread_capability thread);
|
||||||
void kill_thread(Thread_capability);
|
void kill_thread(Thread_capability);
|
||||||
Thread_capability first();
|
|
||||||
Thread_capability next(Thread_capability);
|
|
||||||
int set_pager(Thread_capability, Pager_capability);
|
int set_pager(Thread_capability, Pager_capability);
|
||||||
int start(Thread_capability, addr_t, addr_t);
|
int start(Thread_capability, addr_t, addr_t);
|
||||||
void pause(Thread_capability thread_cap);
|
void pause(Thread_capability thread_cap);
|
||||||
|
@ -47,14 +47,19 @@ namespace Genode {
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Platform_thread _platform_thread;
|
Platform_thread _platform_thread;
|
||||||
|
bool _bound; /* pd binding flag */
|
||||||
bool _bound; /* pd binding flag */
|
Signal_context_capability _sigh; /* exception handler */
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Cpu_thread_component(const char *name, unsigned priority, addr_t)
|
Cpu_thread_component(const char *name, unsigned priority, addr_t utcb,
|
||||||
: _platform_thread(name, priority), _bound(false) { }
|
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 Platform_thread * platform_thread() { return &_platform_thread; }
|
||||||
inline bool bound() const { return _bound; }
|
inline bool bound() const { return _bound; }
|
||||||
inline void bound(bool b) { _bound = b; }
|
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
|
unsigned _priority; /* priority of threads
|
||||||
created with this
|
created with this
|
||||||
session */
|
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
|
* Lookup thread in CPU session by its capability
|
||||||
@ -134,7 +155,6 @@ namespace Genode {
|
|||||||
|
|
||||||
Thread_capability create_thread(Name const &, addr_t);
|
Thread_capability create_thread(Name const &, addr_t);
|
||||||
Ram_dataspace_capability utcb(Thread_capability thread);
|
Ram_dataspace_capability utcb(Thread_capability thread);
|
||||||
|
|
||||||
void kill_thread(Thread_capability);
|
void kill_thread(Thread_capability);
|
||||||
int set_pager(Thread_capability, Pager_capability);
|
int set_pager(Thread_capability, Pager_capability);
|
||||||
int start(Thread_capability, addr_t, addr_t);
|
int start(Thread_capability, addr_t, addr_t);
|
||||||
@ -150,9 +170,9 @@ namespace Genode {
|
|||||||
void affinity(Thread_capability, unsigned);
|
void affinity(Thread_capability, unsigned);
|
||||||
|
|
||||||
|
|
||||||
/***********************************
|
/******************************
|
||||||
** NOVA specific extensions **
|
** NOVA specific extensions **
|
||||||
***********************************/
|
******************************/
|
||||||
|
|
||||||
Native_capability native_cap(Thread_capability);
|
Native_capability native_cap(Thread_capability);
|
||||||
Native_capability pause_sync(Thread_capability);
|
Native_capability pause_sync(Thread_capability);
|
||||||
|
@ -147,6 +147,16 @@ namespace Genode {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Register signal handler for exceptions of the specified thread
|
* 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,
|
virtual void exception_handler(Thread_capability thread,
|
||||||
Signal_context_capability handler) = 0;
|
Signal_context_capability handler) = 0;
|
||||||
|
@ -166,6 +166,11 @@ namespace Genode {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Register signal handler for region-manager faults
|
* 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;
|
virtual void fault_handler(Signal_context_capability handler) = 0;
|
||||||
|
|
||||||
|
@ -25,6 +25,13 @@
|
|||||||
using namespace Genode;
|
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,
|
Thread_capability Cpu_session_component::create_thread(Name const &name,
|
||||||
addr_t utcb)
|
addr_t utcb)
|
||||||
{
|
{
|
||||||
@ -34,7 +41,8 @@ Thread_capability Cpu_session_component::create_thread(Name const &name,
|
|||||||
Cpu_thread_component *thread = 0;
|
Cpu_thread_component *thread = 0;
|
||||||
try {
|
try {
|
||||||
thread = new(&_thread_alloc) Cpu_thread_component(name.string(),
|
thread = new(&_thread_alloc) Cpu_thread_component(name.string(),
|
||||||
_priority, utcb);
|
_priority, utcb,
|
||||||
|
_default_exception_handler);
|
||||||
} catch (Allocator::Out_of_memory) {
|
} catch (Allocator::Out_of_memory) {
|
||||||
throw Out_of_metadata();
|
throw Out_of_metadata();
|
||||||
}
|
}
|
||||||
@ -81,6 +89,7 @@ int Cpu_session_component::set_pager(Thread_capability thread_cap,
|
|||||||
if (!p) return -2;
|
if (!p) return -2;
|
||||||
|
|
||||||
thread->platform_thread()->pager(p);
|
thread->platform_thread()->pager(p);
|
||||||
|
|
||||||
p->thread_cap(thread->cap());
|
p->thread_cap(thread->cap());
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -93,6 +102,12 @@ int Cpu_session_component::start(Thread_capability thread_cap,
|
|||||||
Cpu_thread_component *thread = _lookup_thread(thread_cap);
|
Cpu_thread_component *thread = _lookup_thread(thread_cap);
|
||||||
if (!thread) return -1;
|
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);
|
return thread->platform_thread()->start((void *)ip, (void *)sp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,10 +161,27 @@ void
|
|||||||
Cpu_session_component::exception_handler(Thread_capability thread_cap,
|
Cpu_session_component::exception_handler(Thread_capability thread_cap,
|
||||||
Signal_context_capability sigh_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:
|
private:
|
||||||
|
|
||||||
Platform_thread _platform_thread;
|
Platform_thread _platform_thread;
|
||||||
|
bool _bound; /* pd binding flag */
|
||||||
bool _bound; /* pd binding flag */
|
Signal_context_capability _sigh; /* exception handler */
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Cpu_thread_component(const char *name, unsigned priority,
|
Cpu_thread_component(const char *name, unsigned priority, addr_t utcb,
|
||||||
addr_t utcb)
|
Signal_context_capability sigh)
|
||||||
: _platform_thread(name, priority, utcb), _bound(false) { }
|
:
|
||||||
|
_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 Platform_thread * platform_thread() { return &_platform_thread; }
|
||||||
inline bool bound() const { return _bound; }
|
inline bool bound() const { return _bound; }
|
||||||
inline void bound(bool b) { _bound = b; }
|
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
|
created with this
|
||||||
session */
|
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
|
* Lookup thread in CPU session by its capability
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user