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();
return result;
}

View File

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

View File

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

View File

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

View File

@ -140,12 +140,16 @@ Pager_capability Pager_entrypoint::manage(Pager_object &obj)
{
using namespace Foc;
Native_capability cap(_cap_factory.alloc(Thread::_thread_cap));
return _thread_cap.convert<Pager_capability>(
[&] (Thread_capability thread_cap) {
Native_capability cap(_cap_factory.alloc(thread_cap));
/* add server object to object pool */
obj.cap(cap);
insert(&obj);
/* add server object to object pool */
obj.cap(cap);
insert(&obj);
/* return capability that uses the object id as badge */
return reinterpret_cap_cast<Pager_object>(cap);
/* return capability that uses the object id as badge */
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;
}
error("thread alloc failed");
return false;
}

View File

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

View File

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

View File

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

View File

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

View File

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

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");
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();
return result;
}

View File

@ -64,8 +64,9 @@ void Thread::_init_platform_thread(size_t, Type) { }
void Thread::_deinit_platform_thread() { }
void Thread::start()
Thread::Start_result Thread::start()
{
native_thread().tid = lx_create_thread(Thread::_thread_start, stack_top());
native_thread().pid = lx_getpid();
return Start_result::OK;
}

View File

@ -24,6 +24,16 @@
using namespace Genode;
static Thread_capability create_thread(auto &pd, auto &cpu, auto const &name)
{
return cpu.create_thread(pd, name, { }, { }).template convert<Thread_capability>(
[&] (Thread_capability cap) { return cap; },
[&] (Cpu_session::Create_thread_error) {
error("failed to create thread via CPU session");
return Thread_capability(); });
}
/*
* Register main thread at core
*
@ -35,8 +45,7 @@ Child::Initial_thread::Initial_thread(Cpu_session &cpu,
Pd_session_capability pd,
Name const &name)
:
_cpu(cpu),
_cap(cpu.create_thread(pd, name, Affinity::Location(), Cpu_session::Weight()))
_cpu(cpu), _cap(create_thread(pd, cpu, name))
{ }

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

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'.
*/
native_thread().meta_data->started();
return Start_result::OK;
}
@ -531,9 +532,14 @@ Thread::Thread(size_t weight, const char *name, size_t /* stack size */,
_thread_cap = _cpu_session->create_thread(_env_ptr->pd_session_cap(), name,
Location(), Weight(weight));
Linux_native_cpu_client native_cpu(_cpu_session->native_cpu());
native_cpu.thread_id(_thread_cap, native_thread().pid, native_thread().tid);
_thread_cap.with_result(
[&] (Thread_capability cap) {
Linux_native_cpu_client native_cpu(_cpu_session->native_cpu());
native_cpu.thread_id(cap, native_thread().pid, native_thread().tid);
},
[&] (Cpu_session::Create_thread_error) {
error("failed to create hybrid thread"); }
);
}
@ -573,7 +579,9 @@ Thread::~Thread()
_native_thread = nullptr;
/* inform core about the killed thread */
_cpu_session->kill_thread(_thread_cap);
_thread_cap.with_result(
[&] (Thread_capability cap) { _cpu_session->kill_thread(cap); },
[&] (Cpu_session::Create_thread_error) { });
}

View File

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

View File

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

View File

