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
This commit is contained in:
Norman Feske 2024-06-17 18:19:07 +02:00
parent e7f564cd3b
commit d866b6b053
58 changed files with 562 additions and 371 deletions

View File

@ -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(); _sync_bootup.block();
return result;
} }

View File

@ -200,10 +200,9 @@ bool Platform_pd::bind_thread(Platform_thread &thread)
l4_threadid_t l4_thread_id; l4_threadid_t l4_thread_id;
int t = _alloc_thread(thread_id, thread); int t = _alloc_thread(thread_id, thread);
if (t < 0) { if (t < 0)
error("thread alloc failed");
return false; return false;
}
thread_id = t; thread_id = t;
enum { LTHREAD_MASK = (1 << 7) - 1 }; enum { LTHREAD_MASK = (1 << 7) - 1 };

View File

@ -34,7 +34,7 @@ void Thread::_thread_start()
} }
void Thread::start() Thread::Start_result Thread::start()
{ {
/* create and start platform thread */ /* create and start platform thread */
native_thread().pt = new (platform().core_mem_alloc()) 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().l4id = native_thread().pt->native_thread_id();
native_thread().pt->start((void *)_thread_start, stack_top()); native_thread().pt->start((void *)_thread_start, stack_top());
return Start_result::OK;
} }

View File

@ -52,7 +52,7 @@ class Core::Interrupt_handler : public Thread
static Foc::l4_cap_idx_t handler_cap() static Foc::l4_cap_idx_t handler_cap()
{ {
static Interrupt_handler handler; static Interrupt_handler handler;
return handler._thread_cap.data()->kcap(); return handler.cap().data()->kcap();
} }
}; };

View File

@ -140,7 +140,9 @@ Pager_capability Pager_entrypoint::manage(Pager_object &obj)
{ {
using namespace Foc; using namespace Foc;
Native_capability cap(_cap_factory.alloc(Thread::_thread_cap)); return _thread_cap.convert<Pager_capability>(
[&] (Thread_capability thread_cap) {
Native_capability cap(_cap_factory.alloc(thread_cap));
/* add server object to object pool */ /* add server object to object pool */
obj.cap(cap); obj.cap(cap);
@ -148,4 +150,6 @@ Pager_capability Pager_entrypoint::manage(Pager_object &obj)
/* return capability that uses the object id as badge */ /* return capability that uses the object id as badge */
return reinterpret_cap_cast<Pager_object>(cap); return reinterpret_cap_cast<Pager_object>(cap);
},
[&] (Cpu_session::Create_thread_error) { return Pager_capability(); });
} }

View File

@ -86,7 +86,6 @@ bool Platform_pd::bind_thread(Platform_thread &thread)
return true; return true;
} }
error("thread alloc failed");
return false; return false;
} }

View File

@ -39,7 +39,7 @@ void Thread::_deinit_platform_thread()
void Thread::_init_platform_thread(size_t, Type) { } void Thread::_init_platform_thread(size_t, Type) { }
void Thread::start() Thread::Start_result Thread::start()
{ {
using namespace Foc; using namespace Foc;
@ -113,4 +113,6 @@ void Thread::start()
new (platform().core_mem_alloc()) Core_trace_source(Core::Trace::sources(), new (platform().core_mem_alloc()) Core_trace_source(Core::Trace::sources(),
*this, pt); *this, pt);
return Start_result::OK;
} }

View File

@ -50,11 +50,14 @@ void Thread::_deinit_platform_thread()
{ {
using namespace Foc; 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_index *i = (Cap_index*)l4_utcb_tcr_u(utcb()->foc_utcb)->user[UTCB_TCR_BADGE];
cap_map().remove(i); 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) { if (type == NORMAL) {
/* create thread at core */ /* create thread at core */
_thread_cap = _cpu_session->create_thread(pd_session_cap(), _thread_cap = _cpu_session->create_thread(pd_session_cap(), name(),
name(), _affinity, _affinity, Weight(weight));
Weight(weight));
/* assign thread to protection domain */
if (!_thread_cap.valid())
throw Cpu_session::Thread_creation_failed();
return; return;
} }
@ -80,8 +77,10 @@ void Thread::_init_platform_thread(size_t weight, Type type)
native_thread().kcap = Foc::MAIN_THREAD_CAP; native_thread().kcap = Foc::MAIN_THREAD_CAP;
_thread_cap = main_thread_cap(); _thread_cap = main_thread_cap();
if (!_thread_cap.valid()) if (_thread_cap.failed()) {
throw Cpu_session::Thread_creation_failed(); error("failed to re-initialize main thread");
return;
}
/* make thread object known to the Fiasco.OC environment */ /* make thread object known to the Fiasco.OC environment */
addr_t const t = (addr_t)this; addr_t const t = (addr_t)this;
@ -89,15 +88,17 @@ void Thread::_init_platform_thread(size_t weight, Type type)
} }
void Thread::start() Thread::Start_result Thread::start()
{ {
using namespace Foc; using namespace Foc;
return _thread_cap.convert<Start_result>(
[&] (Thread_capability cap) {
Foc_native_cpu_client native_cpu(_cpu_session->native_cpu()); Foc_native_cpu_client native_cpu(_cpu_session->native_cpu());
/* get gate-capability and badge of new thread */ /* get gate-capability and badge of new thread */
Foc_thread_state state { }; Foc_thread_state state { };
state = native_cpu.thread_state(_thread_cap); state = native_cpu.thread_state(cap);
/* remember UTCB of the new thread */ /* remember UTCB of the new thread */
Foc::l4_utcb_t * const foc_utcb = (Foc::l4_utcb_t *)state.utcb; Foc::l4_utcb_t * const foc_utcb = (Foc::l4_utcb_t *)state.utcb;
@ -110,8 +111,13 @@ void Thread::start()
l4_utcb_tcr_u(foc_utcb)->user[UTCB_TCR_THREAD_OBJ] = (addr_t)this; l4_utcb_tcr_u(foc_utcb)->user[UTCB_TCR_THREAD_OBJ] = (addr_t)this;
/* register initial IP and SP at core */ /* register initial IP and SP at core */
Cpu_thread_client cpu_thread(_thread_cap); Cpu_thread_client cpu_thread(cap);
cpu_thread.start((addr_t)_thread_start, _stack->top()); cpu_thread.start((addr_t)_thread_start, _stack->top());
return Start_result::OK;
},
[&] (Cpu_session::Create_thread_error) { return Start_result::DENIED; }
);
} }

View File

@ -32,14 +32,17 @@ using namespace Core;
namespace Hw { extern Untyped_capability _main_thread_cap; } 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 */ /* start thread with stack pointer at the top of stack */
if (native_thread().platform_thread->start((void *)&_thread_start, stack_top())) { if (native_thread().platform_thread->start((void *)&_thread_start, stack_top())) {
error("failed to start thread"); 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, struct Trace_source : public Core::Trace::Source::Info_accessor,
private Core::Trace::Control, private Core::Trace::Control,
private Core::Trace::Source private Core::Trace::Source
@ -73,6 +76,8 @@ void Thread::start()
/* create trace sources for core threads */ /* create trace sources for core threads */
new (platform().core_mem_alloc()) Trace_source(Core::Trace::sources(), *this); new (platform().core_mem_alloc()) Trace_source(Core::Trace::sources(), *this);
return Start_result::OK;
} }

