base/signal.h: remove pointers from API

This patch updates the signal API to avoid raw pointers, and
replaces the Context_already_in_use and Context_not_associated
exceptions by diagnostic messages.

Fixes #5247
This commit is contained in:
Norman Feske 2024-06-13 15:25:59 +02:00
parent dcddeccccc
commit 24342db476
17 changed files with 85 additions and 95 deletions

View File

@ -78,7 +78,7 @@ void Signal_receiver::_platform_destructor()
}
void Signal_receiver::_platform_begin_dissolve(Signal_context * const c)
void Signal_receiver::_platform_begin_dissolve(Signal_context &context)
{
/**
* Mark the Signal_context as already pending to prevent the receiver
@ -86,24 +86,27 @@ void Signal_receiver::_platform_begin_dissolve(Signal_context * const c)
* processing
*/
{
Mutex::Guard context_guard(c->_mutex);
c->_pending = true;
c->_curr_signal = Signal::Data();
Mutex::Guard context_guard(context._mutex);
context._pending = true;
context._curr_signal = Signal::Data();
}
Kernel::kill_signal_context(Capability_space::capid(c->_cap));
Kernel::kill_signal_context(Capability_space::capid(context._cap));
}
void Signal_receiver::_platform_finish_dissolve(Signal_context *) { }
void Signal_receiver::_platform_finish_dissolve(Signal_context &) { }
Signal_context_capability Signal_receiver::manage(Signal_context * const c)
Signal_context_capability Signal_receiver::manage(Signal_context &context)
{
/* ensure that the context isn't managed already */
Mutex::Guard contexts_guard(_contexts_mutex);
Mutex::Guard context_guard(c->_mutex);
if (c->_receiver)
throw Context_already_in_use();
Mutex::Guard context_guard(context._mutex);
if (context._receiver) {
error("ill-attempt to manage an already managed signal context");
return context._cap;
}
Signal_receiver &this_receiver = *this;
@ -115,13 +118,13 @@ Signal_context_capability Signal_receiver::manage(Signal_context * const c)
using Error = Pd_session::Alloc_context_error;
/* use pointer to signal context as imprint */
Pd_session::Imprint const imprint { addr_t(c) };
Pd_session::Imprint const imprint { addr_t(&context) };
_pd.alloc_context(_cap, imprint).with_result(
[&] (Capability<Signal_context> cap) {
c->_cap = cap;
c->_receiver = &this_receiver;
_contexts.insert_as_tail(c);
context._cap = cap;
context._receiver = &this_receiver;
_contexts.insert_as_tail(&context);
},
[&] (Error e) {
switch (e) {
@ -138,8 +141,8 @@ Signal_context_capability Signal_receiver::manage(Signal_context * const c)
}
});
if (c->_cap.valid())
return c->_cap;
if (context._cap.valid())
return context._cap;
env().upgrade(Parent::Env::pd(),
String<100>("ram_quota=", ram_upgrade, ", "

View File

@ -30,9 +30,9 @@ struct Single_signal
Signal_context_capability cap;
Signal_transmitter transmitter;
Single_signal() : cap(receiver.manage(&context)), transmitter(cap) { }
Single_signal() : cap(receiver.manage(context)), transmitter(cap) { }
~Single_signal() { receiver.dissolve(&context); }
~Single_signal() { receiver.dissolve(context); }
void receive() { receiver.wait_for_signal(); }
void submit() { transmitter.submit(); }
};

View File

@ -343,7 +343,7 @@ class Genode::Signal_receiver : Noncopyable
* and 'dissolve'. Note that '_contexts_mutex' must be held when
* calling this method.
*/
void _unsynchronized_dissolve(Signal_context *context);
void _unsynchronized_dissolve(Signal_context &);
/**
* Hook to platform specific destructor parts
@ -353,25 +353,12 @@ class Genode::Signal_receiver : Noncopyable
/**
* Hooks to platform specific dissolve parts
*/
void _platform_begin_dissolve(Signal_context * const c);
void _platform_finish_dissolve(Signal_context * const c);
void _platform_begin_dissolve (Signal_context &);
void _platform_finish_dissolve(Signal_context &);
public:
/**
* Exception class
*/
class Context_already_in_use { };
class Context_not_associated { };
/**
* Constructor
*/
Signal_receiver();
/**
* Destructor
*/
~Signal_receiver();
/**
@ -379,19 +366,17 @@ class Genode::Signal_receiver : Noncopyable
*
* \param context context associated with signals delivered to the
* receiver
* \throw 'Context_already_in_use'
* \return new signal-context capability that can be
* passed to a signal transmitter
*/
Signal_context_capability manage(Signal_context *context);
Signal_context_capability manage(Signal_context &context);
/**
* Dissolve signal context from receiver
*
* \param context context to remove from receiver
* \throw 'Context_not_associated'
*/
void dissolve(Signal_context *context);
void dissolve(Signal_context &context);
/**
* Block until a signal is received and return the signal
@ -433,7 +418,7 @@ class Genode::Signal_receiver : Noncopyable
* source associated with the process. It must not be used for other
* purposes.
*/
static void dispatch_signals(Signal_source *);
static void dispatch_signals(Signal_source &);
};

View File

@ -186,7 +186,7 @@ class Timer::Connection : public Genode::Connection<Session>,
Genode::Signal_context _default_sigh_ctx { };
Genode::Signal_context_capability
_default_sigh_cap = _sig_rec.manage(&_default_sigh_ctx);
_default_sigh_cap = _sig_rec.manage(_default_sigh_ctx);
Genode::Signal_context_capability _custom_sigh_cap { };
@ -266,7 +266,7 @@ class Timer::Connection : public Genode::Connection<Session>,
Connection(Genode::Env &env, Label const &label = Label())
: Connection(env, env.ep(), label) { }
~Connection() { _sig_rec.dissolve(&_default_sigh_ctx); }
~Connection() { _sig_rec.dissolve(_default_sigh_ctx); }
/*
* Intercept 'sigh' to keep track of customized signal handlers

View File

@ -124,8 +124,8 @@ _ZN6Genode15Signal_receiver12local_submitENS_6Signal4DataE T
_ZN6Genode15Signal_receiver14pending_signalEv T
_ZN6Genode15Signal_receiver15wait_for_signalEv T
_ZN6Genode15Signal_receiver16block_for_signalEv T
_ZN6Genode15Signal_receiver6manageEPNS_14Signal_contextE T
_ZN6Genode15Signal_receiver8dissolveEPNS_14Signal_contextE T
_ZN6Genode15Signal_receiver6manageERNS_14Signal_contextE T
_ZN6Genode15Signal_receiver8dissolveERNS_14Signal_contextE T
_ZN6Genode15Signal_receiverC1Ev T
_ZN6Genode15Signal_receiverC2Ev T
_ZN6Genode15Signal_receiverD1Ev T

View File

@ -42,8 +42,8 @@ Signal_receiver::Signal_receiver() : _pd(*_pd_ptr)
void Signal_receiver::_platform_destructor() { }
void Signal_receiver::_platform_begin_dissolve (Signal_context *) { }
void Signal_receiver::_platform_finish_dissolve(Signal_context *) { }
void Signal_receiver::_platform_begin_dissolve (Signal_context &) { }
void Signal_receiver::_platform_finish_dissolve(Signal_context &) { }
void Signal_receiver::unblock_signal_waiter(Rpc_entrypoint &) { ASSERT_NEVER_CALLED; }
@ -52,7 +52,7 @@ void Signal_receiver::unblock_signal_waiter(Rpc_entrypoint &) { ASSERT_NEVER_CAL
typedef Signal_context_capability Sigh_cap;
Sigh_cap Signal_receiver::manage(Signal_context *) { ASSERT_NEVER_CALLED; }
Sigh_cap Signal_receiver::manage(Signal_context &) { ASSERT_NEVER_CALLED; }
void Signal_receiver::block_for_signal()

View File

@ -90,7 +90,7 @@ class Genode::Expanding_parent_client : public Parent_client
{
if (!_fallback_sig_cap.valid()) {
_fallback_sig_rcv.construct();
_fallback_sig_cap = _fallback_sig_rcv->manage(&_fallback_sig_ctx);
_fallback_sig_cap = _fallback_sig_rcv->manage(_fallback_sig_ctx);
}
}

View File

@ -68,7 +68,7 @@ struct Genode::Component_env : Env
Blockade(Parent &parent) : _parent(parent)
{
_parent.session_sigh(_sig_rec.manage(&_sig_ctx));
_parent.session_sigh(_sig_rec.manage(_sig_ctx));
}
void block() { _sig_rec.wait_for_signal(); }

View File

@ -220,7 +220,7 @@ bool Entrypoint::_wait_and_dispatch_one_io_signal(bool const dont_block)
Signal_context_capability Entrypoint::manage(Signal_dispatcher_base &dispatcher)
{
/* _sig_rec is invalid for a small window in _process_incoming_signals */
return _sig_rec.constructed() ? _sig_rec->manage(&dispatcher)
return _sig_rec.constructed() ? _sig_rec->manage(dispatcher)
: Signal_context_capability();
}
@ -229,7 +229,7 @@ void Genode::Entrypoint::dissolve(Signal_dispatcher_base &dispatcher)
{
/* _sig_rec is invalid for a small window in _process_incoming_signals */
if (_sig_rec.constructed())
_sig_rec->dissolve(&dispatcher);
_sig_rec->dissolve(dispatcher);
/* also remove context from deferred signal list */
{

View File

@ -48,7 +48,7 @@ class Signal_handler_thread : Thread, Blockade
{
_signal_source.construct(_cpu, _pd.alloc_signal_source());
wakeup();
Signal_receiver::dispatch_signals(&(*_signal_source));
Signal_receiver::dispatch_signals(*_signal_source);
}
enum { STACK_SIZE = 4*1024*sizeof(addr_t) };
@ -214,12 +214,12 @@ Signal_receiver::Signal_receiver() : _pd(*_pd_ptr)
}
Signal_context_capability Signal_receiver::manage(Signal_context *context_ptr)
Signal_context_capability Signal_receiver::manage(Signal_context &context)
{
Signal_context &context = *context_ptr;
if (context._receiver)
throw Context_already_in_use();
if (context._receiver) {
error("ill-attempt to manage an already managed signal context");
return context._cap;
}
context._receiver = this;
@ -340,10 +340,10 @@ void Signal_receiver::local_submit(Signal::Data data)
}
void Signal_receiver::dispatch_signals(Signal_source *signal_source)
void Signal_receiver::dispatch_signals(Signal_source &signal_source)
{
for (;;) {
Signal_source::Signal source_signal = signal_source->wait_for_signal();
Signal_source::Signal source_signal = signal_source.wait_for_signal();
/* look up context as pointed to by the signal imprint */
Signal_context *context = (Signal_context *)(source_signal.imprint());
@ -372,18 +372,18 @@ void Signal_receiver::dispatch_signals(Signal_source *signal_source)
}
void Signal_receiver::_platform_begin_dissolve(Signal_context *context)
void Signal_receiver::_platform_begin_dissolve(Signal_context &context)
{
/*
* Because the 'remove' operation takes the registry mutex, the context
* must not be acquired when calling this method. See the comment in
* 'Signal_receiver::dissolve'.
*/
signal_context_registry()->remove(&context->_registry_le);
signal_context_registry()->remove(&context._registry_le);
}
void Signal_receiver::_platform_finish_dissolve(Signal_context *) { }
void Signal_receiver::_platform_finish_dissolve(Signal_context &) { }
void Signal_receiver::_platform_destructor() { }

View File

@ -164,34 +164,36 @@ Signal_receiver::~Signal_receiver()
Mutex::Guard contexts_guard(_contexts_mutex);
/* disassociate contexts from the receiver */
while (Signal_context *context = _contexts.head()) {
_platform_begin_dissolve(context);
_unsynchronized_dissolve(context);
_platform_finish_dissolve(context);
while (Signal_context *context_ptr = _contexts.head()) {
_platform_begin_dissolve(*context_ptr);
_unsynchronized_dissolve(*context_ptr);
_platform_finish_dissolve(*context_ptr);
}
_platform_destructor();
}
void Signal_receiver::_unsynchronized_dissolve(Signal_context * const context)
void Signal_receiver::_unsynchronized_dissolve(Signal_context &context)
{
/* tell core to stop sending signals referring to the context */
_pd.free_context(context->_cap);
_pd.free_context(context._cap);
/* restore default initialization of signal context */
context->_receiver = nullptr;
context->_cap = Signal_context_capability();
context._receiver = nullptr;
context._cap = Signal_context_capability();
/* remove context from context list */
_contexts.remove(context);
_contexts.remove(&context);
}
void Signal_receiver::dissolve(Signal_context *context)
void Signal_receiver::dissolve(Signal_context &context)
{
if (context->_receiver != this)
throw Context_not_associated();
if (context._receiver != this) {
error("ill-attempt to dissolve unmanaged signal context");
return;
}
{
/*
@ -207,14 +209,14 @@ void Signal_receiver::dissolve(Signal_context *context)
_platform_begin_dissolve(context);
Mutex::Guard context_guard(context->_mutex);
Mutex::Guard context_guard(context._mutex);
_unsynchronized_dissolve(context);
}
_platform_finish_dissolve(context);
Mutex::Guard context_destroy_guard(context->_destroy_mutex);
Mutex::Guard context_destroy_guard(context._destroy_mutex);
}

View File

@ -33,8 +33,8 @@ struct Audio_in::Signal
Genode::Signal_context context { };
Genode::Signal_context_capability cap;
Signal() : cap(recv.manage(&context)) { }
~Signal() { recv.dissolve(&context); }
Signal() : cap(recv.manage(context)) { }
~Signal() { recv.dissolve(context); }
void wait() { recv.wait_for_signal(); }
};

View File

@ -31,8 +31,8 @@ struct Audio_out::Signal
Genode::Signal_context context { };
Genode::Signal_context_capability cap;
Signal() : cap(recv.manage(&context)) { }
~Signal() { recv.dissolve(&context); }
Signal() : cap(recv.manage(context)) { }
~Signal() { recv.dissolve(context); }
void wait() { recv.wait_for_signal(); }
};

View File

@ -34,14 +34,14 @@ struct Terminal::Connection : Genode::Connection<Session>, Session_client
/* create signal receiver, just for the single signal */
Signal_context sig_ctx;
Signal_receiver sig_rec;
Signal_context_capability sig_cap = sig_rec.manage(&sig_ctx);
Signal_context_capability sig_cap = sig_rec.manage(sig_ctx);
/* register signal handler */
cap.call<Rpc_connected_sigh>(sig_cap);
/* wati for signal */
sig_rec.wait_for_signal();
sig_rec.dissolve(&sig_ctx);
sig_rec.dissolve(sig_ctx);
}
Connection(Genode::Env &env, Label const &label = Label())

View File

@ -67,7 +67,7 @@ Main::Main(Env &env) : env(env)
* Initialize the pin IRQ signal
*/
Irq_session_client irq(signal_input.irq_session(Gpio::Session::HIGH_LEVEL));
irq.sigh(sig_rec.manage(&sig_ctx));
irq.sigh(sig_rec.manage(sig_ctx));
irq.ack_irq();
while(true)

View File

@ -134,12 +134,12 @@ class Handler : Thread
~Handler()
{
Signal_context context;
Signal_context_capability context_cap { _receiver.manage(&context) };
Signal_context_capability context_cap { _receiver.manage(context) };
_stop = true;
Signal_transmitter(context_cap).submit();
Thread::join();
_receiver.dissolve(&context);
_receiver.dissolve(context);
}
void print(Output &output) const { Genode::print(output, "handler ", _id); }
@ -185,7 +185,7 @@ struct Fast_sender_test : Signal_test
Signal_context context { };
Signal_receiver receiver { };
Handler handler { env, receiver, HANDLER_INTERVAL_MS, false, 1 };
Sender sender { env, receiver.manage(&context),
Sender sender { env, receiver.manage(context),
SENDER_INTERVAL_MS, false };
Fast_sender_test(Env &env, int id) : Signal_test(id, brief), env(env)
@ -218,7 +218,7 @@ struct Stress_test : Signal_test
Signal_context context { };
Signal_receiver receiver { };
Handler handler { env, receiver, 0, false, 1 };
Sender sender { env, receiver.manage(&context), 0, false };
Sender sender { env, receiver.manage(context), 0, false };
Stress_test(Env &env, int id) : Signal_test(id, brief), env(env)
{
@ -254,8 +254,8 @@ struct Lazy_receivers_test : Signal_test
Signal_context context_1 { }, context_2 { };
Signal_receiver receiver_1 { }, receiver_2 { };
Signal_transmitter transmitter_1 { receiver_1.manage(&context_1) };
Signal_transmitter transmitter_2 { receiver_2.manage(&context_2) };
Signal_transmitter transmitter_1 { receiver_1.manage(context_1) };
Signal_transmitter transmitter_2 { receiver_2.manage(context_2) };
Lazy_receivers_test(Env &, int id) : Signal_test(id, brief)
{
@ -291,7 +291,7 @@ struct Context_management_test : Signal_test
Timer::Connection timer { env };
Signal_context context { };
Signal_receiver receiver { };
Signal_context_capability context_cap { receiver.manage(&context) };
Signal_context_capability context_cap { receiver.manage(context) };
Sender sender { env, context_cap, 500, true };
Context_management_test(Env &env, int id) : Signal_test(id, brief), env(env)
@ -306,7 +306,7 @@ struct Context_management_test : Signal_test
Signal signal = receiver.wait_for_signal();
log("got ", signal.num(), " signal(s) from ", signal.context());
}
receiver.dissolve(&context);
receiver.dissolve(context);
/* let sender spin for some time */
log("resume sender");
@ -330,12 +330,12 @@ struct Synchronized_destruction_test : private Signal_test, Thread
Heap heap { env.ram(), env.rm() };
Signal_context &context { *new (heap) Signal_context };
Signal_receiver receiver { };
Signal_transmitter transmitter { receiver.manage(&context) };
Signal_transmitter transmitter { receiver.manage(context) };
bool destroyed { false };
void entry() override
{
receiver.dissolve(&context);
receiver.dissolve(context);
log("dissolve finished");
destroyed = true;
destroy(heap, &context);
@ -380,11 +380,11 @@ struct Many_contexts_test : Signal_test
Signal_receiver receiver;
for (unsigned i = 0; i < nr_of_contexts; i++) {
if (!receiver.manage(new (heap) Registered<Signal_context>(contexts)).valid()) {
if (!receiver.manage(*new (heap) Registered<Signal_context>(contexts)).valid()) {
throw Manage_failed(); }
}
contexts.for_each([&] (Registered<Signal_context> &context) {
receiver.dissolve(&context);
receiver.dissolve(context);
destroy(heap, &context);
});
}

View File

@ -81,7 +81,7 @@ class Test_terminal_crosslink::Partner : public Thread
: Thread(env, name, STACK_SIZE),
_terminal(env)
{
_terminal.read_avail_sigh(_sig_rec.manage(&_sig_ctx));
_terminal.read_avail_sigh(_sig_rec.manage(_sig_ctx));
}
};