@ -57,12 +57,10 @@ void Thread::_init_platform_thread(size_t, Type type)
native_thread().exc_pt_sel = cap_map().insert(NUM_INITIAL_PT_LOG2);
/* create running semaphore required for locking */
addr_t rs_sel =native_thread().exc_pt_sel + SM_SEL_EC;
addr_t rs_sel = native_thread().exc_pt_sel + SM_SEL_EC;
uint8_t res = create_sm(rs_sel, platform_specific().core_pd_sel(), 0);
if (res != NOVA_OK) {
error("create_sm returned ", res);
throw Cpu_session::Thread_creation_failed();
}
if (res != NOVA_OK)
error("Thread::_init_platform_thread: create_sm returned ", res);
}
@ -81,7 +79,7 @@ void Thread::_deinit_platform_thread()
}
void Thread::start()
Thread::Start_result Thread::start()
{
/*
* On NOVA, core almost never starts regular threads. This simply creates a
@ -99,8 +97,8 @@ void Thread::start()
platform_specific().core_pd_sel(), kernel_cpu_id,
(mword_t)&utcb, sp, native_thread().exc_pt_sel, LOCAL_THREAD);
if (res != NOVA_OK) {
error("create_ec returned ", res);
throw Cpu_session::Thread_creation_failed();
error("Thread::start: create_ec returned ", res);
return Start_result::DENIED;
}
/* default: we don't accept any mappings or translations */
@ -111,8 +109,8 @@ void Thread::start()
*reinterpret_cast<Nova::Utcb *>(Thread::myself()->utcb()),
Obj_crd(PT_SEL_PAGE_FAULT, 0),
Obj_crd(native_thread().exc_pt_sel + PT_SEL_PAGE_FAULT, 0))) {
error("could not create page fault portal");
throw Cpu_session::Thread_creation_failed();
error("Thread::start: failed to create page-fault portal");
return Start_result::DENIED;
}
struct Core_trace_source : public Core::Trace::Source::Info_accessor,
@ -147,4 +145,6 @@ void Thread::start()
new (platform().core_mem_alloc())
Core_trace_source(Core::Trace::sources(), *this);
return Start_result::OK;
}

View File

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

View File

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

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

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();
return result;
}

View File

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

View File

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

View File

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

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();
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*/
utcb()->ipcbuffer(addr_t(utcb()));
@ -142,6 +142,8 @@ void Thread::start()
new (platform().core_mem_alloc())
Core_trace_source(Core::Trace::sources(), *this);
return Start_result::OK;
}

View File

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

View File

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

View File

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

View File