View File

@ -58,8 +58,8 @@ void Thread::_init_platform_thread(size_t weight, Type type)
/* create server object */ /* create server object */
addr_t const utcb = (addr_t)&_stack->utcb(); 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); Weight(weight), utcb);
return; return;
} }
@ -88,7 +88,9 @@ void Thread::_deinit_platform_thread()
return; 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 */ /* detach userland stack */
size_t const size = sizeof(_stack->utcb()); 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 */ return _thread_cap.convert<Start_result>(
try { [&] (Thread_capability cap) {
Dataspace_capability ds = Cpu_thread_client(_thread_cap).utcb(); Cpu_thread_client cpu_thread(cap);
/* attach UTCB at top of stack */
size_t const size = sizeof(_stack->utcb()); size_t const size = sizeof(_stack->utcb());
addr_t dst = Stack_allocator::addr_to_base(_stack) + addr_t dst = Stack_allocator::addr_to_base(_stack) +
stack_virtual_size() - size - stack_area_virtual_base(); stack_virtual_size() - size - stack_area_virtual_base();
env_stack_area_region_map->attach_at(ds, dst, size); try {
env_stack_area_region_map->attach_at(cpu_thread.utcb(), dst, size);
} catch (...) { } catch (...) {
error("failed to attach userland stack"); error("failed to attach userland stack");
sleep_forever(); sleep_forever();
} }
/* start thread with its initial IP and aligned SP */ /* start execution with initial IP and aligned SP */
Cpu_thread_client(_thread_cap).start((addr_t)_thread_start, _stack->top()); cpu_thread.start((addr_t)_thread_start, _stack->top());
return Start_result::OK;
},
[&] (Cpu_session::Create_thread_error) { return Start_result::DENIED; }
);
} }

View File

@ -43,7 +43,7 @@ class Core::Irq_object : public Thread
void sigh(Signal_context_capability cap); void sigh(Signal_context_capability cap);
void ack_irq(); void ack_irq();
void start() override; Start_result start() override;
}; };

View File

@ -75,9 +75,10 @@ void Irq_object::ack_irq()
} }
void Irq_object::start() Thread::Start_result Irq_object::start()
{ {
warning(__func__, " not implemented"); warning(__func__, " not implemented");
return Start_result::DENIED;
} }

View File

@ -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(); _sync_bootup.block();
return result;
} }

View File

@ -64,8 +64,9 @@ void Thread::_init_platform_thread(size_t, Type) { }
void Thread::_deinit_platform_thread() { } 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().tid = lx_create_thread(Thread::_thread_start, stack_top());
native_thread().pid = lx_getpid(); native_thread().pid = lx_getpid();
return Start_result::OK;
} }

View File

@ -24,6 +24,16 @@
using namespace Genode; 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>(
[&] (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 * Register main thread at core
* *
@ -35,8 +45,7 @@ Child::Initial_thread::Initial_thread(Cpu_session &cpu,
Pd_session_capability pd, Pd_session_capability pd,
Name const &name) Name const &name)
: :
_cpu(cpu), _cpu(cpu), _cap(create_thread(pd, cpu, name))
_cap(cpu.create_thread(pd, name, Affinity::Location(), Cpu_session::Weight()))
{ } { }

View File

@ -110,10 +110,12 @@ void Thread::_init_platform_thread(size_t /* weight */, Type type)
/* for normal threads create an object at the CPU session */ /* for normal threads create an object at the CPU session */
if (type == NORMAL) { if (type == NORMAL) {
_thread_cap = _cpu_session->create_thread(pd_session_cap(), _cpu_session->create_thread(pd_session_cap(), _stack->name().string(),
_stack->name().string(), Affinity::Location(), Weight()).with_result(
Affinity::Location(), [&] (Thread_capability cap) { _thread_cap = cap; },
Weight()); [&] (Cpu_session::Create_thread_error) {
error("Thread::_init_platform_thread: create_thread failed");
});
return; return;
} }
/* adjust initial object state for main threads */ /* adjust initial object state for main threads */
@ -152,11 +154,13 @@ void Thread::_deinit_platform_thread()
} }
/* inform core about the killed 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 */ /* synchronize calls of the 'start' function */
static Mutex mutex; static Mutex mutex;
@ -181,6 +185,8 @@ void Thread::start()
/* wait until the 'thread_start' function got entered */ /* wait until the 'thread_start' function got entered */
startup_lock().block(); startup_lock().block();
return Start_result::OK;
} }

View File

