diff --git a/repos/base-hw/src/lib/base/signal_receiver.cc b/repos/base-hw/src/lib/base/signal_receiver.cc index bb3415deda..83595c7c87 100644 --- a/repos/base-hw/src/lib/base/signal_receiver.cc +++ b/repos/base-hw/src/lib/base/signal_receiver.cc @@ -17,6 +17,7 @@ #include #include #include +#include /* base-internal includes */ #include @@ -104,20 +105,41 @@ Signal_context_capability Signal_receiver::manage(Signal_context * const c) if (c->_receiver) throw Context_already_in_use(); + Signal_receiver &this_receiver = *this; + for (;;) { Ram_quota ram_upgrade { 0 }; Cap_quota cap_upgrade { 0 }; - try { - /* use signal context as imprint */ - c->_cap = env().pd().alloc_context(_cap, (unsigned long)c); - c->_receiver = this; - _contexts.insert_as_tail(c); + using Error = Pd_session::Alloc_context_error; + + /* use pointer to signal context as imprint */ + Pd_session::Imprint const imprint { addr_t(c) }; + + _pd.alloc_context(_cap, imprint).with_result( + [&] (Capability cap) { + c->_cap = cap; + c->_receiver = &this_receiver; + _contexts.insert_as_tail(c); + }, + [&] (Error e) { + switch (e) { + case Error::OUT_OF_RAM: + ram_upgrade = Ram_quota { 1024*sizeof(long) }; + break; + case Error::OUT_OF_CAPS: + cap_upgrade = Cap_quota { 4 }; + break; + case Error::INVALID_SIGNAL_SOURCE: + error("ill-attempt to create context for invalid signal source"); + sleep_forever(); + break; + } + }); + + if (c->_cap.valid()) return c->_cap; - } - catch (Out_of_ram) { ram_upgrade = Ram_quota { 1024*sizeof(long) }; } - catch (Out_of_caps) { cap_upgrade = Cap_quota { 4 }; } env().upgrade(Parent::Env::pd(), String<100>("ram_quota=", ram_upgrade, ", " diff --git a/repos/base/include/pd_session/client.h b/repos/base/include/pd_session/client.h index bd6a9608cf..70a8006409 100644 --- a/repos/base/include/pd_session/client.h +++ b/repos/base/include/pd_session/client.h @@ -39,8 +39,8 @@ struct Genode::Pd_session_client : Rpc_client void free_signal_source(Signal_source_capability cap) override { call(cap); } - Signal_context_capability alloc_context(Signal_source_capability source, - unsigned long imprint) override { + Alloc_context_result alloc_context(Signal_source_capability source, + Imprint imprint) override { return call(source, imprint); } void free_context(Signal_context_capability cap) override { diff --git a/repos/base/include/pd_session/pd_session.h b/repos/base/include/pd_session/pd_session.h index bb1a02d560..8b16b6f725 100644 --- a/repos/base/include/pd_session/pd_session.h +++ b/repos/base/include/pd_session/pd_session.h @@ -94,7 +94,6 @@ struct Genode::Pd_session : Session, Ram_allocator class Invalid_session : public Exception { }; class Undefined_ref_account : public Exception { }; - class Invalid_signal_source : public Exception { }; /** * Create a new signal source @@ -115,22 +114,22 @@ struct Genode::Pd_session : Session, Ram_allocator */ virtual void free_signal_source(Signal_source_capability cap) = 0; + enum class Alloc_context_error { OUT_OF_RAM, OUT_OF_CAPS, INVALID_SIGNAL_SOURCE }; + using Alloc_context_result = Attempt, Alloc_context_error>; + + struct Imprint { addr_t value; }; + /** * Allocate signal context * * \param source signal source that shall provide the new context * - * * \param imprint opaque value that gets delivered with signals * originating from the allocated signal-context capability * \return new signal-context capability - * - * \throw Out_of_ram - * \throw Out_of_caps - * \throw Invalid_signal_source */ - virtual Capability - alloc_context(Signal_source_capability source, unsigned long imprint) = 0; + virtual Alloc_context_result alloc_context(Signal_source_capability source, + Imprint imprint) = 0; /** * Free signal-context @@ -373,9 +372,8 @@ struct Genode::Pd_session : Session, Ram_allocator alloc_signal_source, GENODE_TYPE_LIST(Out_of_ram, Out_of_caps)); GENODE_RPC(Rpc_free_signal_source, void, free_signal_source, Signal_source_capability); - GENODE_RPC_THROW(Rpc_alloc_context, Capability, alloc_context, - GENODE_TYPE_LIST(Out_of_ram, Out_of_caps, Invalid_signal_source), - Signal_source_capability, unsigned long); + GENODE_RPC(Rpc_alloc_context, Alloc_context_result, alloc_context, + Signal_source_capability, Imprint); GENODE_RPC(Rpc_free_context, void, free_context, Capability); GENODE_RPC(Rpc_submit, void, submit, Capability, unsigned); diff --git a/repos/base/src/core/include/pd_session_component.h b/repos/base/src/core/include/pd_session_component.h index d8c2d5d06b..58a5821dd8 100644 --- a/repos/base/src/core/include/pd_session_component.h +++ b/repos/base/src/core/include/pd_session_component.h @@ -223,21 +223,24 @@ class Core::Pd_session_component : public Session_object } } - Signal_context_capability - alloc_context(Signal_source_capability sig_rec_cap, unsigned long imprint) override + Alloc_context_result + alloc_context(Signal_source_capability sig_rec_cap, Imprint imprint) override { - Cap_quota_guard::Reservation cap_costs(_cap_quota_guard(), Cap_quota{1}); try { - /* may throw 'Out_of_ram' or 'Invalid_signal_source' */ + Cap_quota_guard::Reservation cap_costs(_cap_quota_guard(), Cap_quota{1}); + + /* may throw 'Out_of_ram', 'Out_of_caps', or 'Invalid_signal_source' */ Signal_context_capability cap = - _signal_broker.alloc_context(sig_rec_cap, imprint); + _signal_broker.alloc_context(sig_rec_cap, imprint.value); cap_costs.acknowledge(); diag("consumed signal-context cap (", _cap_account, ")"); return cap; } catch (Signal_broker::Invalid_signal_source) { - throw Pd_session::Invalid_signal_source(); } + return Alloc_context_error::INVALID_SIGNAL_SOURCE; } + catch (Out_of_ram) { return Alloc_context_error::OUT_OF_RAM; } + catch (Out_of_caps) { return Alloc_context_error::OUT_OF_CAPS; } } void free_context(Signal_context_capability cap) override diff --git a/repos/base/src/lib/base/signal.cc b/repos/base/src/lib/base/signal.cc index 57ab8e75b0..7b8e6f4230 100644 --- a/repos/base/src/lib/base/signal.cc +++ b/repos/base/src/lib/base/signal.cc @@ -214,33 +214,52 @@ Signal_receiver::Signal_receiver() : _pd(*_pd_ptr) } -Signal_context_capability Signal_receiver::manage(Signal_context *context) +Signal_context_capability Signal_receiver::manage(Signal_context *context_ptr) { - if (context->_receiver) + Signal_context &context = *context_ptr; + + if (context._receiver) throw Context_already_in_use(); - context->_receiver = this; + context._receiver = this; Mutex::Guard contexts_guard(_contexts_mutex); /* insert context into context list */ - _contexts.insert_as_tail(context); + _contexts.insert_as_tail(&context); /* register context at process-wide registry */ - signal_context_registry()->insert(&context->_registry_le); + signal_context_registry()->insert(&context._registry_le); for (;;) { Ram_quota ram_upgrade { 0 }; Cap_quota cap_upgrade { 0 }; - try { - /* use signal context as imprint */ - context->_cap = _pd.alloc_context(_cap, (long)context); + using Error = Pd_session::Alloc_context_error; + + /* use pointer to signal context as imprint */ + Pd_session::Imprint const imprint { addr_t(&context) }; + + _pd.alloc_context(_cap, imprint).with_result( + [&] (Capability cap) { context._cap = cap; }, + [&] (Error e) { + switch (e) { + case Error::OUT_OF_RAM: + ram_upgrade = Ram_quota { 1024*sizeof(long) }; + break; + case Error::OUT_OF_CAPS: + cap_upgrade = Cap_quota { 4 }; + break; + case Error::INVALID_SIGNAL_SOURCE: + error("ill-attempt to create context for invalid signal source"); + sleep_forever(); + break; + } + }); + + if (context._cap.valid()) break; - } - catch (Out_of_ram) { ram_upgrade = Ram_quota { 1024*sizeof(long) }; } - catch (Out_of_caps) { cap_upgrade = Cap_quota { 4 }; } log("upgrading quota donation for PD session " "(", ram_upgrade, " bytes, ", cap_upgrade, " caps)"); @@ -249,8 +268,7 @@ Signal_context_capability Signal_receiver::manage(Signal_context *context) String<100>("ram_quota=", ram_upgrade, ", " "cap_quota=", cap_upgrade).string()); } - - return context->_cap; + return context._cap; } diff --git a/repos/os/src/monitor/inferior_pd.h b/repos/os/src/monitor/inferior_pd.h index b3d6056d5b..3e25315082 100644 --- a/repos/os/src/monitor/inferior_pd.h +++ b/repos/os/src/monitor/inferior_pd.h @@ -207,8 +207,8 @@ struct Monitor::Inferior_pd : Monitored_pd_session void free_signal_source(Signal_source_capability cap) override { _real.call(cap); } - Signal_context_capability alloc_context(Signal_source_capability source, - unsigned long imprint) override { + Alloc_context_result alloc_context(Signal_source_capability source, + Imprint imprint) override { return _real.call(source, imprint); } void free_context(Signal_context_capability cap) override { diff --git a/repos/os/src/monitor/pd_intrinsics.h b/repos/os/src/monitor/pd_intrinsics.h index 9dfaceb63a..e75d516e6f 100644 --- a/repos/os/src/monitor/pd_intrinsics.h +++ b/repos/os/src/monitor/pd_intrinsics.h @@ -46,7 +46,7 @@ struct Monitor::Pd_intrinsics : Sandbox::Pd_intrinsics void map(addr_t, addr_t) override { never_called(__func__); }; Sig_src_cap alloc_signal_source() override { never_called(__func__); }; void free_signal_source(Sig_src_cap) override { never_called(__func__); }; - Sig_ctx_cap alloc_context(Sig_src_cap, unsigned long) override { never_called(__func__); }; + Alloc_context_result alloc_context(Sig_src_cap, Imprint) override { never_called(__func__); }; void free_context(Sig_ctx_cap) override { never_called(__func__); }; void submit(Sig_ctx_cap, unsigned) override { never_called(__func__); }; Native_capability alloc_rpc_cap(Native_capability) override { never_called(__func__); };