@ -96,11 +96,12 @@ class Genode::Thread
protected:
/**
* Capability for this thread (set by _start())
* Capability for this thread or creation error (set by _start())
*
* Used if thread creation involves core's CPU service.
*/
Thread_capability _thread_cap { };
Cpu_session::Create_thread_result _thread_cap =
Cpu_session::Create_thread_error::DENIED;
/**
* Pointer to cpu session used for this thread
@ -271,13 +272,15 @@ class Genode::Thread
*/
virtual void entry() = 0;
enum class Start_result { OK, DENIED };
/**
* Start execution of the thread
*
* This method is virtual to enable the customization of threads
* used as server activation.
*/
virtual void start();
virtual Start_result start();
/**
* Request name of thread
@ -316,7 +319,15 @@ class Genode::Thread
/**
* Request capability of thread
*/
Thread_capability cap() const { return _thread_cap; }
Thread_capability cap() const
{
return _thread_cap.convert<Thread_capability>(
[&] (Thread_capability cap) { return cap; },
[&] (auto) {
error("attempt to obtain cap of incomplete thread");
return Thread_capability();
});
}
/**
* 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)
: Rpc_client<Cpu_session>(session) { }
Thread_capability
Create_thread_result
create_thread(Capability<Pd_session> pd, Name const &name,
Affinity::Location affinity, Weight weight, addr_t utcb = 0) override {
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())
{ }
Thread_capability create_thread(Capability<Pd_session> pd,
Name const &name,
Affinity::Location affinity,
Weight weight,
addr_t utcb = 0) override
Create_thread_result create_thread(Capability<Pd_session> pd,
Name const &name,
Affinity::Location affinity,
Weight weight,
addr_t utcb = 0) override
{
return retry_with_upgrade(Ram_quota{8*1024}, Cap_quota{2}, [&] () {
return Cpu_session_client::create_thread(pd, name, affinity, weight, utcb); });
Thread_capability result { };
bool denied = false;
while (!result.valid()) {
using Error = Cpu_session::Create_thread_error;
Cpu_session_client::create_thread(pd, name, affinity, weight, utcb).with_result(
[&] (Thread_capability cap) { result = cap; },
[&] (Error e) {
switch (e) {
case Error::OUT_OF_RAM: upgrade_ram(8*1024); break;
case Error::OUT_OF_CAPS: upgrade_caps(2); break;
case Error::DENIED: denied = true; break;
}
});
if (denied)
return Error::DENIED;
}
return result;
}
};

View File

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

View File

@ -25,73 +25,66 @@
using namespace Core;
Thread_capability Cpu_session_component::create_thread(Capability<Pd_session> pd_cap,
Name const &name,
Affinity::Location affinity,
Weight weight,
addr_t utcb)
Cpu_session::Create_thread_result
Cpu_session_component::create_thread(Capability<Pd_session> pd_cap,
Name const &name, Affinity::Location affinity,
Weight weight, addr_t utcb)
{
Trace::Thread_name thread_name(name.string());
if (!try_withdraw(Ram_quota{_utcb_quota_size()}))
return Create_thread_error::OUT_OF_RAM;
withdraw(Ram_quota{_utcb_quota_size()});
if (weight.value == 0) {
warning("Thread ", name, ": Bad weight 0, using default weight instead.");
weight = Weight();
}
if (weight.value > QUOTA_LIMIT) {
warning("Thread ", name, ": Oversized weight ", weight.value, ", using limit instead.");
weight = Weight(QUOTA_LIMIT);
}
try {
Mutex::Guard thread_list_lock_guard(_thread_list_lock);
Cpu_thread_component *thread = 0;
Create_thread_result result = Create_thread_error::DENIED;
if (weight.value == 0) {
warning("Thread ", name, ": Bad weight 0, using default weight instead.");
weight = Weight();
}
if (weight.value > QUOTA_LIMIT) {
warning("Thread ", name, ": Oversized weight ", weight.value, ", using limit instead.");
weight = Weight(QUOTA_LIMIT);
_incr_weight(weight.value);
_thread_ep.apply(pd_cap, [&] (Pd_session_component *pd) {
if (!pd) {
error("create_thread: invalid PD argument");
return;
}
Mutex::Guard thread_list_lock_guard(_thread_list_lock);
Mutex::Guard slab_lock_guard(_thread_alloc_lock);
/*
* Create thread associated with its protection domain
*/
auto create_thread_lambda = [&] (Pd_session_component *pd) {
if (!pd) {
error("create_thread: invalid PD argument");
throw Thread_creation_failed();
}
Mutex::Guard slab_lock_guard(_thread_alloc_lock);
thread = new (&_thread_alloc)
try {
Cpu_thread_component &thread = *new (&_thread_alloc)
Cpu_thread_component(
cap(), _thread_ep, _pager_ep, *pd, _trace_control_area,
_trace_sources, weight, _weight_to_quota(weight.value),
_thread_affinity(affinity), _label, thread_name,
_thread_affinity(affinity), _label, name,
_priority, utcb);
};
try {
_incr_weight(weight.value);
_thread_ep.apply(pd_cap, create_thread_lambda);
} catch (Allocator::Out_of_memory) {
_decr_weight(weight.value);
throw Out_of_ram();
} catch (Native_capability::Reference_count_overflow) {
_decr_weight(weight.value);
throw Thread_creation_failed();
} catch (...) {
_decr_weight(weight.value);
throw;
if (!thread.valid()) {
destroy(_thread_alloc, &thread);
return;
}
thread.session_exception_sigh(_exception_sigh);
_thread_list.insert(&thread);
result = thread.cap();
}
catch (Out_of_ram) { result = Create_thread_error::OUT_OF_RAM; }
catch (Out_of_caps) { result = Create_thread_error::OUT_OF_CAPS; }
catch (...) { result = Create_thread_error::DENIED; }
});
thread->session_exception_sigh(_exception_sigh);
_thread_list.insert(thread);
return thread->cap();
} catch (...) {
if (result.failed()) {
_decr_weight(weight.value);
replenish(Ram_quota{_utcb_quota_size()});
throw;
}
return result;
}

View File

@ -192,6 +192,17 @@ class Core::Account
_quota_guard.withdraw(amount);
}
/**
* Withdraw quota from account
*
* \return true if withdrawal of 'amount' succeeded
*/
[[nodiscard]] bool try_withdraw(UNIT amount)
{
Mutex::Guard guard(_mutex);
return _quota_guard.try_withdraw(amount);
}
/**
* Replenish quota to account
*

View File

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

View File

@ -55,9 +55,7 @@ class Core::Cpu_thread_component : public Rpc_object<Cpu_thread>,
bool _bind_to_pd(Pd_session_component &pd)
{
if (!pd.bind_thread(_platform_thread))
throw Cpu_session::Thread_creation_failed();
return true;
return pd.bind_thread(_platform_thread);
}
/**
@ -183,6 +181,8 @@ class Core::Cpu_thread_component : public Rpc_object<Cpu_thread>,
_address_space_region_map.remove_client(_rm_client);
}
bool valid() const { return _bound_to_pd; };
/********************************************
** 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 ack_irq() { _sync_ack.wakeup(); }
void start() override;
Start_result start() override;
};
#endif /* _CORE__INCLUDE__IRQ_OBJECT_H_ */