@ -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'. * Unblock thread that is supposed to slumber in 'thread_start'.
*/ */
native_thread().meta_data->started(); 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, _thread_cap = _cpu_session->create_thread(_env_ptr->pd_session_cap(), name,
Location(), Weight(weight)); Location(), Weight(weight));
_thread_cap.with_result(
[&] (Thread_capability cap) {
Linux_native_cpu_client native_cpu(_cpu_session->native_cpu()); Linux_native_cpu_client native_cpu(_cpu_session->native_cpu());
native_cpu.thread_id(_thread_cap, native_thread().pid, native_thread().tid); 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; _native_thread = nullptr;
/* inform core about the killed 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) { });
} }

View File

@ -31,8 +31,6 @@
namespace Core { namespace Core {
typedef Cpu_session::Thread_creation_failed Invalid_thread;
class Pager_entrypoint; class Pager_entrypoint;
class Pager_object; class Pager_object;
class Exception_handlers; class Exception_handlers;

View File

@ -58,22 +58,23 @@ struct Pager_thread: public Thread
enum { PAGER_CPUS = Core::Platform::MAX_SUPPORTED_CPUS }; enum { PAGER_CPUS = Core::Platform::MAX_SUPPORTED_CPUS };
static Constructible<Pager_thread> pager_threads[PAGER_CPUS]; static Constructible<Pager_thread> pager_threads[PAGER_CPUS];
static Pager_thread &pager_thread(Affinity::Location location, static void with_pager_thread(Affinity::Location location,
Core::Platform &platform) Core::Platform &platform, auto const &fn)
{ {
unsigned const pager_index = platform.pager_index(location); unsigned const pager_index = platform.pager_index(location);
unsigned const kernel_cpu_id = platform.kernel_cpu_id(location); unsigned const kernel_cpu_id = platform.kernel_cpu_id(location);
if (kernel_hip().is_cpu_enabled(kernel_cpu_id) && if (kernel_hip().is_cpu_enabled(kernel_cpu_id) &&
pager_index < PAGER_CPUS && pager_threads[pager_index].constructed()) pager_index < PAGER_CPUS && pager_threads[pager_index].constructed()) {
return *pager_threads[pager_index];
fn(*pager_threads[pager_index]);
return;
}
warning("invalid CPU parameter used in pager object: ", warning("invalid CPU parameter used in pager object: ",
pager_index, "->", kernel_cpu_id, " location=", pager_index, "->", kernel_cpu_id, " location=",
location.xpos(), "x", location.ypos(), " ", location.xpos(), "x", location.ypos(), " ",
location.width(), "x", location.height()); location.width(), "x", location.height());
throw Invalid_thread();
} }
@ -577,14 +578,18 @@ template <uint8_t EV>
void Exception_handlers::register_handler(Pager_object &obj, Mtd mtd, void Exception_handlers::register_handler(Pager_object &obj, Mtd mtd,
void (* __attribute__((regparm(1))) func)(Pager_object &)) 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 */ /* compiler generates instance of exception entry if not specified */
addr_t entry = func ? (addr_t)func : (addr_t)(&_handler<EV>); addr_t entry = func ? (addr_t)func : (addr_t)(&_handler<EV>);
uint8_t res = create_portal(obj.exc_pt_sel_client() + EV, res = create_portal(obj.exc_pt_sel_client() + EV,
platform_specific().core_pd_sel(), ec_sel, mtd, entry, &obj); platform_specific().core_pd_sel(), ec_sel, mtd, entry, &obj);
});
if (res != Nova::NOVA_OK) 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() 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 */ /* create portal for page-fault handler - 14 */
_exceptions.register_handler<14>(*this, Mtd::QUAL | Mtd::ESP | Mtd::EIP, _exceptions.register_handler<14>(*this, Mtd::QUAL | Mtd::ESP | Mtd::EIP,
_page_fault_handler); _page_fault_handler);
@ -647,25 +649,36 @@ void Pager_object::_construct_pager()
_exceptions.register_handler<PT_SEL_RECALL>(*this, mtd_recall, _exceptions.register_handler<PT_SEL_RECALL>(*this, mtd_recall,
_recall_handler); _recall_handler);
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 */ /* create portal for final cleanup call used during destruction */
uint8_t res = create_portal(sel_pt_cleanup(), pd_sel, ec_sel, Mtd(0), res = create_portal(sel_pt_cleanup(), pd_sel, ec_sel, Mtd(0),
reinterpret_cast<addr_t>(_invoke_handler), reinterpret_cast<addr_t>(_invoke_handler),
this); this);
});
if (res != Nova::NOVA_OK) { if (res != Nova::NOVA_OK) {
error("could not create pager cleanup portal, error=", res); error("could not create pager cleanup portal, error=", res);
throw Invalid_thread(); return;
} }
/* semaphore used to block paged thread during recall */ /* semaphore used to block paged thread during recall */
res = Nova::create_sm(sel_sm_block_pause(), pd_sel, 0); res = Nova::create_sm(sel_sm_block_pause(), pd_sel, 0);
if (res != Nova::NOVA_OK) { 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 */ /* semaphore used to block paged thread during OOM memory revoke */
res = Nova::create_sm(sel_sm_block_oom(), pd_sel, 0); res = Nova::create_sm(sel_sm_block_oom(), pd_sel, 0);
if (res != Nova::NOVA_OK) { 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(); _state.block();
if (Native_thread::INVALID_INDEX == _selectors || if (Native_thread::INVALID_INDEX == _selectors ||
Native_thread::INVALID_INDEX == _client_exc_pt_sel) Native_thread::INVALID_INDEX == _client_exc_pt_sel) {
throw Invalid_thread(); error("failed to complete construction of pager object");
return;
}
_construct_pager(); _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, uint8_t const res = Nova::create_sm(exc_pt_sel_client() + SM_SEL_EC,
pd_sel, 0); pd_sel, 0);
if (res != Nova::NOVA_OK) 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() addr_t Pager_object::create_oom_portal()
{ {
try { uint8_t res = !Nova::NOVA_OK;
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 = create_portal(pt_oom, core_pd_sel, ec_sel, Mtd(0), 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<addr_t>(_oom_handler), reinterpret_cast<addr_t>(_oom_handler),
this); this);
});
if (res == Nova::NOVA_OK) if (res == Nova::NOVA_OK)
return pt_oom; return sel_oom_portal();
} catch (...) { }
error("creating portal for out of memory notification failed"); error("creating portal for out of memory notification failed");
return 0; return 0;

View File

@ -59,10 +59,8 @@ void Thread::_init_platform_thread(size_t, Type type)
/* create running semaphore required for locking */ /* 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); uint8_t res = create_sm(rs_sel, platform_specific().core_pd_sel(), 0);
if (res != NOVA_OK) { if (res != NOVA_OK)
error("create_sm returned ", res); error("Thread::_init_platform_thread: create_sm returned ", res);
throw Cpu_session::Thread_creation_failed();
}
} }
@ -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 * 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, platform_specific().core_pd_sel(), kernel_cpu_id,
(mword_t)&utcb, sp, native_thread().exc_pt_sel, LOCAL_THREAD); (mword_t)&utcb, sp, native_thread().exc_pt_sel, LOCAL_THREAD);
if (res != NOVA_OK) { if (res != NOVA_OK) {
error("create_ec returned ", res); error("Thread::start: create_ec returned ", res);
throw Cpu_session::Thread_creation_failed(); return Start_result::DENIED;
} }
/* default: we don't accept any mappings or translations */ /* default: we don't accept any mappings or translations */
@ -111,8 +109,8 @@ void Thread::start()
*reinterpret_cast<Nova::Utcb *>(Thread::myself()->utcb()), *reinterpret_cast<Nova::Utcb *>(Thread::myself()->utcb()),
Obj_crd(PT_SEL_PAGE_FAULT, 0), Obj_crd(PT_SEL_PAGE_FAULT, 0),
Obj_crd(native_thread().exc_pt_sel + PT_SEL_PAGE_FAULT, 0))) { Obj_crd(native_thread().exc_pt_sel + PT_SEL_PAGE_FAULT, 0))) {
error("could not create page fault portal"); error("Thread::start: failed to create page-fault portal");
throw Cpu_session::Thread_creation_failed(); return Start_result::DENIED;
} }
struct Core_trace_source : public Core::Trace::Source::Info_accessor, struct Core_trace_source : public Core::Trace::Source::Info_accessor,
@ -147,4 +145,6 @@ void Thread::start()
new (platform().core_mem_alloc()) new (platform().core_mem_alloc())
Core_trace_source(Core::Trace::sources(), *this); Core_trace_source(Core::Trace::sources(), *this);
return Start_result::OK;
} }

View File

@ -48,7 +48,7 @@ Untyped_capability Rpc_entrypoint::_manage(Rpc_object_base *obj)
if (native_thread().ec_sel != Native_thread::INVALID_INDEX) if (native_thread().ec_sel != Native_thread::INVALID_INDEX)
ec_cap = Capability_space::import(native_thread().ec_sel); ec_cap = Capability_space::import(native_thread().ec_sel);
else else
ec_cap = _thread_cap; ec_cap = Thread::cap();
Untyped_capability obj_cap = _alloc_rpc_cap(_pd_session, ec_cap, Untyped_capability obj_cap = _alloc_rpc_cap(_pd_session, ec_cap,
(addr_t)&_activation_entry); (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, _cap = _alloc_rpc_cap(_pd_session,
Capability_space::import(native_thread().ec_sel), Capability_space::import(native_thread().ec_sel),
(addr_t)_activation_entry); (addr_t)_activation_entry);
if (!_cap.valid()) if (!_cap.valid()) {
throw Cpu_session::Thread_creation_failed(); error("failed to allocate RPC cap for new entrypoint");
return;
}
Receive_window &rcv_window = Thread::native_thread().server_rcv_window; Receive_window &rcv_window = Thread::native_thread().server_rcv_window;
/* prepare portal receive window of new thread */ /* prepare portal receive window of new thread */
if (!rcv_window.prepare_rcv_window(*(Nova::Utcb *)&_stack->utcb())) 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");
} }

