hw: sync signal contexts directly as user

Kernel::signal_context_kill can be used by any program to halt the processing
of a signal context synchronously to prevent broken refs when core destructs
the according kernel object. In turn, Kernel::bin_signal_context doesn't block
anymore and destructs a signal context no matter if there are unacknowledged
signals. This way, cores entrypoint doesn't depend on signal acks of a
untrustworthy client anymore.

ref #989
This commit is contained in:
Martin Stein 2013-12-06 00:12:43 +01:00 committed by Norman Feske
parent 2bdf0e70e9
commit 1c8c30e1f4
6 changed files with 94 additions and 37 deletions

View File

@ -55,16 +55,17 @@ namespace Kernel
AWAIT_REQUEST_MSG = 14,
NEW_SIGNAL_RECEIVER = 15,
NEW_SIGNAL_CONTEXT = 16,
BIN_SIGNAL_CONTEXT = 17,
BIN_SIGNAL_RECEIVER = 18,
SUBMIT_SIGNAL = 19,
AWAIT_SIGNAL = 20,
SIGNAL_PENDING = 21,
ACK_SIGNAL = 22,
NEW_VM = 23,
RUN_VM = 24,
PAUSE_VM = 25,
PRINT_CHAR = 26,
KILL_SIGNAL_CONTEXT = 17,
BIN_SIGNAL_CONTEXT = 18,
BIN_SIGNAL_RECEIVER = 19,
SUBMIT_SIGNAL = 20,
AWAIT_SIGNAL = 21,
SIGNAL_PENDING = 22,
ACK_SIGNAL = 23,
NEW_VM = 24,
RUN_VM = 25,
PAUSE_VM = 26,
PRINT_CHAR = 27,
};
};
@ -522,6 +523,20 @@ namespace Kernel
}
/**
* Halt processing of a signal context synchronously
*
* \param context kernel name of the targeted signal context
*
* \retval 0 suceeded
* \retval -1 failed
*/
inline int kill_signal_context(unsigned const context)
{
return call(Call_id::KILL_SIGNAL_CONTEXT, context);
}
/**
* Destruct a signal context
*

View File

@ -123,6 +123,9 @@ void Signal_receiver::_platform_destructor()
void Signal_receiver::_unsynchronized_dissolve(Signal_context * const c)
{
/* wait untill all context references disappear and put context to sleep */
Kernel::kill_signal_context(c->_cap.dst());
/* release server resources of context */
signal_connection()->free_context(c->_cap);

View File