View File

@ -30,8 +30,6 @@
namespace Core {
typedef Cpu_session::Thread_creation_failed Invalid_thread;
/**
* Special server object for paging
*
@ -84,8 +82,6 @@ class Core::Pager_object : public Object_pool<Pager_object>::Entry
* Constructor
*
* \param location affinity of paged thread to physical CPU
*
* \throw Invalid_thread
*/
Pager_object(Cpu_session_capability cpu_sesion,
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)
{ }
Thread_capability
Create_thread_result
create_thread(Pd_session_capability pd, Name const &name,
Affinity::Location location, Weight weight, addr_t utcb) override
{
return retry<Out_of_ram>(
[&] () {
return retry<Out_of_caps>(
[&] () {
return Cpu_session_client::create_thread(pd, name, location,
weight, utcb); },
[&] () { upgrade_caps(2); });
},
[&] () { upgrade_ram(8*1024); });
Thread_capability result { };
bool denied = false;
while (!result.valid()) {
using Error = Cpu_session::Create_thread_error;
Cpu_session_client::create_thread(pd, name, location, weight, utcb).with_result(
[&] (Thread_capability cap) { result = cap; },
[&] (Error e) {
switch (e) {
case Error::OUT_OF_RAM: upgrade_ram(8*1024); break;
case Error::OUT_OF_CAPS: upgrade_caps(2); break;
case Error::DENIED: denied = true; break;
}
});
if (denied)
return Error::DENIED;
}
return result;
}
};

View File

@ -755,13 +755,12 @@ void Child::_try_construct_env_dependent_members()
*_initial_thread, _initial_thread_start,
_local_rm, address_space, cap()); });
}
catch (Out_of_ram) { _error("out of RAM during ELF loading"); }
catch (Out_of_caps) { _error("out of caps during ELF loading"); }
catch (Cpu_session::Thread_creation_failed) { _error("unable to create initial thread"); }
catch (Process::Missing_dynamic_linker) { _error("dynamic linker unavailable"); }
catch (Process::Invalid_executable) { _error("invalid ELF executable"); }
catch (Region_map::Invalid_dataspace) { _error("ELF loading failed (Invalid_dataspace)"); }
catch (Region_map::Region_conflict) { _error("ELF loading failed (Region_conflict)"); }
catch (Out_of_ram) { _error("out of RAM during ELF loading"); }
catch (Out_of_caps) { _error("out of caps during ELF loading"); }
catch (Process::Missing_dynamic_linker) { _error("dynamic linker unavailable"); }
catch (Process::Invalid_executable) { _error("invalid ELF executable"); }
catch (Region_map::Invalid_dataspace) { _error("ELF loading failed (Invalid_dataspace)"); }
catch (Region_map::Region_conflict) { _error("ELF loading failed (Region_conflict)"); }
}

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

View File

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

View File

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

View File

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

View File

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

View File

