From d866b6b053b474fb59c321d46995263d95eefacb Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Mon, 17 Jun 2024 18:19:07 +0200 Subject: [PATCH] Remove exceptions from Cpu_session interface The 'Thread_creation_failed' error is now reflected as 'Thread::Start_result' return value. This change also removes the use of 'Invalid_thread' within core as this exception is an alias of Cpu_session::Thread_creation_failed. Issue #5245 --- .../src/core/irq_session_component.cc | 5 +- repos/base-fiasco/src/core/platform_pd.cc | 5 +- repos/base-fiasco/src/core/thread_start.cc | 4 +- .../src/core/irq_session_component.cc | 2 +- repos/base-foc/src/core/pager.cc | 16 ++-- repos/base-foc/src/core/platform_pd.cc | 1 - repos/base-foc/src/core/thread_start.cc | 4 +- repos/base-foc/src/lib/base/thread_start.cc | 60 ++++++------ repos/base-hw/src/core/thread_start.cc | 9 +- repos/base-hw/src/lib/base/thread_start.cc | 43 +++++---- .../base-linux/src/core/include/irq_object.h | 2 +- .../core/spec/linux/irq_session_component.cc | 3 +- .../src/core/spec/pc/irq_session_component.cc | 5 +- repos/base-linux/src/core/thread_linux.cc | 3 +- .../base-linux/src/lib/base/child_process.cc | 13 ++- repos/base-linux/src/lib/base/thread_linux.cc | 18 ++-- .../base-linux/src/lib/lx_hybrid/lx_hybrid.cc | 18 +++- repos/base-nova/src/core/include/pager.h | 2 - repos/base-nova/src/core/pager.cc | 88 +++++++++++------- repos/base-nova/src/core/thread_start.cc | 20 ++-- .../base-nova/src/lib/base/rpc_entrypoint.cc | 10 +- repos/base-nova/src/lib/base/thread_start.cc | 45 +++++---- .../src/core/irq_session_component.cc | 5 +- repos/base-okl4/src/core/thread_start.cc | 4 +- .../src/core/irq_session_component.cc | 5 +- repos/base-pistachio/src/core/platform_pd.cc | 5 +- repos/base-pistachio/src/core/thread_start.cc | 4 +- repos/base-sel4/src/core/include/irq_object.h | 2 +- .../src/core/irq_session_component.cc | 5 +- repos/base-sel4/src/core/thread_start.cc | 4 +- repos/base/include/base/child.h | 1 - repos/base/include/base/quota_guard.h | 12 ++- repos/base/include/base/session_object.h | 2 + repos/base/include/base/thread.h | 19 +++- repos/base/include/cpu_session/client.h | 2 +- repos/base/include/cpu_session/connection.h | 29 ++++-- repos/base/include/cpu_session/cpu_session.h | 38 ++++---- repos/base/src/core/cpu_session_component.cc | 93 +++++++++---------- repos/base/src/core/include/account.h | 11 +++ .../src/core/include/cpu_session_component.h | 4 +- .../src/core/include/cpu_thread_component.h | 6 +- repos/base/src/core/include/irq_object.h | 2 +- repos/base/src/core/include/pager.h | 4 - .../internal/expanding_cpu_session_client.h | 28 ++++-- repos/base/src/lib/base/child.cc | 13 ++- repos/base/src/lib/base/child_process.cc | 13 ++- repos/base/src/lib/base/thread_start.cc | 22 +++-- repos/base/src/lib/base/trace.cc | 13 ++- repos/base/src/test/thread/main.cc | 46 +++++---- .../cpu_sampler/cpu_session_component.cc | 2 +- .../cpu_sampler/cpu_session_component.h | 10 +- .../cpu_sampler/cpu_thread_component.cc | 7 +- repos/os/src/monitor/inferior_cpu.h | 30 +++--- repos/os/src/monitor/pd_intrinsics.h | 2 +- repos/os/src/server/cpu_balancer/session.cc | 72 +++++++------- repos/os/src/server/cpu_balancer/session.h | 8 +- repos/ports/include/vmm/vcpu_thread.h | 30 ++++-- repos/ports/src/virtualbox5/spec/nova/vcpu.h | 4 +- 58 files changed, 562 insertions(+), 371 deletions(-) diff --git a/repos/base-fiasco/src/core/irq_session_component.cc b/repos/base-fiasco/src/core/irq_session_component.cc index 46b9bb5cec..3d927b1826 100644 --- a/repos/base-fiasco/src/core/irq_session_component.cc +++ b/repos/base-fiasco/src/core/irq_session_component.cc @@ -78,10 +78,11 @@ void Irq_object::_wait_for_irq() } -void Irq_object::start() +Thread::Start_result Irq_object::start() { - ::Thread::start(); + Start_result const result = ::Thread::start(); _sync_bootup.block(); + return result; } diff --git a/repos/base-fiasco/src/core/platform_pd.cc b/repos/base-fiasco/src/core/platform_pd.cc index 7fd53d44e6..1a2a0d2da6 100644 --- a/repos/base-fiasco/src/core/platform_pd.cc +++ b/repos/base-fiasco/src/core/platform_pd.cc @@ -200,10 +200,9 @@ bool Platform_pd::bind_thread(Platform_thread &thread) l4_threadid_t l4_thread_id; int t = _alloc_thread(thread_id, thread); - if (t < 0) { - error("thread alloc failed"); + if (t < 0) return false; - } + thread_id = t; enum { LTHREAD_MASK = (1 << 7) - 1 }; diff --git a/repos/base-fiasco/src/core/thread_start.cc b/repos/base-fiasco/src/core/thread_start.cc index 2e1180c420..dff6686e75 100644 --- a/repos/base-fiasco/src/core/thread_start.cc +++ b/repos/base-fiasco/src/core/thread_start.cc @@ -34,7 +34,7 @@ void Thread::_thread_start() } -void Thread::start() +Thread::Start_result Thread::start() { /* create and start platform thread */ native_thread().pt = new (platform().core_mem_alloc()) @@ -46,6 +46,8 @@ void Thread::start() native_thread().l4id = native_thread().pt->native_thread_id(); native_thread().pt->start((void *)_thread_start, stack_top()); + + return Start_result::OK; } diff --git a/repos/base-foc/src/core/irq_session_component.cc b/repos/base-foc/src/core/irq_session_component.cc index 231cb6ec5a..e5cac00253 100644 --- a/repos/base-foc/src/core/irq_session_component.cc +++ b/repos/base-foc/src/core/irq_session_component.cc @@ -52,7 +52,7 @@ class Core::Interrupt_handler : public Thread static Foc::l4_cap_idx_t handler_cap() { static Interrupt_handler handler; - return handler._thread_cap.data()->kcap(); + return handler.cap().data()->kcap(); } }; diff --git a/repos/base-foc/src/core/pager.cc b/repos/base-foc/src/core/pager.cc index 31b07632a6..891967266d 100644 --- a/repos/base-foc/src/core/pager.cc +++ b/repos/base-foc/src/core/pager.cc @@ -140,12 +140,16 @@ Pager_capability Pager_entrypoint::manage(Pager_object &obj) { using namespace Foc; - Native_capability cap(_cap_factory.alloc(Thread::_thread_cap)); + return _thread_cap.convert( + [&] (Thread_capability thread_cap) { + Native_capability cap(_cap_factory.alloc(thread_cap)); - /* add server object to object pool */ - obj.cap(cap); - insert(&obj); + /* add server object to object pool */ + obj.cap(cap); + insert(&obj); - /* return capability that uses the object id as badge */ - return reinterpret_cap_cast(cap); + /* return capability that uses the object id as badge */ + return reinterpret_cap_cast(cap); + }, + [&] (Cpu_session::Create_thread_error) { return Pager_capability(); }); } diff --git a/repos/base-foc/src/core/platform_pd.cc b/repos/base-foc/src/core/platform_pd.cc index bf76ecc5e7..92997fd811 100644 --- a/repos/base-foc/src/core/platform_pd.cc +++ b/repos/base-foc/src/core/platform_pd.cc @@ -86,7 +86,6 @@ bool Platform_pd::bind_thread(Platform_thread &thread) return true; } - error("thread alloc failed"); return false; } diff --git a/repos/base-foc/src/core/thread_start.cc b/repos/base-foc/src/core/thread_start.cc index 5ea31a67cb..98f731f670 100644 --- a/repos/base-foc/src/core/thread_start.cc +++ b/repos/base-foc/src/core/thread_start.cc @@ -39,7 +39,7 @@ void Thread::_deinit_platform_thread() void Thread::_init_platform_thread(size_t, Type) { } -void Thread::start() +Thread::Start_result Thread::start() { using namespace Foc; @@ -113,4 +113,6 @@ void Thread::start() new (platform().core_mem_alloc()) Core_trace_source(Core::Trace::sources(), *this, pt); + + return Start_result::OK; } diff --git a/repos/base-foc/src/lib/base/thread_start.cc b/repos/base-foc/src/lib/base/thread_start.cc index 072aa95c87..92d6e1f07f 100644 --- a/repos/base-foc/src/lib/base/thread_start.cc +++ b/repos/base-foc/src/lib/base/thread_start.cc @@ -50,11 +50,14 @@ void Thread::_deinit_platform_thread() { using namespace Foc; - if (native_thread().kcap && _thread_cap.valid()) { + if (native_thread().kcap) { Cap_index *i = (Cap_index*)l4_utcb_tcr_u(utcb()->foc_utcb)->user[UTCB_TCR_BADGE]; cap_map().remove(i); - _cpu_session->kill_thread(_thread_cap); } + + _thread_cap.with_result( + [&] (Thread_capability cap) { _cpu_session->kill_thread(cap); }, + [&] (Cpu_session::Create_thread_error) { }); } @@ -65,14 +68,8 @@ void Thread::_init_platform_thread(size_t weight, Type type) if (type == NORMAL) { /* create thread at core */ - _thread_cap = _cpu_session->create_thread(pd_session_cap(), - name(), _affinity, - Weight(weight)); - - /* assign thread to protection domain */ - if (!_thread_cap.valid()) - throw Cpu_session::Thread_creation_failed(); - + _thread_cap = _cpu_session->create_thread(pd_session_cap(), name(), + _affinity, Weight(weight)); return; } @@ -80,8 +77,10 @@ void Thread::_init_platform_thread(size_t weight, Type type) native_thread().kcap = Foc::MAIN_THREAD_CAP; _thread_cap = main_thread_cap(); - if (!_thread_cap.valid()) - throw Cpu_session::Thread_creation_failed(); + if (_thread_cap.failed()) { + error("failed to re-initialize main thread"); + return; + } /* make thread object known to the Fiasco.OC environment */ addr_t const t = (addr_t)this; @@ -89,29 +88,36 @@ void Thread::_init_platform_thread(size_t weight, Type type) } -void Thread::start() +Thread::Start_result Thread::start() { using namespace Foc; - Foc_native_cpu_client native_cpu(_cpu_session->native_cpu()); + return _thread_cap.convert( + [&] (Thread_capability cap) { + Foc_native_cpu_client native_cpu(_cpu_session->native_cpu()); - /* get gate-capability and badge of new thread */ - Foc_thread_state state { }; - state = native_cpu.thread_state(_thread_cap); + /* get gate-capability and badge of new thread */ + Foc_thread_state state { }; + state = native_cpu.thread_state(cap); - /* remember UTCB of the new thread */ - Foc::l4_utcb_t * const foc_utcb = (Foc::l4_utcb_t *)state.utcb; - utcb()->foc_utcb = foc_utcb; + /* remember UTCB of the new thread */ + Foc::l4_utcb_t * const foc_utcb = (Foc::l4_utcb_t *)state.utcb; + utcb()->foc_utcb = foc_utcb; - native_thread() = Native_thread(state.kcap); + native_thread() = Native_thread(state.kcap); - Cap_index *i = cap_map().insert(state.id, state.kcap); - l4_utcb_tcr_u(foc_utcb)->user[UTCB_TCR_BADGE] = (unsigned long) i; - l4_utcb_tcr_u(foc_utcb)->user[UTCB_TCR_THREAD_OBJ] = (addr_t)this; + Cap_index *i = cap_map().insert(state.id, state.kcap); + l4_utcb_tcr_u(foc_utcb)->user[UTCB_TCR_BADGE] = (unsigned long) i; + l4_utcb_tcr_u(foc_utcb)->user[UTCB_TCR_THREAD_OBJ] = (addr_t)this; - /* register initial IP and SP at core */ - Cpu_thread_client cpu_thread(_thread_cap); - cpu_thread.start((addr_t)_thread_start, _stack->top()); + /* register initial IP and SP at core */ + Cpu_thread_client cpu_thread(cap); + cpu_thread.start((addr_t)_thread_start, _stack->top()); + + return Start_result::OK; + }, + [&] (Cpu_session::Create_thread_error) { return Start_result::DENIED; } + ); } diff --git a/repos/base-hw/src/core/thread_start.cc b/repos/base-hw/src/core/thread_start.cc index e8dace0d45..cf46ffe38d 100644 --- a/repos/base-hw/src/core/thread_start.cc +++ b/repos/base-hw/src/core/thread_start.cc @@ -32,14 +32,17 @@ using namespace Core; namespace Hw { extern Untyped_capability _main_thread_cap; } -void Thread::start() +Thread::Start_result Thread::start() { /* start thread with stack pointer at the top of stack */ if (native_thread().platform_thread->start((void *)&_thread_start, stack_top())) { error("failed to start thread"); - return; + return Start_result::DENIED; } + if (_thread_cap.failed()) + return Start_result::DENIED; + struct Trace_source : public Core::Trace::Source::Info_accessor, private Core::Trace::Control, private Core::Trace::Source @@ -73,6 +76,8 @@ void Thread::start() /* create trace sources for core threads */ new (platform().core_mem_alloc()) Trace_source(Core::Trace::sources(), *this); + + return Start_result::OK; } diff --git a/repos/base-hw/src/lib/base/thread_start.cc b/repos/base-hw/src/lib/base/thread_start.cc index 29653bf3d4..bcd6bed15a 100644 --- a/repos/base-hw/src/lib/base/thread_start.cc +++ b/repos/base-hw/src/lib/base/thread_start.cc @@ -58,8 +58,8 @@ void Thread::_init_platform_thread(size_t weight, Type type) /* create server object */ addr_t const utcb = (addr_t)&_stack->utcb(); - _thread_cap = _cpu_session->create_thread(pd_session_cap(), - name(), _affinity, + + _thread_cap = _cpu_session->create_thread(pd_session_cap(), name(), _affinity, Weight(weight), utcb); return; } @@ -88,7 +88,9 @@ void Thread::_deinit_platform_thread() return; } - _cpu_session->kill_thread(_thread_cap); + _thread_cap.with_result( + [&] (Thread_capability cap) { _cpu_session->kill_thread(cap); }, + [&] (Cpu_session::Create_thread_error) { }); /* detach userland stack */ size_t const size = sizeof(_stack->utcb()); @@ -98,21 +100,28 @@ void Thread::_deinit_platform_thread() } -void Thread::start() +Thread::Start_result Thread::start() { - /* attach userland stack */ - try { - Dataspace_capability ds = Cpu_thread_client(_thread_cap).utcb(); - size_t const size = sizeof(_stack->utcb()); - addr_t dst = Stack_allocator::addr_to_base(_stack) + - stack_virtual_size() - size - stack_area_virtual_base(); - env_stack_area_region_map->attach_at(ds, dst, size); - } catch (...) { - error("failed to attach userland stack"); - sleep_forever(); - } - /* start thread with its initial IP and aligned SP */ - Cpu_thread_client(_thread_cap).start((addr_t)_thread_start, _stack->top()); + return _thread_cap.convert( + [&] (Thread_capability cap) { + Cpu_thread_client cpu_thread(cap); + + /* attach UTCB at top of stack */ + size_t const size = sizeof(_stack->utcb()); + addr_t dst = Stack_allocator::addr_to_base(_stack) + + stack_virtual_size() - size - stack_area_virtual_base(); + try { + env_stack_area_region_map->attach_at(cpu_thread.utcb(), dst, size); + } catch (...) { + error("failed to attach userland stack"); + sleep_forever(); + } + /* start execution with initial IP and aligned SP */ + cpu_thread.start((addr_t)_thread_start, _stack->top()); + return Start_result::OK; + }, + [&] (Cpu_session::Create_thread_error) { return Start_result::DENIED; } + ); } diff --git a/repos/base-linux/src/core/include/irq_object.h b/repos/base-linux/src/core/include/irq_object.h index c5a3d3d423..c4c5cef7e2 100644 --- a/repos/base-linux/src/core/include/irq_object.h +++ b/repos/base-linux/src/core/include/irq_object.h @@ -43,7 +43,7 @@ class Core::Irq_object : public Thread void sigh(Signal_context_capability cap); void ack_irq(); - void start() override; + Start_result start() override; }; diff --git a/repos/base-linux/src/core/spec/linux/irq_session_component.cc b/repos/base-linux/src/core/spec/linux/irq_session_component.cc index fc17abaea1..940ad7d820 100644 --- a/repos/base-linux/src/core/spec/linux/irq_session_component.cc +++ b/repos/base-linux/src/core/spec/linux/irq_session_component.cc @@ -75,9 +75,10 @@ void Irq_object::ack_irq() } -void Irq_object::start() +Thread::Start_result Irq_object::start() { warning(__func__, " not implemented"); + return Start_result::DENIED; } diff --git a/repos/base-linux/src/core/spec/pc/irq_session_component.cc b/repos/base-linux/src/core/spec/pc/irq_session_component.cc index ffd1032e9c..192fa30731 100644 --- a/repos/base-linux/src/core/spec/pc/irq_session_component.cc +++ b/repos/base-linux/src/core/spec/pc/irq_session_component.cc @@ -110,10 +110,11 @@ void Irq_object::ack_irq() } -void Irq_object::start() +Thread::Start_result Irq_object::start() { - Thread::start(); + Start_result const result = Thread::start(); _sync_bootup.block(); + return result; } diff --git a/repos/base-linux/src/core/thread_linux.cc b/repos/base-linux/src/core/thread_linux.cc index 7887dc9a09..beb5d34882 100644 --- a/repos/base-linux/src/core/thread_linux.cc +++ b/repos/base-linux/src/core/thread_linux.cc @@ -64,8 +64,9 @@ void Thread::_init_platform_thread(size_t, Type) { } void Thread::_deinit_platform_thread() { } -void Thread::start() +Thread::Start_result Thread::start() { native_thread().tid = lx_create_thread(Thread::_thread_start, stack_top()); native_thread().pid = lx_getpid(); + return Start_result::OK; } diff --git a/repos/base-linux/src/lib/base/child_process.cc b/repos/base-linux/src/lib/base/child_process.cc index 54b563663d..8b9723991b 100644 --- a/repos/base-linux/src/lib/base/child_process.cc +++ b/repos/base-linux/src/lib/base/child_process.cc @@ -24,6 +24,16 @@ using namespace Genode; +static Thread_capability create_thread(auto &pd, auto &cpu, auto const &name) +{ + return cpu.create_thread(pd, name, { }, { }).template convert( + [&] (Thread_capability cap) { return cap; }, + [&] (Cpu_session::Create_thread_error) { + error("failed to create thread via CPU session"); + return Thread_capability(); }); +} + + /* * Register main thread at core * @@ -35,8 +45,7 @@ Child::Initial_thread::Initial_thread(Cpu_session &cpu, Pd_session_capability pd, Name const &name) : - _cpu(cpu), - _cap(cpu.create_thread(pd, name, Affinity::Location(), Cpu_session::Weight())) + _cpu(cpu), _cap(create_thread(pd, cpu, name)) { } diff --git a/repos/base-linux/src/lib/base/thread_linux.cc b/repos/base-linux/src/lib/base/thread_linux.cc index 815fd952cd..f34b62e639 100644 --- a/repos/base-linux/src/lib/base/thread_linux.cc +++ b/repos/base-linux/src/lib/base/thread_linux.cc @@ -110,10 +110,12 @@ void Thread::_init_platform_thread(size_t /* weight */, Type type) /* for normal threads create an object at the CPU session */ if (type == NORMAL) { - _thread_cap = _cpu_session->create_thread(pd_session_cap(), - _stack->name().string(), - Affinity::Location(), - Weight()); + _cpu_session->create_thread(pd_session_cap(), _stack->name().string(), + Affinity::Location(), Weight()).with_result( + [&] (Thread_capability cap) { _thread_cap = cap; }, + [&] (Cpu_session::Create_thread_error) { + error("Thread::_init_platform_thread: create_thread failed"); + }); return; } /* adjust initial object state for main threads */ @@ -152,11 +154,13 @@ void Thread::_deinit_platform_thread() } /* inform core about the killed thread */ - _cpu_session->kill_thread(_thread_cap); + _thread_cap.with_result( + [&] (Thread_capability cap) { _cpu_session->kill_thread(cap); }, + [&] (Cpu_session::Create_thread_error) { }); } -void Thread::start() +Thread::Start_result Thread::start() { /* synchronize calls of the 'start' function */ static Mutex mutex; @@ -181,6 +185,8 @@ void Thread::start() /* wait until the 'thread_start' function got entered */ startup_lock().block(); + + return Start_result::OK; } diff --git a/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc b/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc index e56d61da69..6778366bee 100644 --- a/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc +++ b/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc @@ -493,12 +493,13 @@ Thread *Thread::myself() } -void Thread::start() +Thread::Start_result Thread::start() { /* * Unblock thread that is supposed to slumber in 'thread_start'. */ native_thread().meta_data->started(); + return Start_result::OK; } @@ -531,9 +532,14 @@ Thread::Thread(size_t weight, const char *name, size_t /* stack size */, _thread_cap = _cpu_session->create_thread(_env_ptr->pd_session_cap(), name, Location(), Weight(weight)); - - Linux_native_cpu_client native_cpu(_cpu_session->native_cpu()); - native_cpu.thread_id(_thread_cap, native_thread().pid, native_thread().tid); + _thread_cap.with_result( + [&] (Thread_capability cap) { + Linux_native_cpu_client native_cpu(_cpu_session->native_cpu()); + native_cpu.thread_id(cap, native_thread().pid, native_thread().tid); + }, + [&] (Cpu_session::Create_thread_error) { + error("failed to create hybrid thread"); } + ); } @@ -573,7 +579,9 @@ Thread::~Thread() _native_thread = nullptr; /* inform core about the killed thread */ - _cpu_session->kill_thread(_thread_cap); + _thread_cap.with_result( + [&] (Thread_capability cap) { _cpu_session->kill_thread(cap); }, + [&] (Cpu_session::Create_thread_error) { }); } diff --git a/repos/base-nova/src/core/include/pager.h b/repos/base-nova/src/core/include/pager.h index 4f6d3a49a0..db18f28bcd 100644 --- a/repos/base-nova/src/core/include/pager.h +++ b/repos/base-nova/src/core/include/pager.h @@ -31,8 +31,6 @@ namespace Core { - typedef Cpu_session::Thread_creation_failed Invalid_thread; - class Pager_entrypoint; class Pager_object; class Exception_handlers; diff --git a/repos/base-nova/src/core/pager.cc b/repos/base-nova/src/core/pager.cc index 435ec363e6..7410f5ff62 100644 --- a/repos/base-nova/src/core/pager.cc +++ b/repos/base-nova/src/core/pager.cc @@ -58,22 +58,23 @@ struct Pager_thread: public Thread enum { PAGER_CPUS = Core::Platform::MAX_SUPPORTED_CPUS }; static Constructible pager_threads[PAGER_CPUS]; -static Pager_thread &pager_thread(Affinity::Location location, - Core::Platform &platform) +static void with_pager_thread(Affinity::Location location, + Core::Platform &platform, auto const &fn) { unsigned const pager_index = platform.pager_index(location); unsigned const kernel_cpu_id = platform.kernel_cpu_id(location); if (kernel_hip().is_cpu_enabled(kernel_cpu_id) && - pager_index < PAGER_CPUS && pager_threads[pager_index].constructed()) - return *pager_threads[pager_index]; + pager_index < PAGER_CPUS && pager_threads[pager_index].constructed()) { + + fn(*pager_threads[pager_index]); + return; + } warning("invalid CPU parameter used in pager object: ", pager_index, "->", kernel_cpu_id, " location=", location.xpos(), "x", location.ypos(), " ", location.width(), "x", location.height()); - - throw Invalid_thread(); } @@ -577,14 +578,18 @@ template void Exception_handlers::register_handler(Pager_object &obj, Mtd mtd, void (* __attribute__((regparm(1))) func)(Pager_object &)) { - addr_t const ec_sel = pager_thread(obj.location(), platform_specific()).native_thread().ec_sel; + uint8_t res = !Nova::NOVA_OK; + with_pager_thread(obj.location(), platform_specific(), [&] (Pager_thread &pager_thread) { + addr_t const ec_sel = pager_thread.native_thread().ec_sel; + + /* compiler generates instance of exception entry if not specified */ + addr_t entry = func ? (addr_t)func : (addr_t)(&_handler); + res = create_portal(obj.exc_pt_sel_client() + EV, + platform_specific().core_pd_sel(), ec_sel, mtd, entry, &obj); + }); - /* compiler generates instance of exception entry if not specified */ - addr_t entry = func ? (addr_t)func : (addr_t)(&_handler); - uint8_t res = create_portal(obj.exc_pt_sel_client() + EV, - platform_specific().core_pd_sel(), ec_sel, mtd, entry, &obj); if (res != Nova::NOVA_OK) - throw Invalid_thread(); + error("failed to register exception handler"); } @@ -634,9 +639,6 @@ Exception_handlers::Exception_handlers(Pager_object &obj) void Pager_object::_construct_pager() { - addr_t const pd_sel = platform_specific().core_pd_sel(); - addr_t const ec_sel = pager_thread(_location, platform_specific()).native_thread().ec_sel; - /* create portal for page-fault handler - 14 */ _exceptions.register_handler<14>(*this, Mtd::QUAL | Mtd::ESP | Mtd::EIP, _page_fault_handler); @@ -647,25 +649,36 @@ void Pager_object::_construct_pager() _exceptions.register_handler(*this, mtd_recall, _recall_handler); - /* create portal for final cleanup call used during destruction */ - uint8_t res = create_portal(sel_pt_cleanup(), pd_sel, ec_sel, Mtd(0), - reinterpret_cast(_invoke_handler), - this); + addr_t const pd_sel = platform_specific().core_pd_sel(); + + uint8_t res = !Nova::NOVA_OK; + + with_pager_thread(_location, platform_specific(), [&] (Pager_thread &pager_thread) { + + addr_t const ec_sel = pager_thread.native_thread().ec_sel; + + /* create portal for final cleanup call used during destruction */ + res = create_portal(sel_pt_cleanup(), pd_sel, ec_sel, Mtd(0), + reinterpret_cast(_invoke_handler), + this); + }); if (res != Nova::NOVA_OK) { error("could not create pager cleanup portal, error=", res); - throw Invalid_thread(); + return; } /* semaphore used to block paged thread during recall */ res = Nova::create_sm(sel_sm_block_pause(), pd_sel, 0); if (res != Nova::NOVA_OK) { - throw Invalid_thread(); + error("failed to initialize sel_sm_block_pause, error=", res); + return; } /* semaphore used to block paged thread during OOM memory revoke */ res = Nova::create_sm(sel_sm_block_oom(), pd_sel, 0); if (res != Nova::NOVA_OK) { - throw Invalid_thread(); + error("failed to initialize sel_sm_block_oom, error=", res); + return; } } @@ -689,8 +702,10 @@ Pager_object::Pager_object(Cpu_session_capability cpu_session_cap, _state.block(); if (Native_thread::INVALID_INDEX == _selectors || - Native_thread::INVALID_INDEX == _client_exc_pt_sel) - throw Invalid_thread(); + Native_thread::INVALID_INDEX == _client_exc_pt_sel) { + error("failed to complete construction of pager object"); + return; + } _construct_pager(); @@ -707,7 +722,7 @@ Pager_object::Pager_object(Cpu_session_capability cpu_session_cap, uint8_t const res = Nova::create_sm(exc_pt_sel_client() + SM_SEL_EC, pd_sel, 0); if (res != Nova::NOVA_OK) - throw Invalid_thread(); + error("failed to create locking semaphore for pager object"); } @@ -940,18 +955,19 @@ void Pager_object::_oom_handler(addr_t pager_dst, addr_t pager_src, addr_t Pager_object::create_oom_portal() { - try { - addr_t const pt_oom = sel_oom_portal(); - addr_t const core_pd_sel = platform_specific().core_pd_sel(); - Pager_thread &thread = pager_thread(_location, platform_specific()); - addr_t const ec_sel = thread.native_thread().ec_sel; + uint8_t res = !Nova::NOVA_OK; - uint8_t res = create_portal(pt_oom, core_pd_sel, ec_sel, Mtd(0), - reinterpret_cast(_oom_handler), - this); - if (res == Nova::NOVA_OK) - return pt_oom; - } catch (...) { } + with_pager_thread(_location, platform_specific(), + [&] (Pager_thread &thread) { + addr_t const core_pd_sel = platform_specific().core_pd_sel(); + addr_t const ec_sel = thread.native_thread().ec_sel; + res = create_portal(sel_oom_portal(), core_pd_sel, ec_sel, Mtd(0), + reinterpret_cast(_oom_handler), + this); + }); + + if (res == Nova::NOVA_OK) + return sel_oom_portal(); error("creating portal for out of memory notification failed"); return 0; diff --git a/repos/base-nova/src/core/thread_start.cc b/repos/base-nova/src/core/thread_start.cc index 062b9edda2..16a9e4721b 100644 --- a/repos/base-nova/src/core/thread_start.cc +++ b/repos/base-nova/src/core/thread_start.cc @@ -57,12 +57,10 @@ void Thread::_init_platform_thread(size_t, Type type) native_thread().exc_pt_sel = cap_map().insert(NUM_INITIAL_PT_LOG2); /* create running semaphore required for locking */ - addr_t rs_sel =native_thread().exc_pt_sel + SM_SEL_EC; + addr_t rs_sel = native_thread().exc_pt_sel + SM_SEL_EC; uint8_t res = create_sm(rs_sel, platform_specific().core_pd_sel(), 0); - if (res != NOVA_OK) { - error("create_sm returned ", res); - throw Cpu_session::Thread_creation_failed(); - } + if (res != NOVA_OK) + error("Thread::_init_platform_thread: create_sm returned ", res); } @@ -81,7 +79,7 @@ void Thread::_deinit_platform_thread() } -void Thread::start() +Thread::Start_result Thread::start() { /* * On NOVA, core almost never starts regular threads. This simply creates a @@ -99,8 +97,8 @@ void Thread::start() platform_specific().core_pd_sel(), kernel_cpu_id, (mword_t)&utcb, sp, native_thread().exc_pt_sel, LOCAL_THREAD); if (res != NOVA_OK) { - error("create_ec returned ", res); - throw Cpu_session::Thread_creation_failed(); + error("Thread::start: create_ec returned ", res); + return Start_result::DENIED; } /* default: we don't accept any mappings or translations */ @@ -111,8 +109,8 @@ void Thread::start() *reinterpret_cast(Thread::myself()->utcb()), Obj_crd(PT_SEL_PAGE_FAULT, 0), Obj_crd(native_thread().exc_pt_sel + PT_SEL_PAGE_FAULT, 0))) { - error("could not create page fault portal"); - throw Cpu_session::Thread_creation_failed(); + error("Thread::start: failed to create page-fault portal"); + return Start_result::DENIED; } struct Core_trace_source : public Core::Trace::Source::Info_accessor, @@ -147,4 +145,6 @@ void Thread::start() new (platform().core_mem_alloc()) Core_trace_source(Core::Trace::sources(), *this); + + return Start_result::OK; } diff --git a/repos/base-nova/src/lib/base/rpc_entrypoint.cc b/repos/base-nova/src/lib/base/rpc_entrypoint.cc index 727d64469e..e2cc98ef21 100644 --- a/repos/base-nova/src/lib/base/rpc_entrypoint.cc +++ b/repos/base-nova/src/lib/base/rpc_entrypoint.cc @@ -48,7 +48,7 @@ Untyped_capability Rpc_entrypoint::_manage(Rpc_object_base *obj) if (native_thread().ec_sel != Native_thread::INVALID_INDEX) ec_cap = Capability_space::import(native_thread().ec_sel); else - ec_cap = _thread_cap; + ec_cap = Thread::cap(); Untyped_capability obj_cap = _alloc_rpc_cap(_pd_session, ec_cap, (addr_t)&_activation_entry); @@ -214,14 +214,16 @@ Rpc_entrypoint::Rpc_entrypoint(Pd_session *pd_session, size_t stack_size, _cap = _alloc_rpc_cap(_pd_session, Capability_space::import(native_thread().ec_sel), (addr_t)_activation_entry); - if (!_cap.valid()) - throw Cpu_session::Thread_creation_failed(); + if (!_cap.valid()) { + error("failed to allocate RPC cap for new entrypoint"); + return; + } Receive_window &rcv_window = Thread::native_thread().server_rcv_window; /* prepare portal receive window of new thread */ if (!rcv_window.prepare_rcv_window(*(Nova::Utcb *)&_stack->utcb())) - throw Cpu_session::Thread_creation_failed(); + error("failed to prepare receive window for RPC entrypoint"); } diff --git a/repos/base-nova/src/lib/base/thread_start.cc b/repos/base-nova/src/lib/base/thread_start.cc index 762ea6b915..1717227a34 100644 --- a/repos/base-nova/src/lib/base/thread_start.cc +++ b/repos/base-nova/src/lib/base/thread_start.cc @@ -118,17 +118,19 @@ void Thread::_init_platform_thread(size_t weight, Type type) revoke(Mem_crd(utcb >> 12, 0, rwx)); native_thread().exc_pt_sel = cap_map().insert(NUM_INITIAL_PT_LOG2); - if (native_thread().exc_pt_sel == Native_thread::INVALID_INDEX) - throw Cpu_session::Thread_creation_failed(); - + if (native_thread().exc_pt_sel == Native_thread::INVALID_INDEX) { + error("failed allocate exception-portal selector for new thread"); + return; + } _init_cpu_session_and_trace_control(); /* create thread at core */ - _thread_cap = _cpu_session->create_thread(pd_session_cap(), name(), - _affinity, Weight(weight)); - if (!_thread_cap.valid()) - throw Cpu_session::Thread_creation_failed(); + _cpu_session->create_thread(pd_session_cap(), name(), + _affinity, Weight(weight)).with_result( + [&] (Thread_capability cap) { _thread_cap = cap; }, + [&] (Cpu_session::Create_thread_error) { + error("failed to create new thread for local PD"); }); } @@ -141,22 +143,28 @@ void Thread::_deinit_platform_thread() } /* de-announce thread */ - if (_thread_cap.valid()) - _cpu_session->kill_thread(_thread_cap); + _thread_cap.with_result( + [&] (Thread_capability cap) { _cpu_session->kill_thread(cap); }, + [&] (Cpu_session::Create_thread_error) { }); cap_map().remove(native_thread().exc_pt_sel, NUM_INITIAL_PT_LOG2); } -void Thread::start() +Thread::Start_result Thread::start() { - if (native_thread().ec_sel < Native_thread::INVALID_INDEX - 1) - throw Cpu_session::Thread_creation_failed(); + if (native_thread().ec_sel < Native_thread::INVALID_INDEX - 1) { + error("Thread::start failed due to invalid exception portal selector"); + return Start_result::DENIED; + } + + if (_thread_cap.failed()) + return Start_result::DENIED; /* * Default: create global thread - ec.sel == INVALID_INDEX * create local thread - ec.sel == INVALID_INDEX - 1 - */ + */ bool global = native_thread().ec_sel == Native_thread::INVALID_INDEX; using namespace Genode; @@ -174,13 +182,16 @@ void Thread::start() Cpu_session::Native_cpu::Exception_base exception_base { native_thread().exc_pt_sel }; Nova_native_cpu_client native_cpu(_cpu_session->native_cpu()); - native_cpu.thread_type(_thread_cap, thread_type, exception_base); - } catch (...) { throw Cpu_session::Thread_creation_failed(); } + native_cpu.thread_type(cap(), thread_type, exception_base); + } catch (...) { + error("Thread::start failed to set thread type"); + return Start_result::DENIED; + } /* local thread have no start instruction pointer - set via portal entry */ addr_t thread_ip = global ? reinterpret_cast(_thread_start) : native_thread().initial_ip; - Cpu_thread_client cpu_thread(_thread_cap); + Cpu_thread_client cpu_thread(cap()); cpu_thread.start(thread_ip, _stack->top()); /* request native EC thread cap */ @@ -203,6 +214,8 @@ void Thread::start() if (global) /* request creation of SC to let thread run*/ cpu_thread.resume(); + + return Start_result::OK; } diff --git a/repos/base-okl4/src/core/irq_session_component.cc b/repos/base-okl4/src/core/irq_session_component.cc index 09aca4d00c..e8e2bce9e8 100644 --- a/repos/base-okl4/src/core/irq_session_component.cc +++ b/repos/base-okl4/src/core/irq_session_component.cc @@ -80,10 +80,11 @@ void Irq_object::_wait_for_irq() } -void Irq_object::start() +Thread::Start_result Irq_object::start() { - ::Thread::start(); + Start_result const result = ::Thread::start(); _sync_bootup.block(); + return result; } diff --git a/repos/base-okl4/src/core/thread_start.cc b/repos/base-okl4/src/core/thread_start.cc index 3a61f01163..21d7894231 100644 --- a/repos/base-okl4/src/core/thread_start.cc +++ b/repos/base-okl4/src/core/thread_start.cc @@ -34,7 +34,7 @@ void Thread::_thread_start() } -void Thread::start() +Thread::Start_result Thread::start() { /* create and start platform thread */ native_thread().pt = new (Core::platform_specific().thread_slab()) @@ -43,6 +43,8 @@ void Thread::start() Core::platform_specific().core_pd().bind_thread(*native_thread().pt); native_thread().pt->start((void *)_thread_start, stack_top()); + + return Start_result::OK; } diff --git a/repos/base-pistachio/src/core/irq_session_component.cc b/repos/base-pistachio/src/core/irq_session_component.cc index a7ac996ad2..35bd3be1ae 100644 --- a/repos/base-pistachio/src/core/irq_session_component.cc +++ b/repos/base-pistachio/src/core/irq_session_component.cc @@ -53,10 +53,11 @@ void Irq_object::_wait_for_irq() } -void Irq_object::start() +Thread::Start_result Irq_object::start() { - ::Thread::start(); + Start_result const result = ::Thread::start(); _sync_bootup.block(); + return result; } diff --git a/repos/base-pistachio/src/core/platform_pd.cc b/repos/base-pistachio/src/core/platform_pd.cc index a3ee44c76a..4c628c49c2 100644 --- a/repos/base-pistachio/src/core/platform_pd.cc +++ b/repos/base-pistachio/src/core/platform_pd.cc @@ -185,10 +185,9 @@ bool Platform_pd::bind_thread(Platform_thread &thread) L4_ThreadId_t l4_thread_id; int t = _alloc_thread(thread_id, thread); - if (t < 0) { - error("thread alloc failed"); + if (t < 0) return false; - } + thread_id = t; l4_thread_id = make_l4_id(_pd_id, thread_id, _version); diff --git a/repos/base-pistachio/src/core/thread_start.cc b/repos/base-pistachio/src/core/thread_start.cc index a1fa2fc35e..41e66819cb 100644 --- a/repos/base-pistachio/src/core/thread_start.cc +++ b/repos/base-pistachio/src/core/thread_start.cc @@ -35,7 +35,7 @@ void Thread::_thread_start() } -void Thread::start() +Thread::Start_result Thread::start() { /* create and start platform thread */ native_thread().pt = new (platform().core_mem_alloc()) @@ -47,6 +47,8 @@ void Thread::start() native_thread().l4id = native_thread().pt->native_thread_id(); native_thread().pt->start((void *)_thread_start, stack_top()); + + return Start_result::OK; } diff --git a/repos/base-sel4/src/core/include/irq_object.h b/repos/base-sel4/src/core/include/irq_object.h index a6945bbcf1..e5fa51aad7 100644 --- a/repos/base-sel4/src/core/include/irq_object.h +++ b/repos/base-sel4/src/core/include/irq_object.h @@ -52,7 +52,7 @@ class Core::Irq_object : public Thread { void notify() { Signal_transmitter(_sig_cap).submit(1); } void ack_irq(); - void start() override; + Start_result start() override; bool associate(Irq_session::Trigger const, Irq_session::Polarity const); }; diff --git a/repos/base-sel4/src/core/irq_session_component.cc b/repos/base-sel4/src/core/irq_session_component.cc index e9feab77d5..108f8f9940 100644 --- a/repos/base-sel4/src/core/irq_session_component.cc +++ b/repos/base-sel4/src/core/irq_session_component.cc @@ -57,10 +57,11 @@ void Irq_object::_wait_for_irq() } -void Irq_object::start() +Thread::Start_result Irq_object::start() { - ::Thread::start(); + Thread::Start_result const result = ::Thread::start(); _sync_bootup.block(); + return result; } diff --git a/repos/base-sel4/src/core/thread_start.cc b/repos/base-sel4/src/core/thread_start.cc index cd2e34a27e..03d14ca820 100644 --- a/repos/base-sel4/src/core/thread_start.cc +++ b/repos/base-sel4/src/core/thread_start.cc @@ -99,7 +99,7 @@ void Thread::_thread_start() } -void Thread::start() +Thread::Start_result Thread::start() { /* write ipcbuffer address to utcb*/ utcb()->ipcbuffer(addr_t(utcb())); @@ -142,6 +142,8 @@ void Thread::start() new (platform().core_mem_alloc()) Core_trace_source(Core::Trace::sources(), *this); + + return Start_result::OK; } diff --git a/repos/base/include/base/child.h b/repos/base/include/base/child.h index 641c89a9e6..430f0b89fe 100644 --- a/repos/base/include/base/child.h +++ b/repos/base/include/base/child.h @@ -304,7 +304,6 @@ class Genode::Child : protected Rpc_object, /** * Constructor * - * \throw Cpu_session::Thread_creation_failed * \throw Out_of_ram * \throw Out_of_caps */ diff --git a/repos/base/include/base/quota_guard.h b/repos/base/include/base/quota_guard.h index ecf5e34d2e..86068c83cd 100644 --- a/repos/base/include/base/quota_guard.h +++ b/repos/base/include/base/quota_guard.h @@ -88,7 +88,7 @@ class Genode::Quota_guard_untyped * \return true if quota limit could be reduced, or * false if the requested amount exceeds the available quota */ - bool try_downgrade(size_t const amount) + [[nodiscard]] bool try_downgrade(size_t const amount) { if (avail() < amount) return false; @@ -103,7 +103,7 @@ class Genode::Quota_guard_untyped * \return true on success, or * false if the amount exceeds the available quota */ - bool try_withdraw(size_t const amount) + [[nodiscard]] bool try_withdraw(size_t const amount) { if (amount > avail()) return false; @@ -185,6 +185,14 @@ class Genode::Quota_guard */ void upgrade(UNIT amount) { _guard.upgrade(amount.value); } + /** + * Try to withdraw quota by specified amount + */ + bool try_withdraw(UNIT amount) + { + return _guard.try_withdraw(amount.value); + } + /** * Try to decrease quota limit by specified amount */ diff --git a/repos/base/include/base/session_object.h b/repos/base/include/base/session_object.h index fc9ce62d41..38ea670475 100644 --- a/repos/base/include/base/session_object.h +++ b/repos/base/include/base/session_object.h @@ -31,6 +31,8 @@ class Genode::Session_object : private Ram_quota_guard, typedef Session::Diag Diag; typedef Session::Resources Resources; + using Ram_quota_guard::try_withdraw; + using Cap_quota_guard::try_withdraw; using Ram_quota_guard::withdraw; using Cap_quota_guard::withdraw; using Ram_quota_guard::replenish; diff --git a/repos/base/include/base/thread.h b/repos/base/include/base/thread.h index c52f1b067e..c47a874301 100644 --- a/repos/base/include/base/thread.h +++ b/repos/base/include/base/thread.h @@ -96,11 +96,12 @@ class Genode::Thread protected: /** - * Capability for this thread (set by _start()) + * Capability for this thread or creation error (set by _start()) * * Used if thread creation involves core's CPU service. */ - Thread_capability _thread_cap { }; + Cpu_session::Create_thread_result _thread_cap = + Cpu_session::Create_thread_error::DENIED; /** * Pointer to cpu session used for this thread @@ -271,13 +272,15 @@ class Genode::Thread */ virtual void entry() = 0; + enum class Start_result { OK, DENIED }; + /** * Start execution of the thread * * This method is virtual to enable the customization of threads * used as server activation. */ - virtual void start(); + virtual Start_result start(); /** * Request name of thread @@ -316,7 +319,15 @@ class Genode::Thread /** * Request capability of thread */ - Thread_capability cap() const { return _thread_cap; } + Thread_capability cap() const + { + return _thread_cap.convert( + [&] (Thread_capability cap) { return cap; }, + [&] (auto) { + error("attempt to obtain cap of incomplete thread"); + return Thread_capability(); + }); + } /** * Return kernel-specific thread meta data diff --git a/repos/base/include/cpu_session/client.h b/repos/base/include/cpu_session/client.h index e677d64ef5..48ed7ad007 100644 --- a/repos/base/include/cpu_session/client.h +++ b/repos/base/include/cpu_session/client.h @@ -25,7 +25,7 @@ struct Genode::Cpu_session_client : Rpc_client explicit Cpu_session_client(Cpu_session_capability session) : Rpc_client(session) { } - Thread_capability + Create_thread_result create_thread(Capability pd, Name const &name, Affinity::Location affinity, Weight weight, addr_t utcb = 0) override { return call(pd, name, affinity, weight, utcb); } diff --git a/repos/base/include/cpu_session/connection.h b/repos/base/include/cpu_session/connection.h index 30a44dfb4c..aedbb5d385 100644 --- a/repos/base/include/cpu_session/connection.h +++ b/repos/base/include/cpu_session/connection.h @@ -38,14 +38,29 @@ struct Genode::Cpu_connection : Connection, Cpu_session_client Cpu_session_client(cap()) { } - Thread_capability create_thread(Capability pd, - Name const &name, - Affinity::Location affinity, - Weight weight, - addr_t utcb = 0) override + Create_thread_result create_thread(Capability pd, + Name const &name, + Affinity::Location affinity, + Weight weight, + addr_t utcb = 0) override { - return retry_with_upgrade(Ram_quota{8*1024}, Cap_quota{2}, [&] () { - return Cpu_session_client::create_thread(pd, name, affinity, weight, utcb); }); + Thread_capability result { }; + bool denied = false; + while (!result.valid()) { + using Error = Cpu_session::Create_thread_error; + Cpu_session_client::create_thread(pd, name, affinity, weight, utcb).with_result( + [&] (Thread_capability cap) { result = cap; }, + [&] (Error e) { + switch (e) { + case Error::OUT_OF_RAM: upgrade_ram(8*1024); break; + case Error::OUT_OF_CAPS: upgrade_caps(2); break; + case Error::DENIED: denied = true; break; + } + }); + if (denied) + return Error::DENIED; + } + return result; } }; diff --git a/repos/base/include/cpu_session/cpu_session.h b/repos/base/include/cpu_session/cpu_session.h index 25474bc8ae..a0c7200f4e 100644 --- a/repos/base/include/cpu_session/cpu_session.h +++ b/repos/base/include/cpu_session/cpu_session.h @@ -14,9 +14,9 @@ #ifndef _INCLUDE__CPU_SESSION__CPU_SESSION_H_ #define _INCLUDE__CPU_SESSION__CPU_SESSION_H_ +#include #include #include -#include #include #include #include @@ -27,7 +27,7 @@ namespace Genode { struct Cpu_session; struct Cpu_session_client; - typedef Capability Thread_capability; + using Thread_capability = Capability; } @@ -46,18 +46,13 @@ struct Genode::Cpu_session : Session static constexpr unsigned CAP_QUOTA = 6; static constexpr size_t RAM_QUOTA = 36*1024; - typedef Cpu_session_client Client; + using Client = Cpu_session_client; /********************* ** Exception types ** *********************/ - class Thread_creation_failed : public Exception { }; - class Quota_exceeded : public Thread_creation_failed { }; - - - enum { THREAD_NAME_LEN = 32 }; enum { PRIORITY_LIMIT = 1 << 16 }; enum { QUOTA_LIMIT_LOG2 = 15 }; enum { QUOTA_LIMIT = 1 << QUOTA_LIMIT_LOG2 }; @@ -68,13 +63,13 @@ struct Genode::Cpu_session : Session */ struct Weight { - enum { DEFAULT_WEIGHT = 10 }; + static constexpr size_t DEFAULT_WEIGHT = 10; size_t value = DEFAULT_WEIGHT; Weight() { } explicit Weight(size_t value) : value(value) { } }; - typedef String Name; + using Name = String<32>; /** * Physical quota configuration @@ -83,6 +78,9 @@ struct Genode::Cpu_session : Session virtual ~Cpu_session() { } + enum class Create_thread_error { OUT_OF_RAM, OUT_OF_CAPS, DENIED }; + using Create_thread_result = Attempt; + /** * Create a new thread * @@ -93,15 +91,12 @@ struct Genode::Cpu_session : Session * \param weight CPU quota that shall be granted to the thread * \param utcb base of the UTCB that will be used by the thread * \return capability representing the new thread - * \throw Thread_creation_failed - * \throw Out_of_ram - * \throw Out_of_caps */ - virtual Thread_capability create_thread(Capability pd, - Name const &name, - Affinity::Location affinity, - Weight weight, - addr_t utcb = 0) = 0; + virtual Create_thread_result create_thread(Capability pd, + Name const &name, + Affinity::Location affinity, + Weight weight, + addr_t utcb = 0) = 0; /** * Kill an existing thread @@ -233,10 +228,9 @@ struct Genode::Cpu_session : Session ** RPC declaration ** *********************/ - GENODE_RPC_THROW(Rpc_create_thread, Thread_capability, create_thread, - GENODE_TYPE_LIST(Thread_creation_failed, Out_of_ram, Out_of_caps), - Capability, Name const &, Affinity::Location, - Weight, addr_t); + GENODE_RPC(Rpc_create_thread, Create_thread_result, create_thread, + Capability, Name const &, Affinity::Location, + Weight, addr_t); GENODE_RPC(Rpc_kill_thread, void, kill_thread, Thread_capability); GENODE_RPC(Rpc_exception_sigh, void, exception_sigh, Signal_context_capability); GENODE_RPC(Rpc_affinity_space, Affinity::Space, affinity_space); diff --git a/repos/base/src/core/cpu_session_component.cc b/repos/base/src/core/cpu_session_component.cc index e487029c78..e1274c1462 100644 --- a/repos/base/src/core/cpu_session_component.cc +++ b/repos/base/src/core/cpu_session_component.cc @@ -25,73 +25,66 @@ using namespace Core; -Thread_capability Cpu_session_component::create_thread(Capability pd_cap, - Name const &name, - Affinity::Location affinity, - Weight weight, - addr_t utcb) +Cpu_session::Create_thread_result +Cpu_session_component::create_thread(Capability pd_cap, + Name const &name, Affinity::Location affinity, + Weight weight, addr_t utcb) { - Trace::Thread_name thread_name(name.string()); + if (!try_withdraw(Ram_quota{_utcb_quota_size()})) + return Create_thread_error::OUT_OF_RAM; - withdraw(Ram_quota{_utcb_quota_size()}); + if (weight.value == 0) { + warning("Thread ", name, ": Bad weight 0, using default weight instead."); + weight = Weight(); + } + if (weight.value > QUOTA_LIMIT) { + warning("Thread ", name, ": Oversized weight ", weight.value, ", using limit instead."); + weight = Weight(QUOTA_LIMIT); + } - try { + Mutex::Guard thread_list_lock_guard(_thread_list_lock); - Cpu_thread_component *thread = 0; + Create_thread_result result = Create_thread_error::DENIED; - if (weight.value == 0) { - warning("Thread ", name, ": Bad weight 0, using default weight instead."); - weight = Weight(); - } - if (weight.value > QUOTA_LIMIT) { - warning("Thread ", name, ": Oversized weight ", weight.value, ", using limit instead."); - weight = Weight(QUOTA_LIMIT); + _incr_weight(weight.value); + + _thread_ep.apply(pd_cap, [&] (Pd_session_component *pd) { + + if (!pd) { + error("create_thread: invalid PD argument"); + return; } - Mutex::Guard thread_list_lock_guard(_thread_list_lock); + Mutex::Guard slab_lock_guard(_thread_alloc_lock); - /* - * Create thread associated with its protection domain - */ - auto create_thread_lambda = [&] (Pd_session_component *pd) { - if (!pd) { - error("create_thread: invalid PD argument"); - throw Thread_creation_failed(); - } - - Mutex::Guard slab_lock_guard(_thread_alloc_lock); - thread = new (&_thread_alloc) + try { + Cpu_thread_component &thread = *new (&_thread_alloc) Cpu_thread_component( cap(), _thread_ep, _pager_ep, *pd, _trace_control_area, _trace_sources, weight, _weight_to_quota(weight.value), - _thread_affinity(affinity), _label, thread_name, + _thread_affinity(affinity), _label, name, _priority, utcb); - }; - try { - _incr_weight(weight.value); - _thread_ep.apply(pd_cap, create_thread_lambda); - } catch (Allocator::Out_of_memory) { - _decr_weight(weight.value); - throw Out_of_ram(); - } catch (Native_capability::Reference_count_overflow) { - _decr_weight(weight.value); - throw Thread_creation_failed(); - } catch (...) { - _decr_weight(weight.value); - throw; + if (!thread.valid()) { + destroy(_thread_alloc, &thread); + return; + } + + thread.session_exception_sigh(_exception_sigh); + + _thread_list.insert(&thread); + result = thread.cap(); } + catch (Out_of_ram) { result = Create_thread_error::OUT_OF_RAM; } + catch (Out_of_caps) { result = Create_thread_error::OUT_OF_CAPS; } + catch (...) { result = Create_thread_error::DENIED; } + }); - thread->session_exception_sigh(_exception_sigh); - - _thread_list.insert(thread); - - return thread->cap(); - - } catch (...) { + if (result.failed()) { + _decr_weight(weight.value); replenish(Ram_quota{_utcb_quota_size()}); - throw; } + return result; } diff --git a/repos/base/src/core/include/account.h b/repos/base/src/core/include/account.h index 763a8244a6..6676cf5577 100644 --- a/repos/base/src/core/include/account.h +++ b/repos/base/src/core/include/account.h @@ -192,6 +192,17 @@ class Core::Account _quota_guard.withdraw(amount); } + /** + * Withdraw quota from account + * + * \return true if withdrawal of 'amount' succeeded + */ + [[nodiscard]] bool try_withdraw(UNIT amount) + { + Mutex::Guard guard(_mutex); + return _quota_guard.try_withdraw(amount); + } + /** * Replenish quota to account * diff --git a/repos/base/src/core/include/cpu_session_component.h b/repos/base/src/core/include/cpu_session_component.h index c309210b80..78559171e2 100644 --- a/repos/base/src/core/include/cpu_session_component.h +++ b/repos/base/src/core/include/cpu_session_component.h @@ -166,8 +166,8 @@ class Core::Cpu_session_component : public Session_object, ** CPU session interface ** ***************************/ - Thread_capability create_thread(Capability, Name const &, - Affinity::Location, Weight, addr_t) override; + Create_thread_result create_thread(Capability, Name const &, + Affinity::Location, Weight, addr_t) override; void kill_thread(Thread_capability) override; void exception_sigh(Signal_context_capability) override; Affinity::Space affinity_space() const override; diff --git a/repos/base/src/core/include/cpu_thread_component.h b/repos/base/src/core/include/cpu_thread_component.h index 84cec38f21..825784e217 100644 --- a/repos/base/src/core/include/cpu_thread_component.h +++ b/repos/base/src/core/include/cpu_thread_component.h @@ -55,9 +55,7 @@ class Core::Cpu_thread_component : public Rpc_object, bool _bind_to_pd(Pd_session_component &pd) { - if (!pd.bind_thread(_platform_thread)) - throw Cpu_session::Thread_creation_failed(); - return true; + return pd.bind_thread(_platform_thread); } /** @@ -183,6 +181,8 @@ class Core::Cpu_thread_component : public Rpc_object, _address_space_region_map.remove_client(_rm_client); } + bool valid() const { return _bound_to_pd; }; + /******************************************** ** Trace::Source::Info_accessor interface ** diff --git a/repos/base/src/core/include/irq_object.h b/repos/base/src/core/include/irq_object.h index b39cb9beba..87a5147f63 100644 --- a/repos/base/src/core/include/irq_object.h +++ b/repos/base/src/core/include/irq_object.h @@ -43,7 +43,7 @@ class Core::Irq_object : public Thread void sigh(Signal_context_capability cap) { _sig_cap = cap; } void ack_irq() { _sync_ack.wakeup(); } - void start() override; + Start_result start() override; }; #endif /* _CORE__INCLUDE__IRQ_OBJECT_H_ */ diff --git a/repos/base/src/core/include/pager.h b/repos/base/src/core/include/pager.h index a61e45af3b..925c099d38 100644 --- a/repos/base/src/core/include/pager.h +++ b/repos/base/src/core/include/pager.h @@ -30,8 +30,6 @@ namespace Core { - typedef Cpu_session::Thread_creation_failed Invalid_thread; - /** * Special server object for paging * @@ -84,8 +82,6 @@ class Core::Pager_object : public Object_pool::Entry * Constructor * * \param location affinity of paged thread to physical CPU - * - * \throw Invalid_thread */ Pager_object(Cpu_session_capability cpu_sesion, Thread_capability thread, diff --git a/repos/base/src/include/base/internal/expanding_cpu_session_client.h b/repos/base/src/include/base/internal/expanding_cpu_session_client.h index 3b47b3a30a..4f73b24bc9 100644 --- a/repos/base/src/include/base/internal/expanding_cpu_session_client.h +++ b/repos/base/src/include/base/internal/expanding_cpu_session_client.h @@ -38,19 +38,27 @@ struct Genode::Expanding_cpu_session_client : Upgradeable_client(cap), id) { } - Thread_capability + Create_thread_result create_thread(Pd_session_capability pd, Name const &name, Affinity::Location location, Weight weight, addr_t utcb) override { - return retry( - [&] () { - return retry( - [&] () { - return Cpu_session_client::create_thread(pd, name, location, - weight, utcb); }, - [&] () { upgrade_caps(2); }); - }, - [&] () { upgrade_ram(8*1024); }); + Thread_capability result { }; + bool denied = false; + while (!result.valid()) { + using Error = Cpu_session::Create_thread_error; + Cpu_session_client::create_thread(pd, name, location, weight, utcb).with_result( + [&] (Thread_capability cap) { result = cap; }, + [&] (Error e) { + switch (e) { + case Error::OUT_OF_RAM: upgrade_ram(8*1024); break; + case Error::OUT_OF_CAPS: upgrade_caps(2); break; + case Error::DENIED: denied = true; break; + } + }); + if (denied) + return Error::DENIED; + } + return result; } }; diff --git a/repos/base/src/lib/base/child.cc b/repos/base/src/lib/base/child.cc index 93140d6f0e..4bc3775ed0 100644 --- a/repos/base/src/lib/base/child.cc +++ b/repos/base/src/lib/base/child.cc @@ -755,13 +755,12 @@ void Child::_try_construct_env_dependent_members() *_initial_thread, _initial_thread_start, _local_rm, address_space, cap()); }); } - catch (Out_of_ram) { _error("out of RAM during ELF loading"); } - catch (Out_of_caps) { _error("out of caps during ELF loading"); } - catch (Cpu_session::Thread_creation_failed) { _error("unable to create initial thread"); } - catch (Process::Missing_dynamic_linker) { _error("dynamic linker unavailable"); } - catch (Process::Invalid_executable) { _error("invalid ELF executable"); } - catch (Region_map::Invalid_dataspace) { _error("ELF loading failed (Invalid_dataspace)"); } - catch (Region_map::Region_conflict) { _error("ELF loading failed (Region_conflict)"); } + catch (Out_of_ram) { _error("out of RAM during ELF loading"); } + catch (Out_of_caps) { _error("out of caps during ELF loading"); } + catch (Process::Missing_dynamic_linker) { _error("dynamic linker unavailable"); } + catch (Process::Invalid_executable) { _error("invalid ELF executable"); } + catch (Region_map::Invalid_dataspace) { _error("ELF loading failed (Invalid_dataspace)"); } + catch (Region_map::Region_conflict) { _error("ELF loading failed (Region_conflict)"); } } diff --git a/repos/base/src/lib/base/child_process.cc b/repos/base/src/lib/base/child_process.cc index 3545735583..59235dc07f 100644 --- a/repos/base/src/lib/base/child_process.cc +++ b/repos/base/src/lib/base/child_process.cc @@ -155,12 +155,21 @@ Child::Process::Loaded_executable::Loaded_executable(Type type, } +static Thread_capability create_thread(auto &pd, auto &cpu, auto const &name) +{ + return cpu.create_thread(pd, name, { }, { }).template convert( + [&] (Thread_capability cap) { return cap; }, + [&] (Cpu_session::Create_thread_error) { + error("failed to create initial thread for new PD"); + return Thread_capability(); }); +} + + Child::Initial_thread::Initial_thread(Cpu_session &cpu, Pd_session_capability pd, Name const &name) : - _cpu(cpu), - _cap(cpu.create_thread(pd, name, Affinity::Location(), Cpu_session::Weight())) + _cpu(cpu), _cap(create_thread(pd, cpu, name)) { } diff --git a/repos/base/src/lib/base/thread_start.cc b/repos/base/src/lib/base/thread_start.cc index c7fb1325ac..5b6d619850 100644 --- a/repos/base/src/lib/base/thread_start.cc +++ b/repos/base/src/lib/base/thread_start.cc @@ -71,23 +71,29 @@ void Thread::_deinit_platform_thread() return; } - _cpu_session->kill_thread(_thread_cap); + _thread_cap.with_result( + [&] (Thread_capability cap) { _cpu_session->kill_thread(cap); }, + [&] (auto) { }); } -void Thread::start() +Thread::Start_result Thread::start() { _init_cpu_session_and_trace_control(); /* create thread at core */ addr_t const utcb = (addr_t)&_stack->utcb(); - _thread_cap = _cpu_session->create_thread(pd_session_cap(), name(), - _affinity, Weight(), utcb); - if (!_thread_cap.valid()) - throw Cpu_session::Thread_creation_failed(); - /* start execution at initial instruction pointer and stack pointer */ - Cpu_thread_client(_thread_cap).start((addr_t)_thread_start, _stack->top()); + _thread_cap = _cpu_session->create_thread(pd_session_cap(), name(), _affinity, + Weight(), utcb); + return _thread_cap.convert( + [&] (Thread_capability cap) { + + /* start execution at initial instruction pointer and stack pointer */ + Cpu_thread_client(cap).start((addr_t)_thread_start, _stack->top()); + return Start_result::OK; + }, + [&] (Cpu_session::Create_thread_error) { return Start_result::DENIED; }); } diff --git a/repos/base/src/lib/base/trace.cc b/repos/base/src/lib/base/trace.cc index d3d72321cb..17505db90f 100644 --- a/repos/base/src/lib/base/trace.cc +++ b/repos/base/src/lib/base/trace.cc @@ -222,8 +222,10 @@ Trace::Logger *Thread::_logger() if (!logger.initialized()) { logger.init_pending(true); - Thread_capability thread_cap = myself ? myself->_thread_cap - : _env().parent().main_thread_cap(); + using Create_result = Cpu_session::Create_thread_result; + Create_result const thread_cap = + myself ? myself->_thread_cap + : Create_result(_env().parent().main_thread_cap()); Cpu_session &cpu = myself ? *myself->_cpu_session : _env().cpu(); @@ -234,8 +236,11 @@ Trace::Logger *Thread::_logger() main_trace_control = _env().rm().attach(ds); } - logger.init(thread_cap, &cpu, - myself ? myself->_trace_control : main_trace_control); + thread_cap.with_result( + [&] (Thread_capability cap) { + logger.init(cap, &cpu, myself ? myself->_trace_control + : main_trace_control); }, + [&] (Cpu_session::Create_thread_error) { }); } return &logger; diff --git a/repos/base/src/test/thread/main.cc b/repos/base/src/test/thread/main.cc index 09718ce129..b5b7bf60c9 100644 --- a/repos/base/src/test/thread/main.cc +++ b/repos/base/src/test/thread/main.cc @@ -312,26 +312,33 @@ static void test_create_as_many_threads(Env &env) Heap heap(env.ram(), env.rm()); unsigned i = 0; - try { - for (; i < max; i++) { - try { - threads[i] = new (heap) Cpu_helper(env, Thread::Name(i + 1), env.cpu()); - threads[i]->start(); - threads[i]->join(); - } catch (Cpu_session::Thread_creation_failed) { - throw "Thread_creation_failed"; - } catch (Thread::Out_of_stack_space) { - throw "Out_of_stack_space"; - } catch (Genode::Native_capability::Reference_count_overflow) { - throw "Native_capability::Reference_count_overflow"; + bool denied = false; + bool out_of_stack_space = false; + for (; i < max; i++) { + try { + threads[i] = new (heap) Cpu_helper(env, Thread::Name(i + 1), env.cpu()); + if (threads[i]->start() == Thread::Start_result::DENIED) { + denied = true; + break; } + threads[i]->join(); + } catch (Thread::Out_of_stack_space) { + out_of_stack_space = true; + break; + } catch (Genode::Native_capability::Reference_count_overflow) { + warning("Native_capability::Reference_count_overflow"); + denied = true; + break; } - } catch (const char * ex) { - log("created ", i, " threads before I got '", ex, "'"); - for (unsigned j = i; j > 0; j--) { - destroy(heap, threads[j - 1]); - threads[j - 1] = nullptr; - } + } + + for (unsigned j = i; j > 0; j--) { + destroy(heap, threads[j - 1]); + threads[j - 1] = nullptr; + } + + if (denied) { + log("created ", i, " threads before thread creation got denied"); return; } @@ -339,7 +346,8 @@ static void test_create_as_many_threads(Env &env) * We have to get a Out_of_stack_space message, because we can't create * up to max threads, because already the main thread is running ... */ - throw -21; + if (!out_of_stack_space) + throw -21; } diff --git a/repos/gems/src/server/cpu_sampler/cpu_session_component.cc b/repos/gems/src/server/cpu_sampler/cpu_session_component.cc index 2f93ac88cb..091628b762 100644 --- a/repos/gems/src/server/cpu_sampler/cpu_session_component.cc +++ b/repos/gems/src/server/cpu_sampler/cpu_session_component.cc @@ -21,7 +21,7 @@ using namespace Genode; using namespace Cpu_sampler; -Thread_capability +Cpu_session::Create_thread_result Cpu_sampler::Cpu_session_component::create_thread(Pd_session_capability pd, Name const &name, Affinity::Location affinity, diff --git a/repos/gems/src/server/cpu_sampler/cpu_session_component.h b/repos/gems/src/server/cpu_sampler/cpu_session_component.h index 918f7c4889..5eb6cec609 100644 --- a/repos/gems/src/server/cpu_sampler/cpu_session_component.h +++ b/repos/gems/src/server/cpu_sampler/cpu_session_component.h @@ -97,11 +97,11 @@ class Cpu_sampler::Cpu_session_component : public Rpc_object ** CPU session interface ** ***************************/ - Thread_capability create_thread(Pd_session_capability pd, - Name const &, - Affinity::Location, - Weight, - addr_t) override; + Create_thread_result create_thread(Pd_session_capability pd, + Name const &, + Affinity::Location, + Weight, + addr_t) override; void kill_thread(Thread_capability) override; void exception_sigh(Signal_context_capability handler) override; Affinity::Space affinity_space() const override; diff --git a/repos/gems/src/server/cpu_sampler/cpu_thread_component.cc b/repos/gems/src/server/cpu_sampler/cpu_thread_component.cc index 22d19665d3..08091ab6c3 100644 --- a/repos/gems/src/server/cpu_sampler/cpu_thread_component.cc +++ b/repos/gems/src/server/cpu_sampler/cpu_thread_component.cc @@ -36,7 +36,12 @@ Cpu_sampler::Cpu_thread_component::Cpu_thread_component( _cpu_session_component(cpu_session_component), _env(env), _md_alloc(md_alloc), _parent_cpu_thread( _cpu_session_component.parent_cpu_session() - .create_thread(pd, name, affinity, weight, utcb)), + .create_thread(pd, name, affinity, weight, utcb) + .convert( + [&] (Thread_capability cap) { return cap; }, + [&] (auto) { + error("failed to create CPU thread"); + return Thread_capability(); })), _label(_cpu_session_component.session_label().string(), " -> ", thread_name), _log_session_label("samples -> ", _label, ".", thread_id) { diff --git a/repos/os/src/monitor/inferior_cpu.h b/repos/os/src/monitor/inferior_cpu.h index d0ab6b2672..dce2dee018 100644 --- a/repos/os/src/monitor/inferior_cpu.h +++ b/repos/os/src/monitor/inferior_cpu.h @@ -51,29 +51,33 @@ struct Monitor::Inferior_cpu : Monitored_cpu_session ** Cpu_session interface ** ***************************/ - Thread_capability + Create_thread_result create_thread(Capability pd, Cpu_session::Name const &name, Affinity::Location affinity, Weight weight, addr_t utcb) override { - Thread_capability result { }; + Create_thread_result result = Create_thread_error::DENIED; Inferior_pd::with_inferior_pd(_ep, pd, + [&] (Inferior_pd &inferior_pd) { + _real.call(inferior_pd._real, name, affinity, + weight, utcb).with_result( - Capability real_thread = - _real.call(inferior_pd._real, - name, affinity, weight, utcb); + [&] (Thread_capability real_thread) { - Threads::Id thread_id { inferior_pd.alloc_thread_id() }; - bool wait = inferior_pd._policy.wait && - (thread_id == Threads::Id { 1 }); + Threads::Id thread_id { inferior_pd.alloc_thread_id() }; + bool const wait = inferior_pd._policy.wait + && (thread_id == Threads::Id { 1 }); - Monitored_thread &monitored_thread = *new (_alloc) - Monitored_thread(_ep, real_thread, name, - inferior_pd._threads, thread_id, - pd, _thread_monitor, wait); + Monitored_thread &monitored_thread = *new (_alloc) + Monitored_thread(_ep, real_thread, name, + inferior_pd._threads, thread_id, + pd, _thread_monitor, wait); - result = monitored_thread.cap(); + result = monitored_thread.cap(); + }, + [&] (Create_thread_error e) { result = e; } + ); }, [&] { result = _real.call(pd, name, affinity, weight, utcb); diff --git a/repos/os/src/monitor/pd_intrinsics.h b/repos/os/src/monitor/pd_intrinsics.h index d9dc618a74..c374ff3b66 100644 --- a/repos/os/src/monitor/pd_intrinsics.h +++ b/repos/os/src/monitor/pd_intrinsics.h @@ -74,7 +74,7 @@ struct Monitor::Pd_intrinsics : Sandbox::Pd_intrinsics using Sig_ctx_cap = Signal_context_capability; - Thread_capability + Create_thread_result create_thread(Capability, Cpu_session::Name const &, Affinity::Location, Weight, addr_t) override { never_called(__func__); } void kill_thread(Thread_capability) override { never_called(__func__); } diff --git a/repos/os/src/server/cpu_balancer/session.cc b/repos/os/src/server/cpu_balancer/session.cc index ab252aebe1..2c17e52d2a 100644 --- a/repos/os/src/server/cpu_balancer/session.cc +++ b/repos/os/src/server/cpu_balancer/session.cc @@ -17,14 +17,14 @@ using namespace Genode; using namespace Cpu; -Thread_capability +Cpu_session::Create_thread_result Cpu::Session::create_thread(Pd_session_capability const pd, Name const &name_by_client, Affinity::Location const location, Weight const weight, addr_t const utcb) { - Thread_capability cap { }; + Create_thread_result result = Create_thread_error::DENIED; Name name = name_by_client; if (!name.valid()) @@ -33,9 +33,9 @@ Cpu::Session::create_thread(Pd_session_capability const pd, /* quirk since init can't handle Out_of_* during first create_thread call */ if ((_reclaim_ram.value || _reclaim_cap.value) && _one_valid_thread()) { if (_reclaim_ram.value) - throw Out_of_ram(); + return Create_thread_error::OUT_OF_RAM; if (_reclaim_cap.value) - throw Out_of_caps(); + return Create_thread_error::OUT_OF_CAPS; } /* read in potential existing policy for thread */ @@ -47,33 +47,39 @@ Cpu::Session::create_thread(Pd_session_capability const pd, if (store_cap.valid()) return false; - cap = _parent.create_thread(pd, name, location, weight, utcb); - if (!cap.valid()) - /* stop creation attempt by saying done */ - return true; + result = _parent.create_thread(pd, name, location, weight, utcb); + return result.convert( - /* policy and name are set beforehand */ - store_cap = cap; + [&] (Thread_capability cap) { + /* policy and name are set beforehand */ + store_cap = cap; - /* for static case with valid location, don't overwrite config */ - policy.thread_create(location); + /* for static case with valid location, don't overwrite config */ + policy.thread_create(location); - if (_verbose) - log("[", _label, "] new thread at ", - policy.location.xpos(), "x", policy.location.ypos(), - ", policy=", policy, ", name='", name, "'"); + if (_verbose) + log("[", _label, "] new thread at ", + policy.location.xpos(), "x", policy.location.ypos(), + ", policy=", policy, ", name='", name, "'"); - return true; + return true; + }, + + [&] (Create_thread_error) { + /* stop creation attempt by saying done */ + return true; + } + ); }); - if (cap.valid()) { + if (result.ok()) { _report = true; - return cap; + return result; } - cap = _parent.create_thread(pd, name, location, weight, utcb); - if (!cap.valid()) - return cap; + result = _parent.create_thread(pd, name, location, weight, utcb); + if (result.failed()) + return result; /* unknown thread without any configuration */ construct(_default_policy, [&](Thread_capability &store_cap, @@ -81,20 +87,24 @@ Cpu::Session::create_thread(Pd_session_capability const pd, { policy.location = location; - store_cap = cap; - store_name = name; + result.with_result( + [&] (Thread_capability cap) { + store_cap = cap; + store_name = name; - if (_verbose) - log("[", _label, "] new thread at ", - location.xpos(), "x", location.ypos(), - ", no policy defined", - ", name='", name, "'"); + if (_verbose) + log("[", _label, "] new thread at ", + location.xpos(), "x", location.ypos(), + ", no policy defined", + ", name='", name, "'"); + }, + [&] (Create_thread_error) { }); }); - if (cap.valid()) + if (result.ok()) _report = true; - return cap; + return result; } diff --git a/repos/os/src/server/cpu_balancer/session.h b/repos/os/src/server/cpu_balancer/session.h index eda3b96ea0..c4c151c41c 100644 --- a/repos/os/src/server/cpu_balancer/session.h +++ b/repos/os/src/server/cpu_balancer/session.h @@ -328,10 +328,10 @@ class Cpu::Session : public Rpc_object ** CPU session interface ** ***************************/ - Thread_capability create_thread(Pd_session_capability, - Thread::Name const &, - Affinity::Location, Weight, - addr_t) override; + Create_thread_result create_thread(Pd_session_capability, + Thread::Name const &, + Affinity::Location, Weight, + addr_t) override; void kill_thread(Thread_capability) override; void exception_sigh(Signal_context_capability) override; Affinity::Space affinity_space() const override; diff --git a/repos/ports/include/vmm/vcpu_thread.h b/repos/ports/include/vmm/vcpu_thread.h index 3c92d8b4a8..9d2353e252 100644 --- a/repos/ports/include/vmm/vcpu_thread.h +++ b/repos/ports/include/vmm/vcpu_thread.h @@ -76,13 +76,29 @@ class Vmm::Vcpu_other_pd : public Vmm::Vcpu_thread { using namespace Genode; - Thread_capability vcpu_vm = - _cpu_connection->retry_with_upgrade(Ram_quota{8*1024}, Cap_quota{2}, - [&] () - { - return _cpu_connection->create_thread(_pd_cap, "vCPU", _location, - Cpu_session::Weight()); - }); + Thread_capability vcpu_vm { }; + + while (!vcpu_vm.valid()) { + + bool denied = false; + + using Error = Cpu_session::Create_thread_error; + _cpu_connection->create_thread(_pd_cap, "vCPU", _location, + Cpu_session::Weight()).with_result( + [&] (Thread_capability cap) { vcpu_vm = cap; }, + [&] (Error e) { + if (e == Error::OUT_OF_RAM) _cpu_connection->upgrade_ram(8*1024); + else if (e == Error::OUT_OF_CAPS) _cpu_connection->upgrade_caps(2); + else + denied = true; + } + ); + + if (denied) { + error("Vcpu_other_pd: failed to create vCPU"); + return; + } + } /* tell parent that this will be a vCPU */ Cpu_session::Native_cpu::Thread_type thread_type { Cpu_session::Native_cpu::Thread_type::VCPU }; diff --git a/repos/ports/src/virtualbox5/spec/nova/vcpu.h b/repos/ports/src/virtualbox5/spec/nova/vcpu.h index 0957bd2d33..216b91a2fd 100644 --- a/repos/ports/src/virtualbox5/spec/nova/vcpu.h +++ b/repos/ports/src/virtualbox5/spec/nova/vcpu.h @@ -861,8 +861,10 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher, unsigned int cpu_id() { return _cpu_id; } - void start() { + Start_result start() override + { _vcpu.start(_ec_sel); + return Start_result::OK; } void recall(Vcpu_handler * other = nullptr)