View File

@ -118,17 +118,19 @@ void Thread::_init_platform_thread(size_t weight, Type type)
revoke(Mem_crd(utcb >> 12, 0, rwx)); revoke(Mem_crd(utcb >> 12, 0, rwx));
native_thread().exc_pt_sel = cap_map().insert(NUM_INITIAL_PT_LOG2); native_thread().exc_pt_sel = cap_map().insert(NUM_INITIAL_PT_LOG2);
if (native_thread().exc_pt_sel == Native_thread::INVALID_INDEX) if (native_thread().exc_pt_sel == Native_thread::INVALID_INDEX) {
throw Cpu_session::Thread_creation_failed(); error("failed allocate exception-portal selector for new thread");
return;
}
_init_cpu_session_and_trace_control(); _init_cpu_session_and_trace_control();
/* create thread at core */ /* create thread at core */
_thread_cap = _cpu_session->create_thread(pd_session_cap(), name(), _cpu_session->create_thread(pd_session_cap(), name(),
_affinity, Weight(weight)); _affinity, Weight(weight)).with_result(
if (!_thread_cap.valid()) [&] (Thread_capability cap) { _thread_cap = cap; },
throw Cpu_session::Thread_creation_failed(); [&] (Cpu_session::Create_thread_error) {
error("failed to create new thread for local PD"); });
} }
@ -141,17 +143,23 @@ void Thread::_deinit_platform_thread()
} }
/* de-announce thread */ /* de-announce thread */
if (_thread_cap.valid()) _thread_cap.with_result(
_cpu_session->kill_thread(_thread_cap); [&] (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); 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) if (native_thread().ec_sel < Native_thread::INVALID_INDEX - 1) {
throw Cpu_session::Thread_creation_failed(); 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 * Default: create global thread - ec.sel == INVALID_INDEX
@ -174,13 +182,16 @@ void Thread::start()
Cpu_session::Native_cpu::Exception_base exception_base { native_thread().exc_pt_sel }; Cpu_session::Native_cpu::Exception_base exception_base { native_thread().exc_pt_sel };
Nova_native_cpu_client native_cpu(_cpu_session->native_cpu()); Nova_native_cpu_client native_cpu(_cpu_session->native_cpu());
native_cpu.thread_type(_thread_cap, thread_type, exception_base); native_cpu.thread_type(cap(), thread_type, exception_base);
} catch (...) { throw Cpu_session::Thread_creation_failed(); } } catch (...) {
error("Thread::start failed to set thread type");
return Start_result::DENIED;
}
/* local thread have no start instruction pointer - set via portal entry */ /* local thread have no start instruction pointer - set via portal entry */
addr_t thread_ip = global ? reinterpret_cast<addr_t>(_thread_start) : native_thread().initial_ip; addr_t thread_ip = global ? reinterpret_cast<addr_t>(_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()); cpu_thread.start(thread_ip, _stack->top());
/* request native EC thread cap */ /* request native EC thread cap */
@ -203,6 +214,8 @@ void Thread::start()
if (global) if (global)
/* request creation of SC to let thread run*/ /* request creation of SC to let thread run*/
cpu_thread.resume(); cpu_thread.resume();
return Start_result::OK;
} }

View File

@ -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(); _sync_bootup.block();
return result;
} }

View File

@ -34,7 +34,7 @@ void Thread::_thread_start()
} }
void Thread::start() Thread::Start_result Thread::start()
{ {
/* create and start platform thread */ /* create and start platform thread */
native_thread().pt = new (Core::platform_specific().thread_slab()) 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); Core::platform_specific().core_pd().bind_thread(*native_thread().pt);
native_thread().pt->start((void *)_thread_start, stack_top()); native_thread().pt->start((void *)_thread_start, stack_top());
return Start_result::OK;
} }

View File

@ -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(); _sync_bootup.block();
return result;
} }

View File

@ -185,10 +185,9 @@ bool Platform_pd::bind_thread(Platform_thread &thread)
L4_ThreadId_t l4_thread_id; L4_ThreadId_t l4_thread_id;
int t = _alloc_thread(thread_id, thread); int t = _alloc_thread(thread_id, thread);
if (t < 0) { if (t < 0)
error("thread alloc failed");
return false; return false;
}
thread_id = t; thread_id = t;
l4_thread_id = make_l4_id(_pd_id, thread_id, _version); l4_thread_id = make_l4_id(_pd_id, thread_id, _version);

View File

@ -35,7 +35,7 @@ void Thread::_thread_start()
} }
void Thread::start() Thread::Start_result Thread::start()
{ {
/* create and start platform thread */ /* create and start platform thread */
native_thread().pt = new (platform().core_mem_alloc()) 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().l4id = native_thread().pt->native_thread_id();
native_thread().pt->start((void *)_thread_start, stack_top()); native_thread().pt->start((void *)_thread_start, stack_top());
return Start_result::OK;
} }

View File

@ -52,7 +52,7 @@ class Core::Irq_object : public Thread {
void notify() { Signal_transmitter(_sig_cap).submit(1); } void notify() { Signal_transmitter(_sig_cap).submit(1); }
void ack_irq(); void ack_irq();
void start() override; Start_result start() override;
bool associate(Irq_session::Trigger const, Irq_session::Polarity const); bool associate(Irq_session::Trigger const, Irq_session::Polarity const);
}; };

View File

@ -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(); _sync_bootup.block();
return result;
} }

View File

@ -99,7 +99,7 @@ void Thread::_thread_start()
} }
void Thread::start() Thread::Start_result Thread::start()
{ {
/* write ipcbuffer address to utcb*/ /* write ipcbuffer address to utcb*/
utcb()->ipcbuffer(addr_t(utcb())); utcb()->ipcbuffer(addr_t(utcb()));
@ -142,6 +142,8 @@ void Thread::start()
new (platform().core_mem_alloc()) new (platform().core_mem_alloc())
Core_trace_source(Core::Trace::sources(), *this); Core_trace_source(Core::Trace::sources(), *this);
return Start_result::OK;
} }

View File

@ -304,7 +304,6 @@ class Genode::Child : protected Rpc_object<Parent>,
/** /**
* Constructor * Constructor
* *
* \throw Cpu_session::Thread_creation_failed
* \throw Out_of_ram * \throw Out_of_ram
* \throw Out_of_caps * \throw Out_of_caps
*/ */

View File

