mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-19 13:47:56 +00:00
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:
parent
e7f564cd3b
commit
d866b6b053
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 };
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -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(); });
|
||||
}
|
||||
|
@ -86,7 +86,6 @@ bool Platform_pd::bind_thread(Platform_thread &thread)
|
||||
return true;
|
||||
}
|
||||
|
||||
error("thread alloc failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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; }
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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; }
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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))
|
||||
{ }
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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) { });
|
||||
}
|
||||
|
||||
|
||||
|
@ -31,8 +31,6 @@
|
||||
|
||||
namespace Core {
|
||||
|
||||
typedef Cpu_session::Thread_creation_failed Invalid_thread;
|
||||
|
||||
class Pager_entrypoint;
|
||||
class Pager_object;
|
||||
class Exception_handlers;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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); }
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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;
|
||||
|
@ -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 **
|
||||
|
@ -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_ */
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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)"); }
|
||||
}
|
||||
|
||||
|
||||
|
@ -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))
|
||||
{ }
|
||||
|
||||
|
||||
|
@ -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; });
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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__); }
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 };
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user