@ -67,7 +67,11 @@ void Signal_context::_deliverable()
}
Signal_context::~Signal_context() { _receiver->_context_killed(this); }
Signal_context::~Signal_context()
{
if (_killer) { _killer->_signal_context_kill_failed(); }
_receiver->_context_destructed(this);
}
Signal_context::Signal_context(Signal_receiver * const r, unsigned const imprint)
@ -78,7 +82,7 @@ Signal_context::Signal_context(Signal_receiver * const r, unsigned const imprint
_imprint(imprint),
_submits(0),
_ack(1),
_kill(0),
_killed(0),
_killer(0),
_ack_handler(&_default_ack_handler)
{

View File

@ -161,20 +161,25 @@ class Kernel::Signal_context_killer
Signal_context * _context;
/**
* Backend for for destructor and cancel_waiting
* Backend for destructor and cancel_waiting
*/
void _cancel_waiting();
/**
* Notice that the destruction is pending
* Notice that the kill operation is pending
*/
virtual void _signal_context_kill_pending() = 0;
/**
* Notice that pending destruction is done
* Notice that pending kill operation is done
*/
virtual void _signal_context_kill_done() = 0;
/**
* Notice that pending kill operation failed
*/
virtual void _signal_context_kill_failed() = 0;
protected:
/***************
@ -282,7 +287,7 @@ class Kernel::Signal_context
unsigned const _imprint;
unsigned _submits;
bool _ack;
bool _kill;
bool _killed;
Signal_context_killer * _killer;
Default_ack_handler _default_ack_handler;
Signal_ack_handler * _ack_handler;
@ -302,19 +307,17 @@ class Kernel::Signal_context
}
/**
* Notice that the killer of the context has been destructed
* Notice that the killer of the context has cancelled waiting
*/
void _killer_cancelled() { _killer = 0; }
protected:
public:
/**
* Destructor
*/
~Signal_context();
public:
/**
* Exception types
*/
@ -351,7 +354,7 @@ class Kernel::Signal_context
*/
int submit(unsigned const n)
{
if (_kill || _submits >= (unsigned)~0 - n) { return -1; }
if (_killed || _submits >= (unsigned)~0 - n) { return -1; }
_submits += n;
if (_ack) { _deliverable(); }
return 0;
@ -364,15 +367,15 @@ class Kernel::Signal_context
{
_ack_handler->_signal_acknowledged();
if (_ack) { return; }
if (!_kill) {
if (!_killed) {
_ack = 1;
_deliverable();
return;
}
this->~Signal_context();
if (_killer) {
_killer->_context = 0;
_killer->_signal_context_kill_done();
_killer = 0;
}
}
@ -386,16 +389,19 @@ class Kernel::Signal_context
*/
int kill(Signal_context_killer * const k)
{
if (_kill) { return -1; }
/* destruct directly if there is no unacknowledged delivery */
/* check if in a kill operation or already killed */
if (_killed) {
if (_ack) { return 0; }
return -1;
}
/* kill directly if there is no unacknowledged delivery */
if (_ack) {
this->~Signal_context();
_killed = 1;
return 0;
}
/* wait for delivery acknowledgement */
_killer = k;
_kill = 1;
_killer = k;
_killed = 1;
_killer->_context = this;
_killer->_signal_context_kill_pending();
return 0;
@ -464,11 +470,11 @@ class Kernel::Signal_receiver
}
/**
* Notice that a context of the receiver has been killed
* Notice that a context of the receiver has been destructed
*
* \param c killed context
*/
void _context_killed(Signal_context * const c)
void _context_destructed(Signal_context * const c)
{
_contexts.remove(&c->_contexts_fe);
if (!c->_deliver_fe.is_enqueued()) { return; }
@ -520,6 +526,8 @@ class Kernel::Signal_receiver
}
}
void _signal_context_kill_failed() { PERR("unexpected call"); }
public:
/**
@ -569,6 +577,7 @@ class Kernel::Signal_receiver
Signal_context * c = _contexts.dequeue()->object();
while (c) {
c->kill(this);
c->~Signal_context();
c = _contexts.dequeue()->object();
}
/* destruct directly if no context kill is pending */

View File

@ -48,6 +48,14 @@ void Thread::_signal_context_kill_done()
}
void Thread::_signal_context_kill_failed()
{
assert(_state == AWAITS_SIGNAL_CONTEXT_KILL);
user_arg_0(-1);
_schedule();
}
void Thread::_signal_receiver_kill_pending()
{
assert(_state == SCHEDULED);
@ -815,6 +823,25 @@ void Thread::_call_ack_signal()
}
void Thread::_call_kill_signal_context()
{
/* lookup signal context */
unsigned const id = user_arg_1();
Signal_context * const c = Signal_context::pool()->object(id);
if (!c) {
PERR("unknown signal context");
user_arg_0(-1);
return;
}
/* kill signal context */
if (c->kill(this)) {
PERR("failed to kill signal context");
user_arg_0(-1);
return;
}
}
void Thread::_call_bin_signal_context()
{
/* check permissions */
@ -831,12 +858,8 @@ void Thread::_call_bin_signal_context()
user_arg_0(0);
return;
}
/* kill signal context */
if (c->kill(this)) {
PERR("failed to kill signal context");
user_arg_0(-1);
return;
}
/* destruct signal context */
c->~Signal_context();
user_arg_0(0);
}
@ -958,6 +981,7 @@ void Thread::_call()
case Call_id::PRINT_CHAR: _call_print_char(); return;
case Call_id::NEW_SIGNAL_RECEIVER: _call_new_signal_receiver(); return;
case Call_id::NEW_SIGNAL_CONTEXT: _call_new_signal_context(); return;
case Call_id::KILL_SIGNAL_CONTEXT: _call_kill_signal_context(); return;
case Call_id::BIN_SIGNAL_CONTEXT: _call_bin_signal_context(); return;
case Call_id::BIN_SIGNAL_RECEIVER: _call_bin_signal_receiver(); return;
case Call_id::AWAIT_SIGNAL: _call_await_signal(); return;

View File

@ -222,6 +222,7 @@ class Kernel::Thread
void _call_signal_pending();
void _call_submit_signal();
void _call_ack_signal();
void _call_kill_signal_context();
void _call_bin_signal_context();
void _call_bin_signal_receiver();
void _call_new_vm();
@ -236,6 +237,7 @@ class Kernel::Thread
***************************/
void _signal_context_kill_pending();
void _signal_context_kill_failed();
void _signal_context_kill_done();