@ -88,7 +88,7 @@ class Genode::Quota_guard_untyped
* \return true if quota limit could be reduced, or * \return true if quota limit could be reduced, or
* false if the requested amount exceeds the available quota * 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) if (avail() < amount)
return false; return false;
@ -103,7 +103,7 @@ class Genode::Quota_guard_untyped
* \return true on success, or * \return true on success, or
* false if the amount exceeds the available quota * 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()) if (amount > avail())
return false; return false;
@ -185,6 +185,14 @@ class Genode::Quota_guard
*/ */
void upgrade(UNIT amount) { _guard.upgrade(amount.value); } 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 * Try to decrease quota limit by specified amount
*/ */

View File

@ -31,6 +31,8 @@ class Genode::Session_object : private Ram_quota_guard,
typedef Session::Diag Diag; typedef Session::Diag Diag;
typedef Session::Resources Resources; typedef Session::Resources Resources;
using Ram_quota_guard::try_withdraw;
using Cap_quota_guard::try_withdraw;
using Ram_quota_guard::withdraw; using Ram_quota_guard::withdraw;
using Cap_quota_guard::withdraw; using Cap_quota_guard::withdraw;
using Ram_quota_guard::replenish; using Ram_quota_guard::replenish;

View File

@ -96,11 +96,12 @@ class Genode::Thread
protected: 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. * 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 * Pointer to cpu session used for this thread
@ -271,13 +272,15 @@ class Genode::Thread
*/ */
virtual void entry() = 0; virtual void entry() = 0;
enum class Start_result { OK, DENIED };
/** /**
* Start execution of the thread * Start execution of the thread
* *
* This method is virtual to enable the customization of threads * This method is virtual to enable the customization of threads
* used as server activation. * used as server activation.
*/ */
virtual void start(); virtual Start_result start();
/** /**
* Request name of thread * Request name of thread
@ -316,7 +319,15 @@ class Genode::Thread
/** /**
* Request capability of thread * Request capability of thread
*/ */
Thread_capability cap() const { return _thread_cap; } Thread_capability cap() const
{
return _thread_cap.convert<Thread_capability>(
[&] (Thread_capability cap) { return cap; },
[&] (auto) {
error("attempt to obtain cap of incomplete thread");
return Thread_capability();
});
}
/** /**
* Return kernel-specific thread meta data * Return kernel-specific thread meta data

View File

@ -25,7 +25,7 @@ struct Genode::Cpu_session_client : Rpc_client<Cpu_session>
explicit Cpu_session_client(Cpu_session_capability session) explicit Cpu_session_client(Cpu_session_capability session)
: Rpc_client<Cpu_session>(session) { } : Rpc_client<Cpu_session>(session) { }
Thread_capability Create_thread_result
create_thread(Capability<Pd_session> pd, Name const &name, create_thread(Capability<Pd_session> pd, Name const &name,
Affinity::Location affinity, Weight weight, addr_t utcb = 0) override { Affinity::Location affinity, Weight weight, addr_t utcb = 0) override {
return call<Rpc_create_thread>(pd, name, affinity, weight, utcb); } return call<Rpc_create_thread>(pd, name, affinity, weight, utcb); }

View File

@ -38,14 +38,29 @@ struct Genode::Cpu_connection : Connection<Cpu_session>, Cpu_session_client
Cpu_session_client(cap()) Cpu_session_client(cap())
{ } { }
Thread_capability create_thread(Capability<Pd_session> pd, Create_thread_result create_thread(Capability<Pd_session> pd,
Name const &name, Name const &name,
Affinity::Location affinity, Affinity::Location affinity,
Weight weight, Weight weight,
addr_t utcb = 0) override addr_t utcb = 0) override
{ {
return retry_with_upgrade(Ram_quota{8*1024}, Cap_quota{2}, [&] () { Thread_capability result { };
return Cpu_session_client::create_thread(pd, name, affinity, weight, utcb); }); 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;
} }
}; };

View File

@ -14,9 +14,9 @@
#ifndef _INCLUDE__CPU_SESSION__CPU_SESSION_H_ #ifndef _INCLUDE__CPU_SESSION__CPU_SESSION_H_
#define _INCLUDE__CPU_SESSION__CPU_SESSION_H_ #define _INCLUDE__CPU_SESSION__CPU_SESSION_H_
#include <util/attempt.h>
#include <cpu_session/capability.h> #include <cpu_session/capability.h>
#include <cpu_thread/cpu_thread.h> #include <cpu_thread/cpu_thread.h>
#include <base/stdint.h>
#include <base/rpc_args.h> #include <base/rpc_args.h>
#include <session/session.h> #include <session/session.h>
#include <dataspace/capability.h> #include <dataspace/capability.h>
@ -27,7 +27,7 @@ namespace Genode {
struct Cpu_session; struct Cpu_session;
struct Cpu_session_client; struct Cpu_session_client;
typedef Capability<Cpu_thread> Thread_capability; using Thread_capability = Capability<Cpu_thread>;
} }
@ -46,18 +46,13 @@ struct Genode::Cpu_session : Session
static constexpr unsigned CAP_QUOTA = 6; static constexpr unsigned CAP_QUOTA = 6;
static constexpr size_t RAM_QUOTA = 36*1024; static constexpr size_t RAM_QUOTA = 36*1024;
typedef Cpu_session_client Client; using Client = Cpu_session_client;
/********************* /*********************
** Exception types ** ** 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 { PRIORITY_LIMIT = 1 << 16 };
enum { QUOTA_LIMIT_LOG2 = 15 }; enum { QUOTA_LIMIT_LOG2 = 15 };
enum { QUOTA_LIMIT = 1 << QUOTA_LIMIT_LOG2 }; enum { QUOTA_LIMIT = 1 << QUOTA_LIMIT_LOG2 };
@ -68,13 +63,13 @@ struct Genode::Cpu_session : Session
*/ */
struct Weight struct Weight
{ {
enum { DEFAULT_WEIGHT = 10 }; static constexpr size_t DEFAULT_WEIGHT = 10;
size_t value = DEFAULT_WEIGHT; size_t value = DEFAULT_WEIGHT;
Weight() { } Weight() { }
explicit Weight(size_t value) : value(value) { } explicit Weight(size_t value) : value(value) { }
}; };
typedef String<THREAD_NAME_LEN> Name; using Name = String<32>;
/** /**
* Physical quota configuration * Physical quota configuration
@ -83,6 +78,9 @@ struct Genode::Cpu_session : Session
virtual ~Cpu_session() { } virtual ~Cpu_session() { }
enum class Create_thread_error { OUT_OF_RAM, OUT_OF_CAPS, DENIED };
using Create_thread_result = Attempt<Thread_capability, Create_thread_error>;
/** /**
* Create a new thread * Create a new thread
* *
@ -93,11 +91,8 @@ struct Genode::Cpu_session : Session
* \param weight CPU quota that shall be granted to the thread * \param weight CPU quota that shall be granted to the thread
* \param utcb base of the UTCB that will be used by the thread * \param utcb base of the UTCB that will be used by the thread
* \return capability representing the new 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_session> pd, virtual Create_thread_result create_thread(Capability<Pd_session> pd,
Name const &name, Name const &name,
Affinity::Location affinity, Affinity::Location affinity,
Weight weight, Weight weight,
@ -233,8 +228,7 @@ struct Genode::Cpu_session : Session
** RPC declaration ** ** RPC declaration **
*********************/ *********************/
GENODE_RPC_THROW(Rpc_create_thread, Thread_capability, create_thread, GENODE_RPC(Rpc_create_thread, Create_thread_result, create_thread,
GENODE_TYPE_LIST(Thread_creation_failed, Out_of_ram, Out_of_caps),
Capability<Pd_session>, Name const &, Affinity::Location, Capability<Pd_session>, Name const &, Affinity::Location,
Weight, addr_t); Weight, addr_t);
GENODE_RPC(Rpc_kill_thread, void, kill_thread, Thread_capability); GENODE_RPC(Rpc_kill_thread, void, kill_thread, Thread_capability);

