From 1c8c30e1f419d73eb60216f0213659c5e17dd0e8 Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Fri, 6 Dec 2013 00:12:43 +0100 Subject: [PATCH] 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 --- base-hw/include/kernel/interface.h | 35 +++++++++++----- base-hw/src/base/signal/signal.cc | 3 ++ base-hw/src/core/kernel/signal_receiver.cc | 8 +++- base-hw/src/core/kernel/signal_receiver.h | 47 +++++++++++++--------- base-hw/src/core/kernel/thread.cc | 36 ++++++++++++++--- base-hw/src/core/kernel/thread.h | 2 + 6 files changed, 94 insertions(+), 37 deletions(-) diff --git a/base-hw/include/kernel/interface.h b/base-hw/include/kernel/interface.h index 9c1a12e409..e513cd2c76 100644 --- a/base-hw/include/kernel/interface.h +++ b/base-hw/include/kernel/interface.h @@ -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 * diff --git a/base-hw/src/base/signal/signal.cc b/base-hw/src/base/signal/signal.cc index e6be8517c2..f18c2e5865 100644 --- a/base-hw/src/base/signal/signal.cc +++ b/base-hw/src/base/signal/signal.cc @@ -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); diff --git a/base-hw/src/core/kernel/signal_receiver.cc b/base-hw/src/core/kernel/signal_receiver.cc index 54357a3429..e0c2975069 100644 --- a/base-hw/src/core/kernel/signal_receiver.cc +++ b/base-hw/src/core/kernel/signal_receiver.cc @@ -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) { diff --git a/base-hw/src/core/kernel/signal_receiver.h b/base-hw/src/core/kernel/signal_receiver.h index f0b39201e2..9004bb2ad6 100644 --- a/base-hw/src/core/kernel/signal_receiver.h +++ b/base-hw/src/core/kernel/signal_receiver.h @@ -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 */ diff --git a/base-hw/src/core/kernel/thread.cc b/base-hw/src/core/kernel/thread.cc index 3ec40a867b..3cc5818fa3 100644 --- a/base-hw/src/core/kernel/thread.cc +++ b/base-hw/src/core/kernel/thread.cc @@ -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; diff --git a/base-hw/src/core/kernel/thread.h b/base-hw/src/core/kernel/thread.h index 80e181cb91..b0b9077e00 100644 --- a/base-hw/src/core/kernel/thread.h +++ b/base-hw/src/core/kernel/thread.h @@ -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();