diff --git a/repos/base-fiasco/src/core/thread_start.cc b/repos/base-fiasco/src/core/thread_start.cc index 7c49f350fa..11d81aa6f3 100644 --- a/repos/base-fiasco/src/core/thread_start.cc +++ b/repos/base-fiasco/src/core/thread_start.cc @@ -35,26 +35,25 @@ void Thread::_thread_start() Thread::Start_result Thread::start() { - if (!_stack) - return Start_result::DENIED; + return _stack.convert([&] (Stack * const stack) { - Stack &stack = *_stack; + Native_thread &nt = stack->native_thread(); - Native_thread &nt = stack.native_thread(); + /* create and start platform thread */ + try { + nt.pt = new (platform().core_mem_alloc()) + Platform_thread(platform_specific().core_pd(), name.string()); + } + catch (...) { return Start_result::DENIED; } - /* create and start platform thread */ - try { - nt.pt = new (platform().core_mem_alloc()) - Platform_thread(platform_specific().core_pd(), stack.name().string()); - } - catch (...) { return Start_result::DENIED; } + nt.pt->pager(platform_specific().core_pager()); + nt.l4id = nt.pt->native_thread_id(); - nt.pt->pager(platform_specific().core_pager()); - nt.l4id = nt.pt->native_thread_id(); + nt.pt->start((void *)_thread_start, (void *)stack->top()); - nt.pt->start((void *)_thread_start, (void *)stack.top()); + return Start_result::OK; - return Start_result::OK; + }, [&] (Stack_error) { return Start_result::DENIED; }); } diff --git a/repos/base-foc/src/core/thread_start.cc b/repos/base-foc/src/core/thread_start.cc index 6ef235f3ce..aa88f598a6 100644 --- a/repos/base-foc/src/core/thread_start.cc +++ b/repos/base-foc/src/core/thread_start.cc @@ -63,11 +63,11 @@ namespace { addr_t const kcap = (addr_t) platform_thread.pager_object_badge(); l4_msgtag_t res = l4_thread_stats_time(kcap, &ec_time); if (l4_error(res)) - Genode::error("cpu time for ", thread.name(), + Genode::error("cpu time for ", thread.name, " is not available ", l4_error(res)); } - return { Session_label("core"), thread.name(), + return { Session_label("core"), thread.name, Genode::Trace::Execution_time(ec_time, sc_time, 10000, platform_thread.prio()), thread.affinity() }; @@ -92,7 +92,7 @@ Thread::Start_result Thread::start() try { /* create and start platform thread */ Platform_thread &pt = *new (platform().core_mem_alloc()) - Platform_thread(_stack->name().string()); + Platform_thread(name.string()); platform_specific().core_pd().bind_thread(pt); @@ -111,15 +111,21 @@ Thread::Start_result Thread::start() l4_utcb_tcr_u(foc_utcb)->user[UTCB_TCR_BADGE] = (unsigned long) pt.gate().local.data(); l4_utcb_tcr_u(foc_utcb)->user[UTCB_TCR_THREAD_OBJ] = (addr_t)this; - pt.start((void *)_thread_start, stack_top()); + return _stack.convert( + [&] (Stack *stack) { + pt.start((void *)_thread_start, (void *)stack->top()); - try { - new (platform().core_mem_alloc()) - Core_trace_source(Core::Trace::sources(), *this, pt); - } - catch (...) { } + try { + new (platform().core_mem_alloc()) + Core_trace_source(Core::Trace::sources(), *this, pt); + } + catch (...) { } + + return Start_result::OK; + }, + [&] (Stack_error) { return Start_result::DENIED; }); } - catch (...) { return Start_result::DENIED; } + catch (...) { } - return Start_result::OK; + return Start_result::DENIED; } diff --git a/repos/base-foc/src/lib/base/thread_start.cc b/repos/base-foc/src/lib/base/thread_start.cc index 9ecfe9cef1..f755e6703e 100644 --- a/repos/base-foc/src/lib/base/thread_start.cc +++ b/repos/base-foc/src/lib/base/thread_start.cc @@ -68,7 +68,7 @@ void Thread::_init_native_thread(Stack &stack, size_t weight, Type type) if (type == NORMAL) { /* create thread at core */ - _thread_cap = _cpu_session->create_thread(pd_session_cap(), name(), + _thread_cap = _cpu_session->create_thread(pd_session_cap(), name, _affinity, Weight(weight)); return; } @@ -113,9 +113,13 @@ Thread::Start_result Thread::start() /* 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; + return _stack.convert( + [&] (Stack *stack) { + cpu_thread.start((addr_t)_thread_start, stack->top()); + return Start_result::OK; + }, + [&] (Stack_error) { return Start_result::DENIED; }); }, [&] (Cpu_session::Create_thread_error) { return Start_result::DENIED; } ); diff --git a/repos/base-hw/src/bootstrap/thread.cc b/repos/base-hw/src/bootstrap/thread.cc index b20ede0f37..bb113acbf5 100644 --- a/repos/base-hw/src/bootstrap/thread.cc +++ b/repos/base-hw/src/bootstrap/thread.cc @@ -20,6 +20,3 @@ Genode::Thread * Genode::Thread::myself() assert(false); return nullptr; } - - -Genode::Thread::Name Genode::Thread::name() const { return "bootstrap"; } diff --git a/repos/base-hw/src/core/thread_start.cc b/repos/base-hw/src/core/thread_start.cc index a736fc2656..f548763cde 100644 --- a/repos/base-hw/src/core/thread_start.cc +++ b/repos/base-hw/src/core/thread_start.cc @@ -51,7 +51,7 @@ namespace { if (nt.platform_thread) execution_time = nt.platform_thread->execution_time(); }); - return { Session_label("core"), thread.name(), + return { Session_label("core"), thread.name, execution_time, thread.affinity() }; } @@ -69,25 +69,24 @@ namespace { Thread::Start_result Thread::start() { - if (!_stack) - return Start_result::DENIED; + return _stack.convert([&] (Stack * const stack) { - Stack &stack = *_stack; + Native_thread &nt = stack->native_thread(); - Native_thread &nt = stack.native_thread(); + /* start thread with stack pointer at the top of stack */ + nt.platform_thread->start((void *)&_thread_start, (void *)stack->top()); - /* start thread with stack pointer at the top of stack */ - nt.platform_thread->start((void *)&_thread_start, (void *)stack.top()); + if (_thread_cap.failed()) + return Start_result::DENIED;; - if (_thread_cap.failed()) - return Start_result::DENIED;; + /* create trace sources for core threads */ + try { + new (platform().core_mem_alloc()) Trace_source(Core::Trace::sources(), *this); + } catch (...) { } - /* create trace sources for core threads */ - try { - new (platform().core_mem_alloc()) Trace_source(Core::Trace::sources(), *this); - } catch (...) { } + return Start_result::OK; - return Start_result::OK; + }, [&] (Stack_error) { return Start_result::DENIED; }); } @@ -100,8 +99,10 @@ void Thread::_deinit_native_thread(Stack &stack) void Thread::_init_native_thread(Stack &stack, size_t, Type type) { if (type == NORMAL) { - stack.native_thread().platform_thread = new (platform().core_mem_alloc()) - Platform_thread(_stack->name(), stack.utcb()); + _stack.with_result([&] (Stack * const stack) { + stack->native_thread().platform_thread = new (platform().core_mem_alloc()) + Platform_thread(name, stack->utcb()); + }, [&] (Stack_error) { }); return; } diff --git a/repos/base-hw/src/lib/base/thread_bootstrap.cc b/repos/base-hw/src/lib/base/thread_bootstrap.cc index fef7068771..39a50eb199 100644 --- a/repos/base-hw/src/lib/base/thread_bootstrap.cc +++ b/repos/base-hw/src/lib/base/thread_bootstrap.cc @@ -66,10 +66,12 @@ void Genode::prepare_init_main_thread() __attribute__((optimize("-fno-delete-null-pointer-checks"))) Native_utcb *Thread::utcb() { - if (this) - return &_stack->utcb(); + if (!this) + return utcb_main_thread(); - return utcb_main_thread(); + return _stack.convert( + [&] (Stack *stack) { return &stack->utcb(); }, + [&] (Stack_error) { return utcb_main_thread(); }); } diff --git a/repos/base-hw/src/lib/base/thread_start.cc b/repos/base-hw/src/lib/base/thread_start.cc index e49049362d..c240a6bdf4 100644 --- a/repos/base-hw/src/lib/base/thread_start.cc +++ b/repos/base-hw/src/lib/base/thread_start.cc @@ -60,7 +60,7 @@ void Thread::_init_native_thread(Stack &stack, 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; } @@ -107,42 +107,40 @@ void Thread::_deinit_native_thread(Stack &stack) Thread::Start_result Thread::start() { - if (!_stack) - return Start_result::DENIED; + return _stack.convert([&] (Stack * const stack) { - Stack &stack = *_stack; + while (avail_capability_slab() < 5) + upgrade_capability_slab(); - while (avail_capability_slab() < 5) - upgrade_capability_slab(); + return _thread_cap.convert( + [&] (Thread_capability cap) { + Cpu_thread_client cpu_thread(cap); - 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()); - return env_stack_area_region_map->attach(cpu_thread.utcb(), { - .size = size, - .offset = { }, - .use_at = true, - .at = Stack_allocator::addr_to_base(&stack) - + stack_virtual_size() - size - stack_area_virtual_base(), - .executable = { }, - .writeable = true - }).convert( - [&] (Region_map::Range) { - /* start execution with initial IP and aligned SP */ - cpu_thread.start((addr_t)_thread_start, stack.top()); - return Start_result::OK; - }, - [&] (Region_map::Attach_error) { - error("failed to attach userland stack"); - return Start_result::DENIED; - } - ); - }, - [&] (Cpu_session::Create_thread_error) { return Start_result::DENIED; } - ); + /* attach UTCB at top of stack */ + size_t const size = sizeof(stack->utcb()); + return env_stack_area_region_map->attach(cpu_thread.utcb(), { + .size = size, + .offset = { }, + .use_at = true, + .at = Stack_allocator::addr_to_base(stack) + + stack_virtual_size() - size - stack_area_virtual_base(), + .executable = { }, + .writeable = true + }).convert( + [&] (Region_map::Range) { + /* start execution with initial IP and aligned SP */ + cpu_thread.start((addr_t)_thread_start, stack->top()); + return Start_result::OK; + }, + [&] (Region_map::Attach_error) { + error("failed to attach userland stack"); + return Start_result::DENIED; + } + ); + }, + [&] (Cpu_session::Create_thread_error) { return Start_result::DENIED; } + ); + }, [&] (Stack_error) { return Start_result::DENIED; }); } diff --git a/repos/base-linux/src/core/thread_linux.cc b/repos/base-linux/src/core/thread_linux.cc index 46f326df54..849e8c509b 100644 --- a/repos/base-linux/src/core/thread_linux.cc +++ b/repos/base-linux/src/core/thread_linux.cc @@ -30,13 +30,20 @@ static void empty_signal_handler(int) { } void Thread::_thread_start() { - Thread * const thread_ptr = Thread::myself(); + Thread &thread = *Thread::myself(); - /* use primary stack as alternate stack for fatal signals (exceptions) */ - void *stack_base = (void *)thread_ptr->_stack->base(); - size_t stack_size = thread_ptr->_stack->top() - thread_ptr->_stack->base(); + thread._stack.with_result( + [&] (Stack *stack) { - lx_sigaltstack(stack_base, stack_size); + /* use primary stack as alternate stack for fatal signals (exceptions) */ + void *stack_base = (void *)stack->base(); + size_t stack_size = stack->top() - stack->base(); + + lx_sigaltstack(stack_base, stack_size); + }, + [&] (Stack_error) { + warning("attempt to start thread ", thread.name, " without stack"); } + ); /* * Set signal handler such that canceled system calls get not transparently @@ -52,8 +59,8 @@ void Thread::_thread_start() */ lx_sigsetmask(LX_SIGCHLD, false); - Thread::myself()->entry(); - Thread::myself()->_join.wakeup(); + thread.entry(); + thread._join.wakeup(); sleep_forever(); } @@ -66,11 +73,12 @@ void Thread::_deinit_native_thread(Stack &) { } Thread::Start_result Thread::start() { - return with_native_thread( - [&] (Native_thread &nt) { - nt.tid = lx_create_thread(Thread::_thread_start, stack_top()); + return _stack.convert( + [&] (Stack *stack) { + Native_thread &nt = stack->native_thread(); + nt.tid = lx_create_thread(Thread::_thread_start, (void *)stack->top()); nt.pid = lx_getpid(); return Start_result::OK; }, - [&] { return Start_result::DENIED; }); + [&] (Stack_error) { return Start_result::DENIED; }); } diff --git a/repos/base-linux/src/lib/base/thread_linux.cc b/repos/base-linux/src/lib/base/thread_linux.cc index a5cb046fc4..3905c514f5 100644 --- a/repos/base-linux/src/lib/base/thread_linux.cc +++ b/repos/base-linux/src/lib/base/thread_linux.cc @@ -65,16 +65,22 @@ static void thread_exit_signal_handler(int) { lx_exit(0); } void Thread::_thread_start() { - Thread * const thread = Thread::myself(); + Thread &thread = *Thread::myself(); - /* use primary stack as alternate stack for fatal signals (exceptions) */ - void *stack_base = (void *)thread->_stack->base(); - size_t stack_size = thread->_stack->top() - thread->_stack->base(); + thread._stack.with_result( + [&] (Stack *stack) { + /* use primary stack as alternate stack for fatal signals (exceptions) */ + void *stack_base = (void *)stack->base(); + size_t stack_size = stack->top() - stack->base(); - lx_sigaltstack(stack_base, stack_size); - if (stack_size < 0x1000) - raw("small stack of ", stack_size, " bytes for \"", thread->name(), - "\" may break Linux signal handling"); + lx_sigaltstack(stack_base, stack_size); + if (stack_size < 0x1000) + raw("small stack of ", stack_size, " bytes for \"", thread.name, + "\" may break Linux signal handling"); + }, + [&] (Stack_error) { + warning("attempt to start thread ", thread.name, " without stack"); } + ); /* * Set signal handler such that canceled system calls get not @@ -83,18 +89,18 @@ void Thread::_thread_start() lx_sigaction(LX_SIGUSR1, empty_signal_handler, false); /* inform core about the new thread and process ID of the new thread */ - thread->with_native_thread([&] (Native_thread &nt) { - Linux_native_cpu_client native_cpu(thread->_cpu_session->native_cpu()); - native_cpu.thread_id(thread->cap(), nt.pid, nt.tid); + thread.with_native_thread([&] (Native_thread &nt) { + Linux_native_cpu_client native_cpu(thread._cpu_session->native_cpu()); + native_cpu.thread_id(thread.cap(), nt.pid, nt.tid); }); /* wakeup 'start' function */ startup_lock().wakeup(); - thread->entry(); + thread.entry(); /* unblock caller of 'join()' */ - thread->_join.wakeup(); + thread._join.wakeup(); sleep_forever(); } @@ -180,15 +186,19 @@ Thread::Start_result Thread::start() threadlib_initialized = true; } - with_native_thread([&] (Native_thread &nt) { - nt.tid = lx_create_thread(Thread::_thread_start, stack_top()); - nt.pid = lx_getpid(); - }); + return _stack.convert( + [&] (Stack *stack) { + Native_thread &nt = stack->native_thread(); - /* wait until the 'thread_start' function got entered */ - startup_lock().block(); + nt.tid = lx_create_thread(Thread::_thread_start, (void *)stack->top()); + nt.pid = lx_getpid(); - return Start_result::OK; + /* wait until the 'thread_start' function got entered */ + startup_lock().block(); + + return Start_result::OK; + }, + [&] (Stack_error) { return Start_result::DENIED; }); } 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 1d7501b501..e71b4a4a78 100644 --- a/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc +++ b/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc @@ -515,7 +515,8 @@ void Thread::join() Thread::Thread(size_t weight, const char *name, size_t /* stack size */, Type, Cpu_session * cpu_sess, Affinity::Location) -: _cpu_session(cpu_sess), _affinity() +: + name(name), _cpu_session(cpu_sess), _affinity() { Native_thread::Meta_data *meta_data = new (global_alloc()) Thread_meta_data_created(this); @@ -526,7 +527,7 @@ Thread::Thread(size_t weight, const char *name, size_t /* stack size */, if (ret) { error("pthread_create failed (returned ", ret, ", errno=", errno, ")"); destroy(global_alloc(), meta_data); - throw Out_of_stack_space(); + return; } with_native_thread([&] (Native_thread &nt) { diff --git a/repos/base-nova/src/core/ipc_pager.cc b/repos/base-nova/src/core/ipc_pager.cc index 92f1419494..41a440378c 100644 --- a/repos/base-nova/src/core/ipc_pager.cc +++ b/repos/base-nova/src/core/ipc_pager.cc @@ -77,5 +77,5 @@ void Ipc_pager::reply_and_wait_for_fault(addr_t sm) */ utcb.set_msg_word((_normal_ipc && _syscall_res != Nova::NOVA_OK) ? 1 : 0); - Nova::reply(myself.stack_top(), sm); + Nova::reply((void *)Thread::mystack().top, sm); } diff --git a/repos/base-nova/src/core/pager.cc b/repos/base-nova/src/core/pager.cc index c7c410c525..5b8a1b0ddc 100644 --- a/repos/base-nova/src/core/pager.cc +++ b/repos/base-nova/src/core/pager.cc @@ -39,6 +39,10 @@ using namespace Nova; static Rpc_entrypoint *_core_ep_ptr; + +static inline void *my_stack_top() { return (void *)Thread::mystack().top; } + + void Core::init_page_fault_handling(Rpc_entrypoint &ep) { _core_ep_ptr = &ep; } @@ -244,7 +248,7 @@ void Pager_object::exception(uint8_t const exit_id) utcb.set_msg_word(0); utcb.mtd = mtd; - reply(myself.stack_top()); + reply(my_stack_top()); } @@ -308,7 +312,7 @@ void Pager_object::_recall_handler(Pager_object &obj) utcb.set_msg_word(0); utcb.mtd = 0; - reply(myself.stack_top()); + reply(my_stack_top()); } if (obj._state.modified) { @@ -343,7 +347,7 @@ void Pager_object::_recall_handler(Pager_object &obj) obj._state_lock.release(); utcb.set_msg_word(0); - reply(myself.stack_top(), sm); + reply(my_stack_top(), sm); } @@ -365,7 +369,7 @@ void Pager_object::_startup_handler(Pager_object &obj) utcb.set_msg_word(0); - reply(myself.stack_top()); + reply(my_stack_top()); } @@ -378,7 +382,7 @@ void Pager_object::_invoke_handler(Pager_object &obj) if (utcb.msg_words() != 1) { utcb.mtd = 0; utcb.set_msg_word(0); - reply(myself.stack_top()); + reply(my_stack_top()); } addr_t const event = utcb.msg()[0]; @@ -413,7 +417,7 @@ void Pager_object::_invoke_handler(Pager_object &obj) utcb.mtd = 0; utcb.set_msg_word(0); - reply(myself.stack_top()); + reply(my_stack_top()); } utcb.mtd = 0; @@ -449,7 +453,7 @@ void Pager_object::_invoke_handler(Pager_object &obj) bool res = Nova::create_sm(obj.exc_pt_sel_client() + PT_SEL_STARTUP, platform_specific().core_pd_sel(), 0); if (res != Nova::NOVA_OK) - reply(myself.stack_top()); + reply(my_stack_top()); obj._state.mark_signal_sm(); } @@ -459,7 +463,7 @@ void Pager_object::_invoke_handler(Pager_object &obj) (void)res; } - reply(myself.stack_top()); + reply(my_stack_top()); } @@ -879,7 +883,7 @@ void Pager_object::_oom_handler(addr_t pager_dst, addr_t pager_src, error("unknown OOM case - stop core pager thread"); myself.with_native_thread([&] (Native_thread &nt) { utcb.set_msg_word(0); - reply(myself.stack_top(), nt.exc_pt_sel + Nova::SM_SEL_EC); + reply(my_stack_top(), nt.exc_pt_sel + Nova::SM_SEL_EC); }); } @@ -887,7 +891,7 @@ void Pager_object::_oom_handler(addr_t pager_dst, addr_t pager_src, if (policy == STOP) { error("PD has insufficient kernel memory left - stop thread"); utcb.set_msg_word(0); - reply(myself.stack_top(), obj_dst.sel_sm_block_pause()); + reply(my_stack_top(), obj_dst.sel_sm_block_pause()); } char const * src_pd = "core"; @@ -901,7 +905,7 @@ void Pager_object::_oom_handler(addr_t pager_dst, addr_t pager_src, error("Unknown PD has insufficient kernel memory left - stop thread"); myself.with_native_thread([&] (Native_thread &nt) { utcb.set_msg_word(0); - reply(myself.stack_top(), nt.exc_pt_sel + Nova::SM_SEL_EC); + reply(my_stack_top(), nt.exc_pt_sel + Nova::SM_SEL_EC); }); break; @@ -933,7 +937,7 @@ void Pager_object::_oom_handler(addr_t pager_dst, addr_t pager_src, uint8_t res = obj_dst.handle_oom(transfer_from, src_pd, src_thread, policy); if (res == Nova::NOVA_OK) /* handling succeeded - continue with original IPC */ - reply(myself.stack_top()); + reply(my_stack_top()); /* transfer nothing */ utcb.set_msg_word(0); @@ -945,7 +949,7 @@ void Pager_object::_oom_handler(addr_t pager_dst, addr_t pager_src, /* else: caller will get blocked until RCU period is over */ /* block caller in semaphore */ - reply(myself.stack_top(), obj_dst.sel_sm_block_oom()); + reply(my_stack_top(), obj_dst.sel_sm_block_oom()); } diff --git a/repos/base-nova/src/core/thread_start.cc b/repos/base-nova/src/core/thread_start.cc index 9039d18c0a..a67c64735c 100644 --- a/repos/base-nova/src/core/thread_start.cc +++ b/repos/base-nova/src/core/thread_start.cc @@ -90,25 +90,34 @@ Thread::Start_result Thread::start() */ using namespace Nova; - addr_t sp = _stack->top(); - Utcb &utcb = *reinterpret_cast(&_stack->utcb()); + bool const ec_created = _stack.convert([&] (Stack *stack) { - /* create local EC */ - enum { LOCAL_THREAD = false }; - unsigned const kernel_cpu_id = platform_specific().kernel_cpu_id(_affinity); + addr_t sp = stack->top(); + Utcb &utcb = reinterpret_cast(stack->utcb()); - uint8_t res { }; - with_native_thread([&] (Native_thread &nt) { - res = create_ec(nt.ec_sel, platform_specific().core_pd_sel(), kernel_cpu_id, - (mword_t)&utcb, sp, nt.exc_pt_sel, LOCAL_THREAD); }); - if (res != NOVA_OK) { - error("Thread::start: create_ec returned ", res); + /* create local EC */ + enum { LOCAL_THREAD = false }; + unsigned const kernel_cpu_id = platform_specific().kernel_cpu_id(_affinity); + + Native_thread &nt = stack->native_thread(); + + uint8_t res = create_ec(nt.ec_sel, platform_specific().core_pd_sel(), + kernel_cpu_id, (mword_t)&utcb, sp, nt.exc_pt_sel, + LOCAL_THREAD); + if (res != NOVA_OK) { + error("Thread::start: create_ec returned ", res); + return false; + } + + /* default: we don't accept any mappings or translations */ + utcb.crd_rcv = Obj_crd(); + utcb.crd_xlt = Obj_crd(); + return true; + + }, [&] (Stack_error) { return false; }); + + if (!ec_created) return Start_result::DENIED; - } - - /* default: we don't accept any mappings or translations */ - utcb.crd_rcv = Obj_crd(); - utcb.crd_xlt = Obj_crd(); for (unsigned i = 0; i < NUM_INITIAL_PT; i++) { if (i == SM_SEL_EC) @@ -148,7 +157,7 @@ Thread::Start_result Thread::start() warning("ec_time for core thread failed res=", res); }); - return { Session_label("core"), thread.name(), + return { Session_label("core"), thread.name, Trace::Execution_time(ec_time, 0), thread._affinity }; } diff --git a/repos/base-nova/src/lib/base/rpc_entrypoint.cc b/repos/base-nova/src/lib/base/rpc_entrypoint.cc index d8b91132b0..9d372fc872 100644 --- a/repos/base-nova/src/lib/base/rpc_entrypoint.cc +++ b/repos/base-nova/src/lib/base/rpc_entrypoint.cc @@ -115,7 +115,7 @@ static void reply(Nova::Utcb &utcb, Rpc_exception_code exc, Msgbuf_base &snd_msg { copy_msgbuf_to_utcb(utcb, snd_msg, exc.value); - Nova::reply(Thread::myself()->stack_top()); + Nova::reply((void *)Thread::mystack().top); } @@ -226,13 +226,16 @@ Rpc_entrypoint::Rpc_entrypoint(Pd_session *pd_session, size_t stack_size, return; } - with_native_thread([&] (Native_thread &nt) { - Receive_window &rcv_window = nt.server_rcv_window; + _stack.with_result( + [&] (Stack *stack) { + Receive_window &rcv_window = stack->native_thread().server_rcv_window; - /* prepare portal receive window of new thread */ - if (!rcv_window.prepare_rcv_window(*(Nova::Utcb *)&_stack->utcb())) - error("failed to prepare receive window for RPC entrypoint"); - }); + /* prepare portal receive window of new thread */ + if (!rcv_window.prepare_rcv_window((Nova::Utcb &)stack->utcb())) + error("failed to prepare receive window for RPC entrypoint"); + }, + [&] (Stack_error) { } + ); } diff --git a/repos/base-nova/src/lib/base/stack.cc b/repos/base-nova/src/lib/base/stack.cc index 313974d42a..e550c474ea 100644 --- a/repos/base-nova/src/lib/base/stack.cc +++ b/repos/base-nova/src/lib/base/stack.cc @@ -116,5 +116,7 @@ Native_utcb *Thread::utcb() */ if (this == 0) return main_thread_utcb(); - return &_stack->utcb(); + return _stack.convert( + [&] (Stack *stack) { return &stack->utcb(); }, + [&] (Stack_error) { return main_thread_utcb(); }); } diff --git a/repos/base-nova/src/lib/base/thread_start.cc b/repos/base-nova/src/lib/base/thread_start.cc index bf3dac9102..d83b320e95 100644 --- a/repos/base-nova/src/lib/base/thread_start.cc +++ b/repos/base-nova/src/lib/base/thread_start.cc @@ -60,7 +60,7 @@ void Thread::_thread_start() Thread::myself()->entry(); } catch (...) { try { - error("Thread '", Thread::myself()->name(), "' " + error("Thread '", Thread::myself()->name, "' " "died because of an uncaught exception"); } catch (...) { /* die in a noisy way */ @@ -123,7 +123,7 @@ void Thread::_init_native_thread(Stack &stack, size_t weight, Type type) _init_cpu_session_and_trace_control(); /* create thread at core */ - _cpu_session->create_thread(pd_session_cap(), name(), + _cpu_session->create_thread(pd_session_cap(), name, _affinity, Weight(weight)).with_result( [&] (Thread_capability cap) { _thread_cap = cap; }, [&] (Cpu_session::Create_thread_error) { @@ -149,7 +149,9 @@ void Thread::_deinit_native_thread(Stack &stack) Thread::Start_result Thread::start() { - return with_native_thread([&] (Native_thread &nt) { + return _stack.convert([&] (Stack *stack) { + + Native_thread &nt = stack->native_thread(); if (nt.ec_sel < Native_thread::INVALID_INDEX - 1) { error("Thread::start failed due to invalid exception portal selector"); @@ -188,7 +190,7 @@ Thread::Start_result Thread::start() addr_t thread_ip = global ? reinterpret_cast(_thread_start) : nt.initial_ip; Cpu_thread_client cpu_thread(cap()); - cpu_thread.start(thread_ip, _stack->top()); + cpu_thread.start(thread_ip, stack->top()); /* request native EC thread cap */ nt.ec_sel = nt.exc_pt_sel + Nova::EC_SEL_THREAD; @@ -211,7 +213,7 @@ Thread::Start_result Thread::start() return Start_result::OK; - }, [&] { return Start_result::DENIED; }); + }, [&] (Stack_error) { return Start_result::DENIED; }); } diff --git a/repos/base-nova/src/lib/base/vm.cc b/repos/base-nova/src/lib/base/vm.cc index f5c3e0f038..4b52c62feb 100644 --- a/repos/base-nova/src/lib/base/vm.cc +++ b/repos/base-nova/src/lib/base/vm.cc @@ -660,7 +660,7 @@ static void nova_reply(Thread &myself, Nova::Utcb &utcb, auto &&... args) /* reset receive window to values expected by RPC server code */ nt.server_rcv_window.prepare_rcv_window(utcb); - Nova::reply(myself.stack_top(), args...); + Nova::reply((void *)Thread::mystack().top, args...); }); } diff --git a/repos/base-nova/src/test/nova/main.cc b/repos/base-nova/src/test/nova/main.cc index 09a71cde80..1484a1e6aa 100644 --- a/repos/base-nova/src/test/nova/main.cc +++ b/repos/base-nova/src/test/nova/main.cc @@ -285,7 +285,7 @@ static void portal_entry() SOLELY_MAP, NO_DMA, EVILLY_DONT_WRITE_COMBINE); (void)ok; - Nova::reply(myself.stack_top()); + Nova::reply((void *)Thread::mystack().top); } void test_pat(Genode::Env &env) @@ -478,7 +478,7 @@ class Pager : private Genode::Thread { bool res = utcb->append_item(crd_map, 0); (void)res; - Nova::reply(myself->stack_top()); + Nova::reply((void *)Thread::mystack().top); } public: diff --git a/repos/base-okl4/src/core/thread_start.cc b/repos/base-okl4/src/core/thread_start.cc index 57df1a6d5c..d92b3cb7f4 100644 --- a/repos/base-okl4/src/core/thread_start.cc +++ b/repos/base-okl4/src/core/thread_start.cc @@ -35,14 +35,19 @@ void Thread::_thread_start() Thread::Start_result Thread::start() { - with_native_thread([&] (Native_thread &nt) { + return _stack.convert([&] (Stack * const stack) { + + Native_thread &nt = stack->native_thread(); + nt.pt = new (Core::platform_specific().thread_slab()) Core::Platform_thread(Core::platform_specific().core_pd(), - _stack->name().string()); + name.string()); - nt.pt->start((void *)_thread_start, stack_top()); - }); - return Start_result::OK; + nt.pt->start((void *)_thread_start, (void *)stack->top()); + + return Start_result::OK; + + }, [&] (Stack_error) { return Start_result::DENIED; }); } diff --git a/repos/base-pistachio/src/core/thread_start.cc b/repos/base-pistachio/src/core/thread_start.cc index 283cd4ab79..eee8ee2866 100644 --- a/repos/base-pistachio/src/core/thread_start.cc +++ b/repos/base-pistachio/src/core/thread_start.cc @@ -36,18 +36,20 @@ void Thread::_thread_start() Thread::Start_result Thread::start() { - return with_native_thread( - [&] (Native_thread &nt) { - nt.pt = new (platform().core_mem_alloc()) - Platform_thread(platform_specific().core_pd(), _stack->name().string()); + return _stack.convert([&] (Stack * const stack) { - nt.pt->pager(platform_specific().core_pager()); - nt.l4id = nt.pt->native_thread_id(); + Native_thread &nt = stack->native_thread(); - nt.pt->start((void *)_thread_start, stack_top()); - return Start_result::OK; - }, - [&] { return Start_result::DENIED; }); + nt.pt = new (platform().core_mem_alloc()) + Platform_thread(platform_specific().core_pd(), stack->name().string()); + + nt.pt->pager(platform_specific().core_pager()); + nt.l4id = nt.pt->native_thread_id(); + + nt.pt->start((void *)_thread_start, (void *)stack->top()); + return Start_result::OK; + + }, [&] (Stack_error) { return Start_result::DENIED; }); } diff --git a/repos/base-sel4/src/core/thread_start.cc b/repos/base-sel4/src/core/thread_start.cc index 2b83f446c2..f8f8074c95 100644 --- a/repos/base-sel4/src/core/thread_start.cc +++ b/repos/base-sel4/src/core/thread_start.cc @@ -124,7 +124,7 @@ namespace { uint64_t const thread_time = buf[BENCHMARK_TCB_UTILISATION]; - return { Session_label("core"), _thread.name(), + return { Session_label("core"), _thread.name, Genode::Trace::Execution_time(thread_time, 0), _thread.affinity() }; } @@ -141,30 +141,28 @@ namespace { Thread::Start_result Thread::start() { - if (!_stack) - return Start_result::DENIED; + return _stack.convert([&] (Stack *stack) { - Stack &stack = *_stack; + /* write ipcbuffer address to utcb*/ + utcb()->ipcbuffer(Native_utcb::Virt { addr_t(utcb()) }); - /* write ipcbuffer address to utcb*/ - utcb()->ipcbuffer(Native_utcb::Virt { addr_t(utcb()) }); + start_sel4_thread(Cap_sel(stack->native_thread().attr.tcb_sel), + (addr_t)&_thread_start, stack->top(), + _affinity.xpos(), addr_t(utcb())); + try { + new (platform().core_mem_alloc()) + Core_trace_source(Core::Trace::sources(), *this); + } catch (...) { } - start_sel4_thread(Cap_sel(stack.native_thread().attr.tcb_sel), - (addr_t)&_thread_start, stack.top(), - _affinity.xpos(), addr_t(utcb())); - try { - new (platform().core_mem_alloc()) - Core_trace_source(Core::Trace::sources(), *this); - } catch (...) { } + return Start_result::OK; - return Start_result::OK; + }, [&] (Stack_error) { return Start_result::DENIED; }); } Native_utcb *Thread::utcb() { - if (!_stack) - return nullptr; - - return &_stack->utcb(); + return _stack.convert( + [] (Stack *stack) { return &stack->utcb(); }, + [] (Stack_error) { return nullptr; }); } diff --git a/repos/base-sel4/src/lib/base/thread_bootstrap.cc b/repos/base-sel4/src/lib/base/thread_bootstrap.cc index af3c9ccc82..dd0047163c 100644 --- a/repos/base-sel4/src/lib/base/thread_bootstrap.cc +++ b/repos/base-sel4/src/lib/base/thread_bootstrap.cc @@ -33,12 +33,17 @@ void Genode::prepare_init_main_thread() { } void Genode::Thread::_thread_bootstrap() { - with_native_thread([&] (Native_thread &nt) { - if (nt.attr.ep_sel == 0) { - nt.attr.ep_sel = (unsigned)_stack->utcb().ep_sel(); - nt.attr.lock_sel = (unsigned)_stack->utcb().lock_sel(); - } - }); + _stack.with_result( + [&] (Stack *stack) { + Native_thread &nt = stack->native_thread(); + + if (nt.attr.ep_sel == 0) { + nt.attr.ep_sel = (unsigned)stack->utcb().ep_sel(); + nt.attr.lock_sel = (unsigned)stack->utcb().lock_sel(); + } + }, + [&] (Stack_error) { } + ); } diff --git a/repos/base-sel4/src/lib/base/x86/vm.cc b/repos/base-sel4/src/lib/base/x86/vm.cc index adbc24cd74..47efb866a2 100644 --- a/repos/base-sel4/src/lib/base/x86/vm.cc +++ b/repos/base-sel4/src/lib/base/x86/vm.cc @@ -124,6 +124,13 @@ struct Sel4_vcpu : Genode::Thread, Noncopyable seL4_VCPUContext _recent_gpr { }; + addr_t _with_utcb(auto const &fn) + { + return _stack.convert( + [&] (Stack *stack) { return fn(stack->utcb()); }, + [&] (Stack_error) { return 0UL; /* cannot happen */ }); + } + void entry() override { /* trigger that thread is up */ @@ -133,9 +140,12 @@ struct Sel4_vcpu : Genode::Thread, Noncopyable _wake_up.down(); /* get selector to read/write VMCS */ - addr_t const service = _stack->utcb().ep_sel(); + addr_t const service = _with_utcb([&] (Native_utcb &utcb) { + return utcb.ep_sel(); }); + /* get selector to call back a vCPU into VMM */ - _recall = _stack->utcb().lock_sel(); + _recall = _with_utcb([&] (Native_utcb &utcb) { + return utcb.lock_sel(); }); Vcpu_state &state = _state; state.discharge(); diff --git a/repos/base/include/base/rpc_server.h b/repos/base/include/base/rpc_server.h index 52c9203f00..bcffabda02 100644 --- a/repos/base/include/base/rpc_server.h +++ b/repos/base/include/base/rpc_server.h @@ -487,11 +487,11 @@ class Genode::Rpc_entrypoint : Thread, public Object_pool * Check whether given stack info matches stack of the entrypoint. * * \noapi - * */ bool myself(addr_t const ptr) const { - return addr_t(stack_base()) <= ptr && ptr <= addr_t(stack_top()); + Stack_info const info = mystack(); + return info.base <= ptr && ptr <= info.top; } }; diff --git a/repos/base/include/base/thread.h b/repos/base/include/base/thread.h index 8ee6395bec..9b4492f359 100644 --- a/repos/base/include/base/thread.h +++ b/repos/base/include/base/thread.h @@ -41,31 +41,34 @@ class Genode::Thread { public: - class Out_of_stack_space : public Exception { }; - class Stack_too_large : public Exception { }; - class Stack_alloc_failed : public Exception { }; - using Location = Affinity::Location; using Name = Cpu_session::Name; using Weight = Cpu_session::Weight; + enum class Stack_error { STACK_AREA_EXHAUSTED, STACK_TOO_LARGE }; + struct Stack_info { addr_t base; addr_t top; addr_t libc_tls_pointer_offset; }; + Name const name; + private: + using Alloc_stack_result = Attempt; + /** * Allocate and locally attach a new stack * * \param stack_size size of this threads stack * \param main_thread wether this is the main thread */ - Stack *_alloc_stack(size_t stack_size, char const *name, bool main_thread); + Alloc_stack_result _alloc_stack(size_t stack_size, Name const &name, + bool main_thread); /** * Detach and release stack of the thread */ - void _free_stack(Stack *stack); + void _free_stack(Stack &stack); /** * Platform-specific thread-startup code @@ -118,9 +121,9 @@ class Genode::Thread Trace::Control *_trace_control = nullptr; /** - * Pointer to primary stack + * Primary stack */ - Stack *_stack = nullptr; + Attempt _stack = Stack_error::STACK_AREA_EXHAUSTED; /** * Pointer to kernel-specific meta data @@ -188,10 +191,6 @@ class Genode::Thread * \param name thread name (for debugging) * \param stack_size stack size * - * \throw Stack_too_large - * \throw Stack_alloc_failed - * \throw Out_of_stack_space - * * The stack for the new thread will be allocated from the RAM session * of the component environment. A small portion of the stack size is * internally used by the framework for storing thread-specific @@ -218,10 +217,6 @@ class Genode::Thread * \param type enables selection of special construction * \param cpu_session capability to cpu session used for construction * - * \throw Stack_too_large - * \throw Stack_alloc_failed - * \throw Out_of_stack_space - * * \deprecated superseded by the 'Thread(Env &...' constructor */ Thread(size_t weight, const char *name, size_t stack_size, @@ -245,10 +240,6 @@ class Genode::Thread * needs to interact with the environment for attaching the thread's * stack, the trace-control dataspace, and the thread's trace buffer * and policy. - * - * \throw Stack_too_large - * \throw Stack_alloc_failed - * \throw Out_of_stack_space */ Thread(Env &env, Name const &name, size_t stack_size, Location location, Weight weight, Cpu_session &cpu); @@ -282,26 +273,11 @@ class Genode::Thread */ virtual Start_result start(); - /** - * Request name of thread - * - * \noapi - * \deprecated use the 'Name name() const' method instead - */ - void name(char *dst, size_t dst_len); - - /** - * Request name of thread - */ - Name name() const; + using Alloc_secondary_stack_result = Attempt; /** * Add an additional stack to the thread * - * \throw Stack_too_large - * \throw Stack_alloc_failed - * \throw Out_of_stack_space - * * The stack for the new thread will be allocated from the RAM * session of the component environment. A small portion of the * stack size is internally used by the framework for storing @@ -309,7 +285,8 @@ class Genode::Thread * * \return pointer to the new stack's top */ - void* alloc_secondary_stack(char const *name, size_t stack_size); + Alloc_secondary_stack_result alloc_secondary_stack(Name const &name, + size_t stack_size); /** * Remove a secondary stack from the thread @@ -351,20 +328,6 @@ class Genode::Thread with_native_thread(fn, [&] { }); } - /** - * Return top of primary stack - * - * \return pointer just after first stack element - */ - void *stack_top() const; - - /** - * Return base of primary stack - * - * \return pointer to last stack element - */ - void *stack_base() const; - /** * Return virtual size reserved for each stack within the stack area */ @@ -380,6 +343,13 @@ class Genode::Thread */ static size_t stack_area_virtual_size(); + using Info_result = Attempt; + + /** + * Return information about the thread's stack + */ + Info_result info() const; + /** * Return 'Thread' object corresponding to the calling thread * @@ -392,15 +362,14 @@ class Genode::Thread */ static Stack_info mystack(); + using Stack_size_result = Attempt; + /** * Ensure that the stack has a given size at the minimum * * \param size minimum stack size - * - * \throw Stack_too_large - * \throw Stack_alloc_failed */ - void stack_size(size_t const size); + Stack_size_result stack_size(size_t const size); /** * Return user-level thread control block diff --git a/repos/base/lib/symbols/ld b/repos/base/lib/symbols/ld index 2d07886846..0666536a1e 100644 --- a/repos/base/lib/symbols/ld +++ b/repos/base/lib/symbols/ld @@ -262,11 +262,10 @@ _ZN6Genode6SignalC2ERKS0_ T _ZN6Genode6SignalD1Ev T _ZN6Genode6SignalD2Ev T _ZN6Genode6SignalaSERKS0_ T -_ZN6Genode6Thread10stack_sizeEm T _ZN6Genode6Thread13native_threadEv T _ZN6Genode6Thread18stack_virtual_sizeEv T _ZN6Genode6Thread20free_secondary_stackEPv T -_ZN6Genode6Thread21alloc_secondary_stackEPKcm T +_ZN6Genode6Thread21alloc_secondary_stackERKNS_6StringILm32EEEm T _ZN6Genode6Thread23stack_area_virtual_baseEv T _ZN6Genode6Thread23stack_area_virtual_sizeEv T _ZN6Genode6Thread4joinEv T @@ -326,6 +325,7 @@ _ZNK6Genode5Child15main_thread_capEv T _ZNK6Genode5Child18skipped_heartbeatsEv T _ZNK6Genode5Child21notify_resource_availEv T _ZNK6Genode6Thread10stack_baseEv T +_ZNK6Genode6Thread4infoEv T _ZNK6Genode6Thread4nameEv T _ZNK6Genode6Thread9stack_topEv T _ZNK6Genode8Duration17trunc_to_plain_msEv T diff --git a/repos/base/src/include/base/internal/stack.h b/repos/base/src/include/base/internal/stack.h index 0c5cd82ca9..1c65119db9 100644 --- a/repos/base/src/include/base/internal/stack.h +++ b/repos/base/src/include/base/internal/stack.h @@ -74,7 +74,9 @@ class Genode::Stack { public: - using Name = Cpu_session::Name; + using Name = Cpu_session::Name; + using Size_result = Thread::Stack_size_result; + using Error = Thread::Stack_error; private: @@ -170,11 +172,9 @@ class Genode::Stack * Ensure that the stack has a given minimum size * * \param size minimum stack size - * - * \throw Stack_too_large - * \throw Stack_alloc_failed + * \return actually available stack size */ - void size(size_t const size); + Size_result size(size_t const size); /** * Return kernel-specific thread meta data diff --git a/repos/base/src/include/base/internal/stack_allocator.h b/repos/base/src/include/base/internal/stack_allocator.h index ebc9db75bb..e42dbab2e0 100644 --- a/repos/base/src/include/base/internal/stack_allocator.h +++ b/repos/base/src/include/base/internal/stack_allocator.h @@ -64,7 +64,7 @@ class Genode::Stack_allocator /** * Release stack */ - void free(Stack *); + void free(Stack &); /** * Return 'Stack' object for a given base address diff --git a/repos/base/src/lib/base/entrypoint.cc b/repos/base/src/lib/base/entrypoint.cc index fae5c53aa9..35c5a0cdfc 100644 --- a/repos/base/src/lib/base/entrypoint.cc +++ b/repos/base/src/lib/base/entrypoint.cc @@ -152,7 +152,7 @@ bool Entrypoint::_wait_and_dispatch_one_io_signal(bool const dont_block) { if (!_rpc_ep->is_myself()) warning(__func__, " called from non-entrypoint thread \"", - Thread::myself()->name(), "\""); + Thread::myself()->name, "\""); for (;;) { diff --git a/repos/base/src/lib/base/stack_allocator.cc b/repos/base/src/lib/base/stack_allocator.cc index b521c68687..16f426c4e3 100644 --- a/repos/base/src/lib/base/stack_allocator.cc +++ b/repos/base/src/lib/base/stack_allocator.cc @@ -60,9 +60,9 @@ Stack_allocator::alloc(Thread *, bool main_thread) } -void Stack_allocator::free(Stack *stack) +void Stack_allocator::free(Stack &stack) { - addr_t const base = addr_to_base(stack); + addr_t const base = addr_to_base(&stack); Mutex::Guard guard(_threads_mutex); _alloc.free(base_to_idx(base)); diff --git a/repos/base/src/lib/base/thread.cc b/repos/base/src/lib/base/thread.cc index dd6916642e..eb64ee0c2e 100644 --- a/repos/base/src/lib/base/thread.cc +++ b/repos/base/src/lib/base/thread.cc @@ -30,11 +30,12 @@ static Region_map *local_rm_ptr; static Cpu_session *cpu_session_ptr; -void Stack::size(size_t const size) +Stack::Size_result Stack::size(size_t const size) { /* check if the stack needs to be enhanced */ size_t const stack_size = (addr_t)_stack - _base; - if (stack_size >= size) { return; } + if (stack_size >= size) + return stack_size; /* check if the stack enhancement fits the stack region */ enum { @@ -45,7 +46,7 @@ void Stack::size(size_t const size) addr_t const stack_slot_base = Stack_allocator::addr_to_base(this); size_t const ds_size = align_addr(size - stack_size, PAGE_SIZE_LOG2); if (_base - ds_size < stack_slot_base) - throw Thread::Stack_too_large(); + return Error::STACK_TOO_LARGE; /* allocate and attach backing store for the stack enhancement */ addr_t const ds_addr = _base - ds_size - stack_area_virtual_base(); @@ -53,41 +54,44 @@ void Stack::size(size_t const size) Ram_allocator &ram = *env_stack_area_ram_allocator; Region_map &rm = *env_stack_area_region_map; - ram.try_alloc(ds_size).with_result( + return ram.try_alloc(ds_size).convert( [&] (Ram_dataspace_capability ds_cap) { - rm.attach(ds_cap, Region_map::Attr { + return rm.attach(ds_cap, Region_map::Attr { .size = ds_size, .offset = 0, .use_at = true, .at = ds_addr, .executable = { }, .writeable = true, - }).with_result( - [&] (Region_map::Range r) { + }).convert ( + + [&] (Region_map::Range r) -> Size_result { if (r.start != ds_addr) - throw Thread::Stack_alloc_failed(); + return Error::STACK_AREA_EXHAUSTED; /* update stack information */ _base -= ds_size; + + return (addr_t)_stack - _base; }, [&] (Region_map::Attach_error) { - throw Thread::Stack_alloc_failed(); } + return Error::STACK_AREA_EXHAUSTED; } ); }, [&] (Ram_allocator::Alloc_error) { - throw Thread::Stack_alloc_failed(); } + return Error::STACK_AREA_EXHAUSTED; } ); } -Stack * -Thread::_alloc_stack(size_t stack_size, char const *name, bool main_thread) +Thread::Alloc_stack_result +Thread::_alloc_stack(size_t stack_size, Name const &name, bool main_thread) { /* allocate stack */ Stack *stack = Stack_allocator::stack_allocator().alloc(this, main_thread); if (!stack) - throw Out_of_stack_space(); + return Stack_error::STACK_AREA_EXHAUSTED; /* determine size of dataspace to allocate for the stack */ enum { PAGE_SIZE_LOG2 = 12 }; @@ -95,7 +99,7 @@ Thread::_alloc_stack(size_t stack_size, char const *name, bool main_thread) if (stack_size >= stack_virtual_size() - sizeof(Native_utcb) - (1UL << PAGE_SIZE_LOG2)) - throw Stack_too_large(); + return Stack_error::STACK_TOO_LARGE; /* * Calculate base address of the stack @@ -112,7 +116,7 @@ Thread::_alloc_stack(size_t stack_size, char const *name, bool main_thread) Ram_allocator &ram = *env_stack_area_ram_allocator; /* allocate and attach backing store for the stack */ - return ram.try_alloc(ds_size).convert( + return ram.try_alloc(ds_size).convert( [&] (Ram_dataspace_capability const ds_cap) { @@ -125,12 +129,12 @@ Thread::_alloc_stack(size_t stack_size, char const *name, bool main_thread) .at = attach_addr, .executable = { }, .writeable = true - }).convert( + }).convert( - [&] (Region_map::Range const range) -> Stack * { + [&] (Region_map::Range const range) -> Alloc_stack_result { if (range.start != attach_addr) { ram.free(ds_cap); - throw Stack_alloc_failed(); + return Stack_error::STACK_TOO_LARGE; } /* @@ -147,25 +151,25 @@ Thread::_alloc_stack(size_t stack_size, char const *name, bool main_thread) Abi::init_stack(stack->top()); return stack; }, - [&] (Region_map::Attach_error) -> Stack * { + [&] (Region_map::Attach_error) -> Alloc_stack_result { ram.free(ds_cap); - throw Stack_alloc_failed(); + return Stack_error::STACK_AREA_EXHAUSTED; } ); }, - [&] (Ram_allocator::Alloc_error) -> Stack * { - throw Stack_alloc_failed(); } + [&] (Ram_allocator::Alloc_error) -> Alloc_stack_result { + return Stack_error::STACK_AREA_EXHAUSTED; } ); } -void Thread::_free_stack(Stack *stack) +void Thread::_free_stack(Stack &stack) { - addr_t ds_addr = stack->base() - stack_area_virtual_base(); - Ram_dataspace_capability ds_cap = stack->ds_cap(); + addr_t ds_addr = stack.base() - stack_area_virtual_base(); + Ram_dataspace_capability ds_cap = stack.ds_cap(); /* call de-constructor explicitly before memory gets detached */ - stack->~Stack(); + stack.~Stack(); Genode::env_stack_area_region_map->detach(ds_addr); Genode::env_stack_area_ram_allocator->free(ds_cap); @@ -175,47 +179,55 @@ void Thread::_free_stack(Stack *stack) } -void Thread::name(char *dst, size_t dst_len) +static Thread::Stack_info stack_info(Stack &stack) { - copy_cstring(dst, name().string(), dst_len); + return { stack.base(), stack.top(), + stack_virtual_size() - stack.libc_tls_pointer_offset() }; } -Thread::Name Thread::name() const { return _stack->name(); } +Thread::Info_result Thread::info() const +{ + return _stack.convert( + [&] (Stack *stack) { return stack_info(*stack); }, + [&] (Stack_error e) { return e; }); +} void Thread::join() { _join.block(); } -void *Thread::alloc_secondary_stack(char const *name, size_t stack_size) +Thread::Alloc_secondary_stack_result +Thread::alloc_secondary_stack(Name const &name, size_t stack_size) { - Stack *stack = _alloc_stack(stack_size, name, false); - return (void *)stack->top(); + return _alloc_stack(stack_size, name, false).convert( + [&] (Stack *stack) { return (void *)stack->top(); }, + [&] (Stack_error e) { return e; }); } void Thread::free_secondary_stack(void* stack_addr) { addr_t base = Stack_allocator::addr_to_base(stack_addr); - _free_stack(Stack_allocator::base_to_stack(base)); + _free_stack(*Stack_allocator::base_to_stack(base)); } -void *Thread::stack_top() const { return (void *)_stack->top(); } - - -void *Thread::stack_base() const { return (void*)_stack->base(); } - - -void Thread::stack_size(size_t const size) { _stack->size(size); } +Thread::Stack_size_result Thread::stack_size(size_t const size) +{ + return _stack.convert( + [&] (Stack *stack) { + stack->size(size); + return stack->top() - stack->base(); + }, + [&] (Stack_error e) { return e; }); +} Thread::Stack_info Thread::mystack() { addr_t base = Stack_allocator::addr_to_base(&base); - Stack *stack = Stack_allocator::base_to_stack(base); - return { stack->base(), stack->top(), - stack_virtual_size() - stack->libc_tls_pointer_offset() }; + return stack_info(*Stack_allocator::base_to_stack(base)); } @@ -240,13 +252,18 @@ size_t Thread::stack_area_virtual_size() Thread::Thread(size_t weight, const char *name, size_t stack_size, Type type, Cpu_session *cpu_session, Affinity::Location affinity) : + name(name), _cpu_session(cpu_session), _affinity(affinity), _trace_control(nullptr), _stack(_alloc_stack(stack_size, name, type == MAIN)) { - _native_thread_ptr = &_stack->native_thread(); - _init_native_thread(*_stack, weight, type); + _stack.with_result( + [&] (Stack *stack) { + _native_thread_ptr = &stack->native_thread(); + _init_native_thread(*stack, weight, type); + }, + [&] (Stack_error) { /* error reflected by 'info()' */ }); } @@ -299,14 +316,16 @@ Thread::Thread(Env &env, Name const &name, size_t stack_size) Thread::~Thread() { if (Thread::myself() == this) { - error("thread '", _stack->name().string(), "' " - "tried to self de-struct - sleeping forever."); + error("thread '", name, "' tried to self de-struct - sleeping forever."); sleep_forever(); } - _deinit_native_thread(*_stack); - - _free_stack(_stack); + _stack.with_result( + [&] (Stack *stack) { + _deinit_native_thread(*stack); + _free_stack(*stack); + }, + [&] (Stack_error) { }); cxx_free_tls(this); diff --git a/repos/base/src/lib/base/thread_start.cc b/repos/base/src/lib/base/thread_start.cc index 5c1e6148ee..1a8b19ae49 100644 --- a/repos/base/src/lib/base/thread_start.cc +++ b/repos/base/src/lib/base/thread_start.cc @@ -44,7 +44,7 @@ void Thread::_thread_start() Thread::myself()->entry(); } catch (...) { try { - raw("Thread '", Thread::myself()->name().string(), + raw("Thread '", Thread::myself()->name, "' died because of an uncaught exception"); } catch (...) { /* die in a noisy way */ @@ -81,24 +81,23 @@ Thread::Start_result Thread::start() { _init_cpu_session_and_trace_control(); - if (!_stack) - return Start_result::DENIED; + return _stack.convert([&] (Stack *stack) { - Stack &stack = *_stack; + /* create thread at core */ + addr_t const utcb = (addr_t)&stack->utcb(); - /* 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); + return _thread_cap.convert( + [&] (Thread_capability cap) { - _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; }); - /* 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; }); + }, [&] (Stack_error) { return Start_result::DENIED; }); } diff --git a/repos/base/src/lib/base/utcb.cc b/repos/base/src/lib/base/utcb.cc index c017fd6b9d..a6c4b07da5 100644 --- a/repos/base/src/lib/base/utcb.cc +++ b/repos/base/src/lib/base/utcb.cc @@ -19,4 +19,8 @@ #include -Genode::Native_utcb *Genode::Thread::utcb() { return &_stack->utcb(); } +Genode::Native_utcb *Genode::Thread::utcb() +{ + return _stack.convert([&] (Stack *stack) { return &stack->utcb(); }, + [&] (Stack_error) { return nullptr; }); +} diff --git a/repos/base/src/lib/cxx/misc.cc b/repos/base/src/lib/cxx/misc.cc index d3ca7ee6be..db560eda2d 100644 --- a/repos/base/src/lib/cxx/misc.cc +++ b/repos/base/src/lib/cxx/misc.cc @@ -96,13 +96,7 @@ extern "C" __attribute__((weak)) void raise() extern "C" void abort(void) { - Genode::Thread const * const myself = Genode::Thread::myself(); - Genode::Thread::Name name = "unknown"; - - if (myself) - name = myself->name(); - - Genode::warning("abort called - thread: ", name.string()); + Genode::warning("abort called - thread: ", Genode::Thread::myself()->name); Genode::sleep_forever(); } diff --git a/repos/base/src/lib/startup/_main.cc b/repos/base/src/lib/startup/_main.cc index 60abdd11c7..3f61bcbaf5 100644 --- a/repos/base/src/lib/startup/_main.cc +++ b/repos/base/src/lib/startup/_main.cc @@ -81,7 +81,10 @@ extern "C" void init_main_thread() * The new stack pointer enables the caller to switch from its current * environment to the those that the thread object provides. */ - addr_t const sp = reinterpret_cast(main_thread.stack_top()); + addr_t const sp = main_thread.info().convert( + [&] (Thread::Stack_info info) { return info.top; }, + [&] (Thread::Stack_error) { return 0UL; }); + init_main_thread_result = sp; /* diff --git a/repos/base/src/test/thread/main.cc b/repos/base/src/test/thread/main.cc index b5b7bf60c9..78263ca55b 100644 --- a/repos/base/src/test/thread/main.cc +++ b/repos/base/src/test/thread/main.cc @@ -59,7 +59,12 @@ class Helper : Thread Helper(Env &env) : Thread(env, "helper", STACK_SIZE), _env(env) { } - void *stack() const { return _stack; } + void *stack() const + { + return info().convert( + [&] (Stack_info info) { return (void *)info.top; }, + [&] (Stack_error) { return nullptr; }); + } void entry() override { @@ -169,16 +174,16 @@ static void test_main_thread() addr_t const stack_slot_size = Thread::stack_area_virtual_size(); addr_t const stack_slot_top = stack_slot_base + stack_slot_size; - addr_t const stack_top = (addr_t)myself->stack_top(); - addr_t const stack_base = (addr_t)myself->stack_base(); + addr_t const stack_top = Thread::mystack().top; + addr_t const stack_base = Thread::mystack().base; if (stack_top <= stack_slot_base) { throw -2; } if (stack_top > stack_slot_top) { throw -3; } if (stack_base >= stack_slot_top) { throw -4; } if (stack_base < stack_slot_base) { throw -5; } - log("thread stack top ", myself->stack_top()); - log("thread stack bottom ", myself->stack_base()); + log("thread stack top ", (void *)stack_top); + log("thread stack bottom ", (void *)stack_base); /* check wether my stack pointer is inside my stack */ unsigned dummy = 0; @@ -205,8 +210,7 @@ struct Cpu_helper : Thread void entry() override { - log(Thread::name().string(), " : _cpu_session=", _cpu_session, - " env.cpu()=", &_env.cpu()); + log(Thread::name, " : _cpu_session=", _cpu_session, " env.cpu()=", &_env.cpu()); } }; @@ -317,14 +321,17 @@ static void test_create_as_many_threads(Env &env) for (; i < max; i++) { try { threads[i] = new (heap) Cpu_helper(env, Thread::Name(i + 1), env.cpu()); + + if (threads[i]->info() == Thread::Stack_error::STACK_AREA_EXHAUSTED) { + out_of_stack_space = true; + break; + } + 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; @@ -371,7 +378,7 @@ struct Lock_helper : Thread void entry() override { - log(" thread '", name(), "' started"); + log(" thread '", name, "' started"); if (unlock) lock.wakeup(); @@ -379,12 +386,12 @@ struct Lock_helper : Thread lock.block(); if (!lock_is_free) { - log(" thread '", name(), "' got lock but somebody else is within" + log(" thread '", name, "' got lock but somebody else is within" " critical section !?"); throw -22; } - log(" thread '", name(), "' done"); + log(" thread '", name, "' done"); lock.wakeup(); } @@ -413,7 +420,7 @@ static void test_locks(Genode::Env &env) lock.block(); - log(" thread '", Thread::myself()->name(), "' - I'm the lock holder - " + log(" thread '", Thread::myself()->name, "' - I'm the lock holder - " "take lock again"); /* we are within the critical section - lock is not free */ @@ -467,7 +474,7 @@ struct Cxa_helper : Thread void entry() override { - log(" thread '", name(), "' started"); + log(" thread '", name, "' started"); if (sync) sync_startup.wakeup(); @@ -482,20 +489,20 @@ struct Cxa_helper : Thread }; if (test == 1) - static Contention contention (name(), in_cxa, sync_startup); + static Contention contention (name, in_cxa, sync_startup); else if (test == 2) - static Contention contention (name(), in_cxa, sync_startup); + static Contention contention (name, in_cxa, sync_startup); else if (test == 3) - static Contention contention (name(), in_cxa, sync_startup); + static Contention contention (name, in_cxa, sync_startup); else if (test == 4) - static Contention contention (name(), in_cxa, sync_startup); + static Contention contention (name, in_cxa, sync_startup); else throw -25; - log(" thread '", name(), "' done"); + log(" thread '", name, "' done"); } }; diff --git a/repos/dde_bsd/src/lib/audio/scheduler.cc b/repos/dde_bsd/src/lib/audio/scheduler.cc index e23e9f1283..8c2448c031 100644 --- a/repos/dde_bsd/src/lib/audio/scheduler.cc +++ b/repos/dde_bsd/src/lib/audio/scheduler.cc @@ -59,7 +59,12 @@ bool Bsd::Task::run() _state = STATE_RUNNING; Genode::Thread *th = Genode::Thread::myself(); - _stack = th->alloc_secondary_stack(_name, _stack_size); + _stack = th->alloc_secondary_stack(_name, _stack_size).convert( + [&] (void *sp) { return sp; }, + [&] (Genode::Thread::Stack_error) { + Genode::error("failed to allocate secondary stack"); + return nullptr; + }); /* switch stack and call '_func(_arg)' */ platform_execute(_stack, (void *)_func, _arg); diff --git a/repos/dde_linux/src/lib/lx_kit/scheduler.cc b/repos/dde_linux/src/lib/lx_kit/scheduler.cc index 1add5b733a..1170a1c8e3 100644 --- a/repos/dde_linux/src/lib/lx_kit/scheduler.cc +++ b/repos/dde_linux/src/lib/lx_kit/scheduler.cc @@ -107,7 +107,7 @@ void Scheduler::execute() auto const thread = Genode::Thread::myself(); if (!_ep.rpc_ep().myself(addr_t(&thread))) { Genode::error("Lx_kit::Scheduler called by invalid thread/stack ", - thread->name(), " ", + thread->name, " ", Genode::Hex(thread->mystack().base), "-", Genode::Hex(thread->mystack().top)); Genode::backtrace(); diff --git a/repos/dde_linux/src/lib/lx_kit/task.cc b/repos/dde_linux/src/lib/lx_kit/task.cc index 3dc1b5ae38..25544f304b 100644 --- a/repos/dde_linux/src/lib/lx_kit/task.cc +++ b/repos/dde_linux/src/lib/lx_kit/task.cc @@ -36,16 +36,19 @@ bool Task::runnable() const static inline void * _alloc_stack(const char * name) { - enum { STACK_SIZE = 32 * 1024 }; - Genode::Thread * th = Genode::Thread::myself(); - return th->alloc_secondary_stack(name, STACK_SIZE); + size_t const stack_size { 32*1024 }; + return Thread::myself()->alloc_secondary_stack(name, stack_size).convert( + [&] (void *sp) { return sp; }, + [&] (Thread::Stack_error) { + error("lx_kit failed to allocate secondary stack"); + return nullptr; + }); } static inline void _free_stack(void *addr) { - Genode::Thread * th = Genode::Thread::myself(); - th->free_secondary_stack(addr); + Thread::myself()->free_secondary_stack(addr); } diff --git a/repos/libports/src/lib/libc/internal/kernel.h b/repos/libports/src/lib/libc/internal/kernel.h index 2557a17985..ddaaca42b1 100644 --- a/repos/libports/src/lib/libc/internal/kernel.h +++ b/repos/libports/src/lib/libc/internal/kernel.h @@ -227,8 +227,10 @@ struct Libc::Kernel final : Vfs::Read_ready_response_handler, addr_t _kernel_stack = Thread::mystack().top; - void *_user_stack = _myself.alloc_secondary_stack(_myself.name().string(), - _config.stack_size); + void *_user_stack = + _myself.alloc_secondary_stack(_myself.name, _config.stack_size) + .convert([&] (void *sp) { return sp; }, + [&] (Thread::Stack_error) { return nullptr; }); enum State { KERNEL, USER }; diff --git a/repos/libports/src/lib/libc/internal/signal.h b/repos/libports/src/lib/libc/internal/signal.h index 823c352f83..b63a97026a 100644 --- a/repos/libports/src/lib/libc/internal/signal.h +++ b/repos/libports/src/lib/libc/internal/signal.h @@ -96,7 +96,9 @@ struct Libc::Signal : Noncopyable if (!signal_stack) { auto myself = Thread::myself(); if (myself) - _signal_stack_default = { myself->alloc_secondary_stack("signal", 16 * 1024) }; + myself->alloc_secondary_stack("signal", 16 * 1024).with_result( + [&] (void *sp) { _signal_stack_default = sp; }, + [&] (Thread::Stack_error) { }); signal_stack = _signal_stack_default; } diff --git a/repos/libports/src/lib/libc/pthread.cc b/repos/libports/src/lib/libc/pthread.cc index 830611f2fc..c8ff2979f5 100644 --- a/repos/libports/src/lib/libc/pthread.cc +++ b/repos/libports/src/lib/libc/pthread.cc @@ -741,7 +741,7 @@ extern "C" { */ if (!_pthread_main_np()) { error("pthread_self() called from alien thread named ", - "'", Thread::myself()->name().string(), "'"); + "'", Thread::myself()->name, "'"); return nullptr; } diff --git a/repos/libports/src/lib/libc/signal.cc b/repos/libports/src/lib/libc/signal.cc index 76e465d0cc..448e94e9d9 100644 --- a/repos/libports/src/lib/libc/signal.cc +++ b/repos/libports/src/lib/libc/signal.cc @@ -251,10 +251,11 @@ extern "C" int sigaltstack(stack_t const * const ss, stack_t * const old_ss) } else { /* ss->ss_sp is ignored, ever use alloc_secondary stack */ - void * stack = myself->alloc_secondary_stack("sigaltstack", - ss->ss_size); - - signal.use_alternative_stack(stack); + myself->alloc_secondary_stack("sigaltstack", ss->ss_size).with_result( + [&] (void *sp) { + signal.use_alternative_stack(sp); }, + [&] (Thread::Stack_error) { + error("failed to allocate sigaltstack"); }); } } diff --git a/repos/libports/src/lib/libc/syscall.cc b/repos/libports/src/lib/libc/syscall.cc index 37dfbf92d5..a0e139bf96 100644 --- a/repos/libports/src/lib/libc/syscall.cc +++ b/repos/libports/src/lib/libc/syscall.cc @@ -26,7 +26,7 @@ static int sys_thr_self() addr_t const base = Genode::Thread::stack_area_virtual_base(); addr_t const size = Genode::Thread::stack_virtual_size(); - addr_t const stack = (addr_t)Genode::Thread::myself()->stack_base(); + addr_t const stack = Genode::Thread::mystack().base; return int((stack - base) / size + 1); } diff --git a/repos/os/include/os/backtrace.h b/repos/os/include/os/backtrace.h index 9a244d0abf..96b026df21 100644 --- a/repos/os/include/os/backtrace.h +++ b/repos/os/include/os/backtrace.h @@ -60,7 +60,7 @@ struct Genode::Backtrace { using Genode::print; - print(out, "backtrace \"", Thread::myself()->name(), "\""); + print(out, "backtrace \"", Thread::myself()->name, "\""); struct Addr : Hex { Addr(void *v) : Hex((addr_t)v, OMIT_PREFIX) { } }; diff --git a/repos/os/src/test/vmm_x86/component.cc b/repos/os/src/test/vmm_x86/component.cc index 3710a75e1e..04a2383668 100644 --- a/repos/os/src/test/vmm_x86/component.cc +++ b/repos/os/src/test/vmm_x86/component.cc @@ -324,13 +324,13 @@ void Vmm::Vm::_handle_timer() } if (_vcpu1.halted()) { - log(Thread::myself()->name(), " : request pause of vcpu ", _vcpu1.id()); + log(Thread::myself()->name, " : request pause of vcpu ", _vcpu1.id()); /* test to trigger a Genode signal even if we're already blocked */ _vcpu1.request_intercept(); } if (_vcpu1.paused_1st()) { - log(Thread::myself()->name(), " : request resume (A) of vcpu ", _vcpu1.id()); + log(Thread::myself()->name, " : request resume (A) of vcpu ", _vcpu1.id()); _vcpu1.with_state([this](Vcpu_state & state) { state.discharge(); @@ -340,7 +340,7 @@ void Vmm::Vm::_handle_timer() return true; }); } else if (_vcpu1.paused_2nd()) { - log(Thread::myself()->name(), " : request resume (B) of vcpu ", _vcpu1.id()); + log(Thread::myself()->name, " : request resume (B) of vcpu ", _vcpu1.id()); _vcpu1.with_state([this](Vcpu_state & state) { state.discharge(); @@ -357,7 +357,7 @@ void Vmm::Vm::_handle_timer() /* request on the next timeout to stop the jmp endless loop */ _vcpu1.break_endless_loop(); } else if (_vcpu1.paused_3rd()) { - log(Thread::myself()->name(), " : request resume (C) of vcpu ", _vcpu1.id()); + log(Thread::myself()->name, " : request resume (C) of vcpu ", _vcpu1.id()); _vcpu1.with_state([this](Vcpu_state & state) { state.discharge(); @@ -398,7 +398,7 @@ void Vmm::Vcpu::_handle_vcpu_exit() log("vcpu ", _id, " : ", _exit_count, ". vm exit - ", "reason ", Hex((unsigned)exit), " handled by '", - Thread::myself()->name(), "'"); + Thread::myself()->name, "'"); switch (exit) { @@ -422,11 +422,11 @@ void Vmm::Vcpu::_handle_vcpu_exit() /* FIXME handle remote resume */ if (id() == 2) { if (paused_1st()) { - log(Thread::myself()->name(), " : request resume of vcpu ", id()); + log(Thread::myself()->name, " : request resume of vcpu ", id()); return true; } if (paused_2nd()) { - log(Thread::myself()->name(), " : request resume of vcpu ", id()); + log(Thread::myself()->name, " : request resume of vcpu ", id()); /* skip over next hlt instructions after second paused state */ skip_instruction(state, 1*1 /* 1x hlt instruction size */); diff --git a/repos/ports/src/virtualbox6/pthread.cc b/repos/ports/src/virtualbox6/pthread.cc index 01b76dde1d..3752e04ba2 100644 --- a/repos/ports/src/virtualbox6/pthread.cc +++ b/repos/ports/src/virtualbox6/pthread.cc @@ -96,8 +96,11 @@ class Pthread::Entrypoint : public Pthread::Emt { Genode::Thread &myself = *Genode::Thread::myself(); - _emt_stack = myself.alloc_secondary_stack(myself.name().string(), - _stack_size); + _emt_stack = myself.alloc_secondary_stack(myself.name, _stack_size).convert( + [&] (void *sp) { return sp; }, + [&] (Genode::Thread::Stack_error) { + Genode::error("failed to allocate secondary stack for EMT"); + return nullptr; }); Libc::pthread_create_from_thread(&_emt_pthread, myself, _emt_stack);