View File

@ -25,19 +25,13 @@
using namespace Core; using namespace Core;
Thread_capability Cpu_session_component::create_thread(Capability<Pd_session> pd_cap, Cpu_session::Create_thread_result
Name const &name, Cpu_session_component::create_thread(Capability<Pd_session> pd_cap,
Affinity::Location affinity, Name const &name, Affinity::Location affinity,
Weight weight, Weight weight, addr_t utcb)
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()});
try {
Cpu_thread_component *thread = 0;
if (weight.value == 0) { if (weight.value == 0) {
warning("Thread ", name, ": Bad weight 0, using default weight instead."); warning("Thread ", name, ": Bad weight 0, using default weight instead.");
@ -50,48 +44,47 @@ Thread_capability Cpu_session_component::create_thread(Capability<Pd_session> pd
Mutex::Guard thread_list_lock_guard(_thread_list_lock); Mutex::Guard thread_list_lock_guard(_thread_list_lock);
/* Create_thread_result result = Create_thread_error::DENIED;
* Create thread associated with its protection domain
*/ _incr_weight(weight.value);
auto create_thread_lambda = [&] (Pd_session_component *pd) {
_thread_ep.apply(pd_cap, [&] (Pd_session_component *pd) {
if (!pd) { if (!pd) {
error("create_thread: invalid PD argument"); error("create_thread: invalid PD argument");
throw Thread_creation_failed(); return;
} }
Mutex::Guard slab_lock_guard(_thread_alloc_lock); Mutex::Guard slab_lock_guard(_thread_alloc_lock);
thread = new (&_thread_alloc)
try {
Cpu_thread_component &thread = *new (&_thread_alloc)
Cpu_thread_component( Cpu_thread_component(
cap(), _thread_ep, _pager_ep, *pd, _trace_control_area, cap(), _thread_ep, _pager_ep, *pd, _trace_control_area,
_trace_sources, weight, _weight_to_quota(weight.value), _trace_sources, weight, _weight_to_quota(weight.value),
_thread_affinity(affinity), _label, thread_name, _thread_affinity(affinity), _label, name,
_priority, utcb); _priority, utcb);
};
try { if (!thread.valid()) {
_incr_weight(weight.value); destroy(_thread_alloc, &thread);
_thread_ep.apply(pd_cap, create_thread_lambda); return;
} 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;
} }
thread->session_exception_sigh(_exception_sigh); thread.session_exception_sigh(_exception_sigh);
_thread_list.insert(thread); _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; }
});
return thread->cap(); if (result.failed()) {
_decr_weight(weight.value);
} catch (...) {
replenish(Ram_quota{_utcb_quota_size()}); replenish(Ram_quota{_utcb_quota_size()});
throw;
} }
return result;
} }

View File

@ -192,6 +192,17 @@ class Core::Account
_quota_guard.withdraw(amount); _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 * Replenish quota to account
* *

View File

@ -166,7 +166,7 @@ class Core::Cpu_session_component : public Session_object<Cpu_session>,
** CPU session interface ** ** CPU session interface **
***************************/ ***************************/
Thread_capability create_thread(Capability<Pd_session>, Name const &, Create_thread_result create_thread(Capability<Pd_session>, Name const &,
Affinity::Location, Weight, addr_t) override; Affinity::Location, Weight, addr_t) override;
void kill_thread(Thread_capability) override; void kill_thread(Thread_capability) override;
void exception_sigh(Signal_context_capability) override; void exception_sigh(Signal_context_capability) override;

View File

@ -55,9 +55,7 @@ class Core::Cpu_thread_component : public Rpc_object<Cpu_thread>,
bool _bind_to_pd(Pd_session_component &pd) bool _bind_to_pd(Pd_session_component &pd)
{ {
if (!pd.bind_thread(_platform_thread)) return pd.bind_thread(_platform_thread);
throw Cpu_session::Thread_creation_failed();
return true;
} }
/** /**
@ -183,6 +181,8 @@ class Core::Cpu_thread_component : public Rpc_object<Cpu_thread>,
_address_space_region_map.remove_client(_rm_client); _address_space_region_map.remove_client(_rm_client);
} }
bool valid() const { return _bound_to_pd; };
/******************************************** /********************************************
** Trace::Source::Info_accessor interface ** ** Trace::Source::Info_accessor interface **

View File

@ -43,7 +43,7 @@ class Core::Irq_object : public Thread
void sigh(Signal_context_capability cap) { _sig_cap = cap; } void sigh(Signal_context_capability cap) { _sig_cap = cap; }
void ack_irq() { _sync_ack.wakeup(); } void ack_irq() { _sync_ack.wakeup(); }
void start() override; Start_result start() override;
}; };
#endif /* _CORE__INCLUDE__IRQ_OBJECT_H_ */ #endif /* _CORE__INCLUDE__IRQ_OBJECT_H_ */

View File