@ -97,11 +97,11 @@ class Cpu_sampler::Cpu_session_component : public Rpc_object<Cpu_session>
** CPU session interface **
***************************/
Thread_capability create_thread(Pd_session_capability pd,
Name const &,
Affinity::Location,
Weight,
addr_t) override;
Create_thread_result create_thread(Pd_session_capability pd,
Name const &,
Affinity::Location,
Weight,
addr_t) override;
void kill_thread(Thread_capability) override;
void exception_sigh(Signal_context_capability handler) override;
Affinity::Space affinity_space() const override;

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),
_parent_cpu_thread(
_cpu_session_component.parent_cpu_session()
.create_thread(pd, name, affinity, weight, utcb)),
.create_thread(pd, name, affinity, weight, utcb)
.convert<Thread_capability>(
[&] (Thread_capability cap) { return cap; },
[&] (auto) {
error("failed to create CPU thread");
return Thread_capability(); })),
_label(_cpu_session_component.session_label().string(), " -> ", thread_name),
_log_session_label("samples -> ", _label, ".", thread_id)
{

View File

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

View File

@ -17,14 +17,14 @@
using namespace Genode;
using namespace Cpu;
Thread_capability
Cpu_session::Create_thread_result
Cpu::Session::create_thread(Pd_session_capability const pd,
Name const &name_by_client,
Affinity::Location const location,
Weight const weight,
addr_t const utcb)
{
Thread_capability cap { };
Create_thread_result result = Create_thread_error::DENIED;
Name name = name_by_client;
if (!name.valid())
@ -33,9 +33,9 @@ Cpu::Session::create_thread(Pd_session_capability const pd,
/* quirk since init can't handle Out_of_* during first create_thread call */
if ((_reclaim_ram.value || _reclaim_cap.value) && _one_valid_thread()) {
if (_reclaim_ram.value)
throw Out_of_ram();
return Create_thread_error::OUT_OF_RAM;
if (_reclaim_cap.value)
throw Out_of_caps();
return Create_thread_error::OUT_OF_CAPS;
}
/* read in potential existing policy for thread */
@ -47,33 +47,39 @@ Cpu::Session::create_thread(Pd_session_capability const pd,
if (store_cap.valid())
return false;
cap = _parent.create_thread(pd, name, location, weight, utcb);
if (!cap.valid())
/* stop creation attempt by saying done */
return true;
result = _parent.create_thread(pd, name, location, weight, utcb);
return result.convert<bool>(
/* policy and name are set beforehand */
store_cap = cap;
[&] (Thread_capability cap) {
/* policy and name are set beforehand */
store_cap = cap;
/* for static case with valid location, don't overwrite config */
policy.thread_create(location);
/* for static case with valid location, don't overwrite config */
policy.thread_create(location);
if (_verbose)
log("[", _label, "] new thread at ",
policy.location.xpos(), "x", policy.location.ypos(),
", policy=", policy, ", name='", name, "'");
if (_verbose)
log("[", _label, "] new thread at ",
policy.location.xpos(), "x", policy.location.ypos(),
", policy=", policy, ", name='", name, "'");
return true;
return true;
},
[&] (Create_thread_error) {
/* stop creation attempt by saying done */
return true;
}
);
});
if (cap.valid()) {
if (result.ok()) {
_report = true;
return cap;
return result;
}
cap = _parent.create_thread(pd, name, location, weight, utcb);
if (!cap.valid())
return cap;
result = _parent.create_thread(pd, name, location, weight, utcb);
if (result.failed())
return result;
/* unknown thread without any configuration */
construct(_default_policy, [&](Thread_capability &store_cap,
@ -81,20 +87,24 @@ Cpu::Session::create_thread(Pd_session_capability const pd,
{
policy.location = location;
store_cap = cap;
store_name = name;
result.with_result(
[&] (Thread_capability cap) {
store_cap = cap;
store_name = name;
if (_verbose)
log("[", _label, "] new thread at ",
location.xpos(), "x", location.ypos(),
", no policy defined",
", name='", name, "'");
if (_verbose)
log("[", _label, "] new thread at ",
location.xpos(), "x", location.ypos(),
", no policy defined",
", name='", name, "'");
},
[&] (Create_thread_error) { });
});
if (cap.valid())
if (result.ok())
_report = true;
return cap;
return result;
}

View File

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

View File

@ -76,13 +76,29 @@ class Vmm::Vcpu_other_pd : public Vmm::Vcpu_thread
{
using namespace Genode;
Thread_capability vcpu_vm =
_cpu_connection->retry_with_upgrade(Ram_quota{8*1024}, Cap_quota{2},
[&] ()
{
return _cpu_connection->create_thread(_pd_cap, "vCPU", _location,
Cpu_session::Weight());
});
Thread_capability vcpu_vm { };
while (!vcpu_vm.valid()) {
bool denied = false;
using Error = Cpu_session::Create_thread_error;
_cpu_connection->create_thread(_pd_cap, "vCPU", _location,
Cpu_session::Weight()).with_result(
[&] (Thread_capability cap) { vcpu_vm = cap; },
[&] (Error e) {
if (e == Error::OUT_OF_RAM) _cpu_connection->upgrade_ram(8*1024);
else if (e == Error::OUT_OF_CAPS) _cpu_connection->upgrade_caps(2);
else
denied = true;
}
);
if (denied) {
error("Vcpu_other_pd: failed to create vCPU");
return;
}
}
/* tell parent that this will be a vCPU */
Cpu_session::Native_cpu::Thread_type thread_type { Cpu_session::Native_cpu::Thread_type::VCPU };

View File

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