@ -30,8 +30,6 @@
namespace Core { namespace Core {
typedef Cpu_session::Thread_creation_failed Invalid_thread;
/** /**
* Special server object for paging * Special server object for paging
* *
@ -84,8 +82,6 @@ class Core::Pager_object : public Object_pool<Pager_object>::Entry
* Constructor * Constructor
* *
* \param location affinity of paged thread to physical CPU * \param location affinity of paged thread to physical CPU
*
* \throw Invalid_thread
*/ */
Pager_object(Cpu_session_capability cpu_sesion, Pager_object(Cpu_session_capability cpu_sesion,
Thread_capability thread, Thread_capability thread,

View File

@ -38,19 +38,27 @@ struct Genode::Expanding_cpu_session_client : Upgradeable_client<Genode::Cpu_ses
(parent, static_cap_cast<Genode::Cpu_session_client::Rpc_interface>(cap), id) (parent, static_cap_cast<Genode::Cpu_session_client::Rpc_interface>(cap), id)
{ } { }
Thread_capability Create_thread_result
create_thread(Pd_session_capability pd, Name const &name, create_thread(Pd_session_capability pd, Name const &name,
Affinity::Location location, Weight weight, addr_t utcb) override Affinity::Location location, Weight weight, addr_t utcb) override
{ {
return retry<Out_of_ram>( Thread_capability result { };
[&] () { bool denied = false;
return retry<Out_of_caps>( while (!result.valid()) {
[&] () { using Error = Cpu_session::Create_thread_error;
return Cpu_session_client::create_thread(pd, name, location, Cpu_session_client::create_thread(pd, name, location, weight, utcb).with_result(
weight, utcb); }, [&] (Thread_capability cap) { result = cap; },
[&] () { upgrade_caps(2); }); [&] (Error e) {
}, switch (e) {
[&] () { upgrade_ram(8*1024); }); 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;
} }
}; };

View File

@ -757,7 +757,6 @@ void Child::_try_construct_env_dependent_members()
} }
catch (Out_of_ram) { _error("out of RAM during ELF loading"); } catch (Out_of_ram) { _error("out of RAM during ELF loading"); }
catch (Out_of_caps) { _error("out of caps 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::Missing_dynamic_linker) { _error("dynamic linker unavailable"); }
catch (Process::Invalid_executable) { _error("invalid ELF executable"); } catch (Process::Invalid_executable) { _error("invalid ELF executable"); }
catch (Region_map::Invalid_dataspace) { _error("ELF loading failed (Invalid_dataspace)"); } catch (Region_map::Invalid_dataspace) { _error("ELF loading failed (Invalid_dataspace)"); }

View File

@ -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>(
[&] (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, Child::Initial_thread::Initial_thread(Cpu_session &cpu,
Pd_session_capability pd, Pd_session_capability pd,
Name const &name) Name const &name)
: :
_cpu(cpu), _cpu(cpu), _cap(create_thread(pd, cpu, name))
_cap(cpu.create_thread(pd, name, Affinity::Location(), Cpu_session::Weight()))
{ } { }

View File

@ -71,23 +71,29 @@ void Thread::_deinit_platform_thread()
return; 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(); _init_cpu_session_and_trace_control();
/* create thread at core */ /* create thread at core */
addr_t const utcb = (addr_t)&_stack->utcb(); addr_t const utcb = (addr_t)&_stack->utcb();
_thread_cap = _cpu_session->create_thread(pd_session_cap(), name(),
_affinity, Weight(), utcb); _thread_cap = _cpu_session->create_thread(pd_session_cap(), name(), _affinity,
if (!_thread_cap.valid()) Weight(), utcb);
throw Cpu_session::Thread_creation_failed(); return _thread_cap.convert<Start_result>(
[&] (Thread_capability cap) {
/* start execution at initial instruction pointer and stack pointer */ /* start execution at initial instruction pointer and stack pointer */
Cpu_thread_client(_thread_cap).start((addr_t)_thread_start, _stack->top()); Cpu_thread_client(cap).start((addr_t)_thread_start, _stack->top());
return Start_result::OK;
},
[&] (Cpu_session::Create_thread_error) { return Start_result::DENIED; });
} }

View File

@ -222,8 +222,10 @@ Trace::Logger *Thread::_logger()
if (!logger.initialized()) { if (!logger.initialized()) {
logger.init_pending(true); logger.init_pending(true);
Thread_capability thread_cap = myself ? myself->_thread_cap using Create_result = Cpu_session::Create_thread_result;
: _env().parent().main_thread_cap(); 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(); Cpu_session &cpu = myself ? *myself->_cpu_session : _env().cpu();
@ -234,8 +236,11 @@ Trace::Logger *Thread::_logger()
main_trace_control = _env().rm().attach(ds); main_trace_control = _env().rm().attach(ds);
} }
logger.init(thread_cap, &cpu, thread_cap.with_result(
myself ? myself->_trace_control : main_trace_control); [&] (Thread_capability cap) {
logger.init(cap, &cpu, myself ? myself->_trace_control
: main_trace_control); },
[&] (Cpu_session::Create_thread_error) { });
} }
return &logger; return &logger;

View File

@ -312,26 +312,33 @@ static void test_create_as_many_threads(Env &env)
Heap heap(env.ram(), env.rm()); Heap heap(env.ram(), env.rm());
unsigned i = 0; unsigned i = 0;
try { bool denied = false;
bool out_of_stack_space = false;
for (; i < max; i++) { for (; i < max; i++) {
try { try {
threads[i] = new (heap) Cpu_helper(env, Thread::Name(i + 1), env.cpu()); threads[i] = new (heap) Cpu_helper(env, Thread::Name(i + 1), env.cpu());
threads[i]->start(); if (threads[i]->start() == Thread::Start_result::DENIED) {
denied = true;
break;
}
threads[i]->join(); threads[i]->join();
} catch (Cpu_session::Thread_creation_failed) {
throw "Thread_creation_failed";
} catch (Thread::Out_of_stack_space) { } catch (Thread::Out_of_stack_space) {
throw "Out_of_stack_space"; out_of_stack_space = true;
break;
} catch (Genode::Native_capability::Reference_count_overflow) { } catch (Genode::Native_capability::Reference_count_overflow) {
throw "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--) { for (unsigned j = i; j > 0; j--) {
destroy(heap, threads[j - 1]); destroy(heap, threads[j - 1]);
threads[j - 1] = nullptr; threads[j - 1] = nullptr;
} }
if (denied) {
log("created ", i, " threads before thread creation got denied");
return; return;
} }
@ -339,6 +346,7 @@ static void test_create_as_many_threads(Env &env)
* We have to get a Out_of_stack_space message, because we can't create * 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 ... * up to max threads, because already the main thread is running ...
*/ */
if (!out_of_stack_space)
throw -21; throw -21;
} }

View File

@ -21,7 +21,7 @@ using namespace Genode;
using namespace Cpu_sampler; using namespace Cpu_sampler;
Thread_capability Cpu_session::Create_thread_result
Cpu_sampler::Cpu_session_component::create_thread(Pd_session_capability pd, Cpu_sampler::Cpu_session_component::create_thread(Pd_session_capability pd,
Name const &name, Name const &name,
Affinity::Location affinity, Affinity::Location affinity,

View File

@ -97,7 +97,7 @@ class Cpu_sampler::Cpu_session_component : public Rpc_object<Cpu_session>
** CPU session interface ** ** CPU session interface **
***************************/ ***************************/
Thread_capability create_thread(Pd_session_capability pd, Create_thread_result create_thread(Pd_session_capability pd,
Name const &, Name const &,
Affinity::Location, Affinity::Location,
Weight, Weight,

View File

@ -36,7 +36,12 @@ Cpu_sampler::Cpu_thread_component::Cpu_thread_component(
_cpu_session_component(cpu_session_component), _env(env), _md_alloc(md_alloc), _cpu_session_component(cpu_session_component), _env(env), _md_alloc(md_alloc),
_parent_cpu_thread( _parent_cpu_thread(
_cpu_session_component.parent_cpu_session() _cpu_session_component.parent_cpu_session()
.create_thread(pd, name, affinity, weight, utcb)), .create_thread(pd, name, affinity, weight, utcb)
.convert<Thread_capability>(
[&] (Thread_capability cap) { return cap; },
[&] (auto) {
error("failed to create CPU thread");
return Thread_capability(); })),
_label(_cpu_session_component.session_label().string(), " -> ", thread_name), _label(_cpu_session_component.session_label().string(), " -> ", thread_name),
_log_session_label("samples -> ", _label, ".", thread_id) _log_session_label("samples -> ", _label, ".", thread_id)
{ {

View File

@ -51,22 +51,23 @@ struct Monitor::Inferior_cpu : Monitored_cpu_session
** Cpu_session interface ** ** Cpu_session interface **
***************************/ ***************************/
Thread_capability Create_thread_result
create_thread(Capability<Pd_session> pd, Cpu_session::Name const &name, create_thread(Capability<Pd_session> pd, Cpu_session::Name const &name,
Affinity::Location affinity, Weight weight, addr_t utcb) override 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::with_inferior_pd(_ep, pd,
[&] (Inferior_pd &inferior_pd) {
Capability<Cpu_thread> real_thread = [&] (Inferior_pd &inferior_pd) {
_real.call<Rpc_create_thread>(inferior_pd._real, _real.call<Rpc_create_thread>(inferior_pd._real, name, affinity,
name, affinity, weight, utcb); weight, utcb).with_result(
[&] (Thread_capability real_thread) {
Threads::Id thread_id { inferior_pd.alloc_thread_id() }; Threads::Id thread_id { inferior_pd.alloc_thread_id() };
bool wait = inferior_pd._policy.wait && bool const wait = inferior_pd._policy.wait
(thread_id == Threads::Id { 1 }); && (thread_id == Threads::Id { 1 });
Monitored_thread &monitored_thread = *new (_alloc) Monitored_thread &monitored_thread = *new (_alloc)
Monitored_thread(_ep, real_thread, name, Monitored_thread(_ep, real_thread, name,
@ -75,6 +76,9 @@ struct Monitor::Inferior_cpu : Monitored_cpu_session
result = monitored_thread.cap(); result = monitored_thread.cap();
}, },
[&] (Create_thread_error e) { result = e; }
);
},
[&] { [&] {
result = _real.call<Rpc_create_thread>(pd, name, affinity, weight, utcb); result = _real.call<Rpc_create_thread>(pd, name, affinity, weight, utcb);
}); });

View File

@ -74,7 +74,7 @@ struct Monitor::Pd_intrinsics : Sandbox::Pd_intrinsics
using Sig_ctx_cap = Signal_context_capability; using Sig_ctx_cap = Signal_context_capability;
Thread_capability Create_thread_result
create_thread(Capability<Pd_session>, Cpu_session::Name const &, create_thread(Capability<Pd_session>, Cpu_session::Name const &,
Affinity::Location, Weight, addr_t) override { never_called(__func__); } Affinity::Location, Weight, addr_t) override { never_called(__func__); }
void kill_thread(Thread_capability) override { never_called(__func__); } void kill_thread(Thread_capability) override { never_called(__func__); }

View File

@ -17,14 +17,14 @@
using namespace Genode; using namespace Genode;
using namespace Cpu; using namespace Cpu;
Thread_capability Cpu_session::Create_thread_result
Cpu::Session::create_thread(Pd_session_capability const pd, Cpu::Session::create_thread(Pd_session_capability const pd,
Name const &name_by_client, Name const &name_by_client,
Affinity::Location const location, Affinity::Location const location,
Weight const weight, Weight const weight,
addr_t const utcb) addr_t const utcb)
{ {
Thread_capability cap { }; Create_thread_result result = Create_thread_error::DENIED;
Name name = name_by_client; Name name = name_by_client;
if (!name.valid()) 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 */ /* 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 || _reclaim_cap.value) && _one_valid_thread()) {
if (_reclaim_ram.value) if (_reclaim_ram.value)
throw Out_of_ram(); return Create_thread_error::OUT_OF_RAM;
if (_reclaim_cap.value) if (_reclaim_cap.value)
throw Out_of_caps(); return Create_thread_error::OUT_OF_CAPS;
} }
/* read in potential existing policy for thread */ /* read in potential existing policy for thread */
@ -47,11 +47,10 @@ Cpu::Session::create_thread(Pd_session_capability const pd,
if (store_cap.valid()) if (store_cap.valid())
return false; return false;
cap = _parent.create_thread(pd, name, location, weight, utcb); result = _parent.create_thread(pd, name, location, weight, utcb);
if (!cap.valid()) return result.convert<bool>(
/* stop creation attempt by saying done */
return true;
[&] (Thread_capability cap) {
/* policy and name are set beforehand */ /* policy and name are set beforehand */
store_cap = cap; store_cap = cap;
@ -64,16 +63,23 @@ Cpu::Session::create_thread(Pd_session_capability const pd,
", policy=", policy, ", name='", name, "'"); ", 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; _report = true;
return cap; return result;
} }
cap = _parent.create_thread(pd, name, location, weight, utcb); result = _parent.create_thread(pd, name, location, weight, utcb);
if (!cap.valid()) if (result.failed())
return cap; return result;
/* unknown thread without any configuration */ /* unknown thread without any configuration */
construct(_default_policy, [&](Thread_capability &store_cap, construct(_default_policy, [&](Thread_capability &store_cap,
@ -81,6 +87,8 @@ Cpu::Session::create_thread(Pd_session_capability const pd,
{ {
policy.location = location; policy.location = location;
result.with_result(
[&] (Thread_capability cap) {
store_cap = cap; store_cap = cap;
store_name = name; store_name = name;
@ -89,12 +97,14 @@ Cpu::Session::create_thread(Pd_session_capability const pd,
location.xpos(), "x", location.ypos(), location.xpos(), "x", location.ypos(),
", no policy defined", ", no policy defined",
", name='", name, "'"); ", name='", name, "'");
},
[&] (Create_thread_error) { });
}); });
if (cap.valid()) if (result.ok())
_report = true; _report = true;
return cap; return result;
} }

View File

@ -328,7 +328,7 @@ class Cpu::Session : public Rpc_object<Cpu_session>
** CPU session interface ** ** CPU session interface **
***************************/ ***************************/
Thread_capability create_thread(Pd_session_capability, Create_thread_result create_thread(Pd_session_capability,
Thread::Name const &, Thread::Name const &,
Affinity::Location, Weight, Affinity::Location, Weight,
addr_t) override; addr_t) override;

View File

@ -76,13 +76,29 @@ class Vmm::Vcpu_other_pd : public Vmm::Vcpu_thread
{ {
using namespace Genode; using namespace Genode;
Thread_capability vcpu_vm = Thread_capability vcpu_vm { };
_cpu_connection->retry_with_upgrade(Ram_quota{8*1024}, Cap_quota{2},
[&] () while (!vcpu_vm.valid()) {
{
return _cpu_connection->create_thread(_pd_cap, "vCPU", _location, bool denied = false;
Cpu_session::Weight());
}); 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 */ /* tell parent that this will be a vCPU */
Cpu_session::Native_cpu::Thread_type thread_type { Cpu_session::Native_cpu::Thread_type::VCPU }; Cpu_session::Native_cpu::Thread_type thread_type { Cpu_session::Native_cpu::Thread_type::VCPU };

View File

@ -861,8 +861,10 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<Genode::Thread>,
unsigned int cpu_id() { return _cpu_id; } unsigned int cpu_id() { return _cpu_id; }
void start() { Start_result start() override
{
_vcpu.start(_ec_sel); _vcpu.start(_ec_sel);
return Start_result::OK;
} }
void recall(Vcpu_handler * other = nullptr) void recall(Vcpu_handler * other = nullptr)