mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-19 21:57:55 +00:00
core: tie Platform_thread to Platform_pd
This patch tightens the coupling of the 'Platform_thread' objects with their corresponding 'Platform_pd' objects by specifying the 'Platform_pd' as constructor argument, keeping the relationship as a reference (instead of a pointer), and constraining the lifetime of 'Platform_pd' objects to the lifetime of the PD. It thereby clears the way to simplify the thread creation since all PD-related information (like quota budgets) are now known at the construction time of the 'Platform_thread'. The return value of 'Platform_thread::start' has been removed because it is not evaluated by 'Cpu_thread_component'. Related to #5256
This commit is contained in:
parent
c18f7c7594
commit
d44ec53cd3
@ -21,7 +21,6 @@
|
||||
#include <base/allocator.h>
|
||||
|
||||
/* core includes */
|
||||
#include <platform_thread.h>
|
||||
#include <address_space.h>
|
||||
|
||||
/* L4/Fiasco includes */
|
||||
@ -36,6 +35,13 @@ namespace Core {
|
||||
|
||||
class Core::Platform_pd : public Address_space
|
||||
{
|
||||
public:
|
||||
|
||||
struct Thread_id { unsigned value; };
|
||||
|
||||
enum class Alloc_thread_id_error { EXHAUSTED };
|
||||
using Alloc_thread_id_result = Attempt<Thread_id, Alloc_thread_id_error>;
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
@ -60,35 +66,11 @@ class Core::Platform_pd : public Address_space
|
||||
Fiasco::l4_taskid_t _l4_task_id { }; /* L4 task ID */
|
||||
|
||||
|
||||
/**********************************************
|
||||
** Threads of this protection domain object **
|
||||
**********************************************/
|
||||
/***************************************
|
||||
** Threads of this protection domain **
|
||||
***************************************/
|
||||
|
||||
Platform_thread *_threads[THREAD_MAX];
|
||||
|
||||
/**
|
||||
* Initialize thread allocator
|
||||
*/
|
||||
void _init_threads();
|
||||
|
||||
/**
|
||||
* Thread iteration for one task
|
||||
*/
|
||||
Platform_thread *_next_thread();
|
||||
|
||||
/**
|
||||
* Thread allocation
|
||||
*
|
||||
* Again a special case for Core thread0.
|
||||
*/
|
||||
int _alloc_thread(int thread_id, Platform_thread &thread);
|
||||
|
||||
/**
|
||||
* Thread deallocation
|
||||
*
|
||||
* No special case for Core thread0 here - we just never call it.
|
||||
*/
|
||||
void _free_thread(int thread_id);
|
||||
Platform_thread *_threads[THREAD_MAX] { };
|
||||
|
||||
|
||||
/******************
|
||||
@ -179,18 +161,25 @@ class Core::Platform_pd : public Address_space
|
||||
static void init();
|
||||
|
||||
/**
|
||||
* Bind thread to protection domain
|
||||
*
|
||||
* \return true on success
|
||||
* Allocate PD-local ID for a new 'Platform_thread'
|
||||
*/
|
||||
bool bind_thread(Platform_thread &thread);
|
||||
Alloc_thread_id_result alloc_thread_id(Platform_thread &);
|
||||
|
||||
/**
|
||||
* Unbind thread from protection domain
|
||||
*
|
||||
* Free the thread's slot and update thread object.
|
||||
* Release PD-local thread ID at destruction of 'Platform_thread'
|
||||
*/
|
||||
void unbind_thread(Platform_thread &thread);
|
||||
void free_thread_id(Thread_id);
|
||||
|
||||
/**
|
||||
* Return L4 thread ID from the PD's task ID and the PD-local thread ID
|
||||
*/
|
||||
Fiasco::l4_threadid_t l4_thread_id(Thread_id const id) const
|
||||
{
|
||||
Fiasco::l4_threadid_t result = _l4_task_id;
|
||||
enum { LTHREAD_MASK = (1 << 7) - 1 };
|
||||
result.id.lthread = id.value & LTHREAD_MASK;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign parent interface to protection domain
|
||||
|
@ -44,85 +44,70 @@ class Core::Platform_thread : Interface
|
||||
Platform_thread(Platform_thread const &);
|
||||
Platform_thread &operator = (Platform_thread const &);
|
||||
|
||||
int _thread_id = THREAD_INVALID; /* plain thread number */
|
||||
using Name = String<32>;
|
||||
|
||||
Fiasco::l4_threadid_t _l4_thread_id;
|
||||
Name const _name; /* name to be registered at the kernel debugger */
|
||||
|
||||
Platform_pd &_pd;
|
||||
|
||||
using Id = Platform_pd::Alloc_thread_id_result;
|
||||
|
||||
Id const _id { _pd.alloc_thread_id(*this) };
|
||||
|
||||
typedef String<32> Name;
|
||||
Name const _name; /* thread name that will be
|
||||
registered at the kernel
|
||||
debugger */
|
||||
Platform_pd *_platform_pd = nullptr; /* protection domain thread
|
||||
is bound to */
|
||||
Pager_object *_pager = nullptr;
|
||||
|
||||
public:
|
||||
|
||||
enum {
|
||||
THREAD_INVALID = -1, /* invalid thread number */
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Platform_thread(size_t, const char *name, unsigned priority,
|
||||
Affinity::Location, addr_t utcb);
|
||||
Platform_thread(Platform_pd &pd, size_t, const char *name,
|
||||
unsigned, Affinity::Location, addr_t)
|
||||
: _name(name), _pd(pd) { }
|
||||
|
||||
/**
|
||||
* Constructor used for core-internal threads
|
||||
*/
|
||||
Platform_thread(const char *name);
|
||||
Platform_thread(Platform_pd &pd, const char *name)
|
||||
: _name(name), _pd(pd) { }
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~Platform_thread();
|
||||
|
||||
/**
|
||||
* Return false if thread IDs are exhausted
|
||||
*/
|
||||
bool valid() const { return _id.ok(); }
|
||||
|
||||
/**
|
||||
* Start thread
|
||||
*
|
||||
* \param ip instruction pointer to start at
|
||||
* \param sp stack pointer to use
|
||||
*
|
||||
* \retval 0 successful
|
||||
* \retval -1 thread could not be started
|
||||
*/
|
||||
int start(void *ip, void *sp);
|
||||
void start(void *ip, void *sp);
|
||||
|
||||
/**
|
||||
* Pause this thread
|
||||
*/
|
||||
void pause();
|
||||
void pause() { /* not implemented */ }
|
||||
|
||||
/**
|
||||
* Enable/disable single stepping
|
||||
*/
|
||||
void single_step(bool) { }
|
||||
void single_step(bool) { /* not implemented */ }
|
||||
|
||||
/**
|
||||
* Resume this thread
|
||||
*/
|
||||
void resume();
|
||||
|
||||
/**
|
||||
* This thread is about to be bound
|
||||
*
|
||||
* \param thread_id local thread ID
|
||||
* \param l4_thread_id final L4 thread ID
|
||||
* \param pd platform pd, thread is bound to
|
||||
*/
|
||||
void bind(int thread_id, Fiasco::l4_threadid_t l4_thread_id,
|
||||
Platform_pd &pd);
|
||||
|
||||
/**
|
||||
* Unbind this thread
|
||||
*/
|
||||
void unbind();
|
||||
void resume() { /* not implemented */ }
|
||||
|
||||
/**
|
||||
* Override thread state with 's'
|
||||
*/
|
||||
void state(Thread_state s);
|
||||
void state(Thread_state) { /* not implemented */ }
|
||||
|
||||
/**
|
||||
* Read thread state
|
||||
@ -163,7 +148,7 @@ class Core::Platform_thread : Interface
|
||||
* Return identification of thread when faulting
|
||||
*/
|
||||
unsigned long pager_object_badge() const {
|
||||
return convert_native_thread_id_to_badge(_l4_thread_id); }
|
||||
return convert_native_thread_id_to_badge(native_thread_id()); }
|
||||
|
||||
/**
|
||||
* Set CPU quota of the thread to 'quota'
|
||||
@ -180,9 +165,16 @@ class Core::Platform_thread : Interface
|
||||
** Fiasco-specific Accessors **
|
||||
*******************************/
|
||||
|
||||
int thread_id() const { return _thread_id; }
|
||||
Fiasco::l4_threadid_t native_thread_id() const { return _l4_thread_id; }
|
||||
Name name() const { return _name; }
|
||||
Fiasco::l4_threadid_t native_thread_id() const
|
||||
{
|
||||
using namespace Fiasco;
|
||||
return _id.convert<l4_threadid_t>(
|
||||
[&] (Platform_pd::Thread_id id) { return _pd.l4_thread_id(id); },
|
||||
[&] (Platform_pd::Alloc_thread_id_error) { return L4_INVALID_ID; }
|
||||
);
|
||||
}
|
||||
|
||||
Name name() const { return _name; }
|
||||
};
|
||||
|
||||
#endif /* _CORE__INCLUDE__PLATFORM_THREAD_H_ */
|
||||
|
@ -142,14 +142,13 @@ Core::Platform::Sigma0 &Core::Platform::sigma0()
|
||||
|
||||
Core::Platform::Core_pager::Core_pager(Platform_pd &core_pd)
|
||||
:
|
||||
Platform_thread("core.pager"),
|
||||
Platform_thread(core_pd, "core.pager"),
|
||||
Pager_object(Cpu_session_capability(), Thread_capability(),
|
||||
0, Affinity::Location(), Session_label(),
|
||||
Cpu_session::Name(name()))
|
||||
{
|
||||
Platform_thread::pager(sigma0());
|
||||
|
||||
core_pd.bind_thread(*this);
|
||||
cap(Capability_space::import(native_thread_id(), Rpc_obj_key()));
|
||||
|
||||
/* pager needs to know core's pd ID */
|
||||
@ -432,10 +431,9 @@ Core::Platform::Platform()
|
||||
* interface that allows us to specify the lthread number.
|
||||
*/
|
||||
Platform_thread &core_thread = *new (core_mem_alloc())
|
||||
Platform_thread("core.main");
|
||||
Platform_thread(*_core_pd, "core.main");
|
||||
|
||||
core_thread.pager(sigma0());
|
||||
_core_pd->bind_thread(core_thread);
|
||||
|
||||
/* we never call _core_thread.start(), so set name directly */
|
||||
fiasco_register_thread_name(core_thread.native_thread_id(),
|
||||
|
@ -37,7 +37,8 @@ static bool _init = false;
|
||||
|
||||
void Platform_pd::init()
|
||||
{
|
||||
if (_init) return;
|
||||
if (_init)
|
||||
return;
|
||||
|
||||
unsigned i;
|
||||
Pd_alloc reserved(true, true, 0);
|
||||
@ -52,10 +53,6 @@ void Platform_pd::init()
|
||||
}
|
||||
|
||||
|
||||
/****************************
|
||||
** Private object members **
|
||||
****************************/
|
||||
|
||||
void Platform_pd::_create_pd(bool syscall)
|
||||
{
|
||||
enum { TASK_ID_MASK = (1 << 11) - 1,
|
||||
@ -135,96 +132,27 @@ void Platform_pd::_free_pd()
|
||||
}
|
||||
|
||||
|
||||
void Platform_pd::_init_threads()
|
||||
Platform_pd::Alloc_thread_id_result Platform_pd::alloc_thread_id(Platform_thread &thread)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < THREAD_MAX; ++i)
|
||||
_threads[i] = 0;
|
||||
}
|
||||
|
||||
|
||||
Platform_thread* Platform_pd::_next_thread()
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
/* look for bound thread */
|
||||
for (i = 0; i < THREAD_MAX; ++i)
|
||||
if (_threads[i]) break;
|
||||
|
||||
/* no bound threads */
|
||||
if (i == THREAD_MAX) return 0;
|
||||
|
||||
return _threads[i];
|
||||
}
|
||||
|
||||
|
||||
int Platform_pd::_alloc_thread(int thread_id, Platform_thread &thread)
|
||||
{
|
||||
int i = thread_id;
|
||||
|
||||
/* look for free thread */
|
||||
if (thread_id == Platform_thread::THREAD_INVALID) {
|
||||
for (i = 0; i < THREAD_MAX; ++i)
|
||||
if (!_threads[i]) break;
|
||||
|
||||
/* no free threads available */
|
||||
if (i == THREAD_MAX) return -1;
|
||||
} else {
|
||||
if (_threads[i]) return -2;
|
||||
for (unsigned i = 0; i < THREAD_MAX; i++) {
|
||||
if (_threads[i] == nullptr) {
|
||||
_threads[i] = &thread;
|
||||
return Thread_id { i };
|
||||
}
|
||||
}
|
||||
|
||||
_threads[i] = &thread;
|
||||
|
||||
return i;
|
||||
return Alloc_thread_id_error::EXHAUSTED;
|
||||
}
|
||||
|
||||
|
||||
void Platform_pd::_free_thread(int thread_id)
|
||||
void Platform_pd::free_thread_id(Thread_id const id)
|
||||
{
|
||||
if (!_threads[thread_id])
|
||||
warning("double-free of thread ", Hex(_pd_id), ".", Hex(thread_id), " detected");
|
||||
if (id.value >= THREAD_MAX)
|
||||
return;
|
||||
|
||||
_threads[thread_id] = 0;
|
||||
}
|
||||
if (!_threads[id.value])
|
||||
warning("double-free of thread ", Hex(_pd_id), ".", Hex(id.value), " detected");
|
||||
|
||||
|
||||
/***************************
|
||||
** Public object members **
|
||||
***************************/
|
||||
|
||||
bool Platform_pd::bind_thread(Platform_thread &thread)
|
||||
{
|
||||
/* thread_id is THREAD_INVALID by default - only core is the special case */
|
||||
int thread_id = thread.thread_id();
|
||||
l4_threadid_t l4_thread_id;
|
||||
|
||||
int t = _alloc_thread(thread_id, thread);
|
||||
if (t < 0)
|
||||
return false;
|
||||
|
||||
thread_id = t;
|
||||
|
||||
enum { LTHREAD_MASK = (1 << 7) - 1 };
|
||||
|
||||
l4_thread_id = _l4_task_id;
|
||||
l4_thread_id.id.lthread = thread_id & LTHREAD_MASK;
|
||||
|
||||
/* finally inform thread about binding */
|
||||
thread.bind(thread_id, l4_thread_id, *this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Platform_pd::unbind_thread(Platform_thread &thread)
|
||||
{
|
||||
int thread_id = thread.thread_id();
|
||||
|
||||
/* unbind thread before proceeding */
|
||||
thread.unbind();
|
||||
|
||||
_free_thread(thread_id);
|
||||
_threads[id.value] = nullptr;
|
||||
}
|
||||
|
||||
|
||||
@ -244,15 +172,13 @@ void Platform_pd::flush(addr_t, size_t size, Core_local_addr core_local_base)
|
||||
L4_FP_FLUSH_PAGE);
|
||||
}
|
||||
|
||||
|
||||
Platform_pd::Platform_pd(Allocator &, char const *)
|
||||
{
|
||||
/* check correct init */
|
||||
if (!_init)
|
||||
panic("init pd facility via Platform_pd::init() before using it!");
|
||||
|
||||
/* init threads */
|
||||
_init_threads();
|
||||
|
||||
int ret = _alloc_pd(PD_INVALID);
|
||||
if (ret < 0) {
|
||||
panic("pd alloc failed");
|
||||
@ -268,9 +194,6 @@ Platform_pd::Platform_pd(char const *, signed pd_id)
|
||||
if (!_init)
|
||||
panic("init pd facility via Platform_pd::init() before using it!");
|
||||
|
||||
/* init threads */
|
||||
_init_threads();
|
||||
|
||||
int ret = _alloc_pd(pd_id);
|
||||
if (ret < 0) {
|
||||
panic("pd alloc failed");
|
||||
@ -282,10 +205,11 @@ Platform_pd::Platform_pd(char const *, signed pd_id)
|
||||
|
||||
Platform_pd::~Platform_pd()
|
||||
{
|
||||
/* unbind all threads */
|
||||
while (Platform_thread *t = _next_thread()) unbind_thread(*t);
|
||||
bool any_thread_exists = false;
|
||||
for (Platform_thread *t : _threads) any_thread_exists |= (t != nullptr);
|
||||
if (any_thread_exists)
|
||||
error("attempt to destruct platform PD before threads");
|
||||
|
||||
_destroy_pd();
|
||||
_free_pd();
|
||||
}
|
||||
|
||||
|
@ -30,10 +30,13 @@ using namespace Core;
|
||||
using namespace Fiasco;
|
||||
|
||||
|
||||
int Platform_thread::start(void *ip, void *sp)
|
||||
void Platform_thread::start(void *ip, void *sp)
|
||||
{
|
||||
if (_id.failed())
|
||||
return;
|
||||
|
||||
l4_umword_t dummy, old_eflags;
|
||||
l4_threadid_t thread = _l4_thread_id;
|
||||
l4_threadid_t thread = native_thread_id();
|
||||
l4_threadid_t pager = _pager
|
||||
? Capability_space::ipc_cap_data(_pager->cap()).dst
|
||||
: L4_INVALID_ID;
|
||||
@ -45,38 +48,47 @@ int Platform_thread::start(void *ip, void *sp)
|
||||
&old_eflags, &dummy, &dummy,
|
||||
0, l4_utcb_get());
|
||||
if (old_eflags == ~0UL)
|
||||
warning("old eflags == ~0 on ex_regs ",
|
||||
warning("start ", _name, ": old eflags == ~0 on ex_regs ",
|
||||
Hex(thread.id.task), ".", Hex(thread.id.lthread));
|
||||
|
||||
fiasco_register_thread_name(thread, _name.string());
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void Platform_thread::pause()
|
||||
Thread_state Platform_thread::state()
|
||||
{
|
||||
warning(__func__, " not implemented");
|
||||
Thread_state s { };
|
||||
|
||||
l4_umword_t old_eflags, ip, sp;
|
||||
l4_threadid_t thread = native_thread_id();
|
||||
l4_threadid_t pager = L4_INVALID_ID;
|
||||
l4_threadid_t preempter = L4_INVALID_ID;
|
||||
l4_threadid_t cap_handler = L4_INVALID_ID;
|
||||
|
||||
l4_inter_task_ex_regs(thread, ~0UL, ~0UL,
|
||||
&preempter, &pager, &cap_handler,
|
||||
&old_eflags, &ip, &sp,
|
||||
L4_THREAD_EX_REGS_NO_CANCEL, l4_utcb_get());
|
||||
if (old_eflags == ~0UL)
|
||||
warning("state old eflags == ~0 on ex_regs ",
|
||||
Hex(thread.id.task), ".", Hex(thread.id.lthread));
|
||||
|
||||
/* fill thread state structure */
|
||||
s.cpu.ip = ip;
|
||||
s.cpu.sp = sp;
|
||||
s.state = Thread_state::State::VALID;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
void Platform_thread::resume()
|
||||
Platform_thread::~Platform_thread()
|
||||
{
|
||||
warning(__func__, " not implemented");
|
||||
}
|
||||
if (_id.failed())
|
||||
return;
|
||||
|
||||
|
||||
void Platform_thread::bind(int thread_id, l4_threadid_t l4_thread_id, Platform_pd &pd)
|
||||
{
|
||||
_thread_id = thread_id;
|
||||
_l4_thread_id = l4_thread_id;
|
||||
_platform_pd = &pd;
|
||||
}
|
||||
|
||||
|
||||
void Platform_thread::unbind()
|
||||
{
|
||||
l4_umword_t dummy, old_eflags;
|
||||
l4_threadid_t thread = _l4_thread_id;
|
||||
l4_threadid_t thread = native_thread_id();
|
||||
l4_threadid_t pager = thread;
|
||||
l4_threadid_t preempter = L4_INVALID_ID;
|
||||
l4_threadid_t cap_handler = L4_INVALID_ID;
|
||||
@ -93,60 +105,10 @@ void Platform_thread::unbind()
|
||||
&old_eflags, &dummy, &dummy,
|
||||
0, l4_utcb_get());
|
||||
if (old_eflags == ~0UL)
|
||||
warning("old eflags == ~0 on ex_regs ",
|
||||
warning("unbind old eflags == ~0 on ex_regs ",
|
||||
Hex(thread.id.task), ".", Hex(thread.id.lthread));
|
||||
|
||||
_thread_id = THREAD_INVALID;
|
||||
_l4_thread_id = L4_INVALID_ID;
|
||||
_platform_pd = 0;
|
||||
}
|
||||
|
||||
|
||||
void Platform_thread::state(Thread_state) { }
|
||||
|
||||
|
||||
Thread_state Platform_thread::state()
|
||||
{
|
||||
Thread_state s { };
|
||||
|
||||
l4_umword_t old_eflags, ip, sp;
|
||||
l4_threadid_t thread = _l4_thread_id;
|
||||
l4_threadid_t pager = L4_INVALID_ID;
|
||||
l4_threadid_t preempter = L4_INVALID_ID;
|
||||
l4_threadid_t cap_handler = L4_INVALID_ID;
|
||||
|
||||
l4_inter_task_ex_regs(thread, ~0UL, ~0UL,
|
||||
&preempter, &pager, &cap_handler,
|
||||
&old_eflags, &ip, &sp,
|
||||
L4_THREAD_EX_REGS_NO_CANCEL, l4_utcb_get());
|
||||
if (old_eflags == ~0UL)
|
||||
warning("old eflags == ~0 on ex_regs ",
|
||||
Hex(thread.id.task), ".", Hex(thread.id.lthread));
|
||||
|
||||
/* fill thread state structure */
|
||||
s.cpu.ip = ip;
|
||||
s.cpu.sp = sp;
|
||||
s.state = Thread_state::State::VALID;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
Platform_thread::Platform_thread(size_t, const char *name, unsigned,
|
||||
Affinity::Location, addr_t)
|
||||
: _l4_thread_id(L4_INVALID_ID), _name(name) { }
|
||||
|
||||
|
||||
Platform_thread::Platform_thread(const char *name)
|
||||
: _l4_thread_id(L4_INVALID_ID), _name(name) { }
|
||||
|
||||
|
||||
Platform_thread::~Platform_thread()
|
||||
{
|
||||
/*
|
||||
* We inform our protection domain about thread destruction, which will end up in
|
||||
* Thread::unbind()
|
||||
*/
|
||||
if (_platform_pd)
|
||||
_platform_pd->unbind_thread(*this);
|
||||
_id.with_result(
|
||||
[&] (Platform_pd::Thread_id id) { _pd.free_thread_id(id); },
|
||||
[&] (Platform_pd::Alloc_thread_id_error) { });
|
||||
}
|
||||
|
@ -38,9 +38,7 @@ Thread::Start_result Thread::start()
|
||||
{
|
||||
/* create and start platform thread */
|
||||
native_thread().pt = new (platform().core_mem_alloc())
|
||||
Platform_thread(_stack->name().string());
|
||||
|
||||
platform_specific().core_pd().bind_thread(*native_thread().pt);
|
||||
Platform_thread(platform_specific().core_pd(), _stack->name().string());
|
||||
|
||||
native_thread().pt->pager(platform_specific().core_pager());
|
||||
native_thread().l4id = native_thread().pt->native_thread_id();
|
||||
|
@ -60,6 +60,7 @@ class Core::Platform_thread : Interface
|
||||
Platform_pd *_platform_pd; /* protection domain thread is bound to */
|
||||
Pager_object *_pager_obj;
|
||||
unsigned _prio;
|
||||
bool _bound_to_pd = false;
|
||||
|
||||
Affinity::Location _location { };
|
||||
|
||||
@ -74,7 +75,7 @@ class Core::Platform_thread : Interface
|
||||
/**
|
||||
* Constructor for non-core threads
|
||||
*/
|
||||
Platform_thread(size_t, const char *name, unsigned priority,
|
||||
Platform_thread(Platform_pd &, size_t, const char *name, unsigned priority,
|
||||
Affinity::Location, addr_t);
|
||||
|
||||
/**
|
||||
@ -93,16 +94,18 @@ class Core::Platform_thread : Interface
|
||||
*/
|
||||
~Platform_thread();
|
||||
|
||||
/**
|
||||
* Return true if thread creation succeeded
|
||||
*/
|
||||
bool valid() const { return _bound_to_pd; }
|
||||
|
||||
/**
|
||||
* Start thread
|
||||
*
|
||||
* \param ip instruction pointer to start at
|
||||
* \param sp stack pointer to use
|
||||
*
|
||||
* \retval 0 successful
|
||||
* \retval -1 thread could not be started
|
||||
*/
|
||||
int start(void *ip, void *sp);
|
||||
void start(void *ip, void *sp);
|
||||
|
||||
/**
|
||||
* Pause this thread
|
||||
|
@ -38,7 +38,7 @@ Trace::Execution_time Platform_thread::execution_time() const
|
||||
}
|
||||
|
||||
|
||||
int Platform_thread::start(void *ip, void *sp)
|
||||
void Platform_thread::start(void *ip, void *sp)
|
||||
{
|
||||
if (!_platform_pd) {
|
||||
|
||||
@ -62,7 +62,7 @@ int Platform_thread::start(void *ip, void *sp)
|
||||
if (l4_msgtag_has_error(tag)) {
|
||||
warning("l4_thread_control_commit for ",
|
||||
Hex(_thread.local.data()->kcap()), " failed!");
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
|
||||
_state = RUNNING;
|
||||
@ -72,10 +72,8 @@ int Platform_thread::start(void *ip, void *sp)
|
||||
(l4_addr_t) sp, 0);
|
||||
if (l4_msgtag_has_error(tag)) {
|
||||
warning("l4_thread_ex_regs failed!");
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -280,7 +278,7 @@ void Platform_thread::_finalize_construction()
|
||||
}
|
||||
|
||||
|
||||
Platform_thread::Platform_thread(size_t, const char *name, unsigned prio,
|
||||
Platform_thread::Platform_thread(Platform_pd &pd, size_t, const char *name, unsigned prio,
|
||||
Affinity::Location location, addr_t)
|
||||
:
|
||||
_name(name),
|
||||
@ -298,6 +296,7 @@ Platform_thread::Platform_thread(size_t, const char *name, unsigned prio,
|
||||
_create_thread();
|
||||
_finalize_construction();
|
||||
affinity(location);
|
||||
_bound_to_pd = pd.bind_thread(*this);
|
||||
}
|
||||
|
||||
|
||||
|
@ -67,8 +67,8 @@ void Pager_object::unresolved_page_fault_occurred() { }
|
||||
void Pager_object::print(Output &out) const
|
||||
{
|
||||
Platform_thread * const pt = (Platform_thread *)badge();
|
||||
if (pt && pt->pd())
|
||||
Genode::print(out, "pager_object: pd='", pt->pd()->label(),
|
||||
if (pt)
|
||||
Genode::print(out, "pager_object: pd='", pt->pd().label(),
|
||||
"' thread='", pt->label(), "'");
|
||||
}
|
||||
|
||||
|
@ -154,16 +154,6 @@ void Cap_space::upgrade_slab(Allocator &alloc)
|
||||
** Platform_pd implementation **
|
||||
********************************/
|
||||
|
||||
bool Platform_pd::bind_thread(Platform_thread &t)
|
||||
{
|
||||
/* is this the first and therefore main thread in this PD? */
|
||||
bool main_thread = !_thread_associated;
|
||||
_thread_associated = true;
|
||||
t.join_pd(this, main_thread, Address_space::weak_ptr());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Platform_pd::assign_parent(Native_capability parent)
|
||||
{
|
||||
if (!_parent.valid() && parent.valid())
|
||||
|
@ -195,6 +195,8 @@ class Core::Platform_pd : public Hw::Address_space, private Cap_space
|
||||
|
||||
public:
|
||||
|
||||
bool has_any_thread = false;
|
||||
|
||||
/**
|
||||
* Constructor used for objects other than the Core PD
|
||||
*
|
||||
|
@ -62,7 +62,7 @@ void Platform_thread::quota(size_t const quota)
|
||||
Platform_thread::Platform_thread(Label const &label, Native_utcb &utcb)
|
||||
:
|
||||
_label(label),
|
||||
_pd(&_kernel_main_get_core_platform_pd()),
|
||||
_pd(_kernel_main_get_core_platform_pd()),
|
||||
_pager(nullptr),
|
||||
_utcb_core_addr(&utcb),
|
||||
_utcb_pd_addr(&utcb),
|
||||
@ -86,19 +86,20 @@ Platform_thread::Platform_thread(Label const &label, Native_utcb &utcb)
|
||||
}
|
||||
|
||||
|
||||
Platform_thread::Platform_thread(size_t const quota,
|
||||
Platform_thread::Platform_thread(Platform_pd &pd,
|
||||
size_t const quota,
|
||||
Label const &label,
|
||||
unsigned const virt_prio,
|
||||
Affinity::Location const location,
|
||||
addr_t const utcb)
|
||||
:
|
||||
_label(label),
|
||||
_pd(nullptr),
|
||||
_pd(pd),
|
||||
_pager(nullptr),
|
||||
_utcb_pd_addr((Native_utcb *)utcb),
|
||||
_priority(_scale_priority(virt_prio)),
|
||||
_quota((unsigned)quota),
|
||||
_main_thread(false),
|
||||
_main_thread(!pd.has_any_thread),
|
||||
_location(location),
|
||||
_kobj(_kobj.CALLED_FROM_CORE, _priority, _quota, _label.string())
|
||||
{
|
||||
@ -116,22 +117,9 @@ Platform_thread::Platform_thread(size_t const quota,
|
||||
_utcb_core_addr = (Native_utcb *)range.start; },
|
||||
[&] (Region_map::Attach_error) {
|
||||
error("failed to attach UTCB of new thread within core"); });
|
||||
}
|
||||
|
||||
|
||||
void Platform_thread::join_pd(Platform_pd * pd, bool const main_thread,
|
||||
Weak_ptr<Address_space> address_space)
|
||||
{
|
||||
/* check if thread is already in another protection domain */
|
||||
if (_pd && _pd != pd) {
|
||||
error("thread already in another protection domain");
|
||||
return;
|
||||
}
|
||||
|
||||
/* join protection domain */
|
||||
_pd = pd;
|
||||
_main_thread = main_thread;
|
||||
_address_space = address_space;
|
||||
_address_space = pd.weak_ptr();
|
||||
pd.has_any_thread = true;
|
||||
}
|
||||
|
||||
|
||||
@ -144,7 +132,7 @@ void Platform_thread::affinity(Affinity::Location const &)
|
||||
Affinity::Location Platform_thread::affinity() const { return _location; }
|
||||
|
||||
|
||||
int Platform_thread::start(void * const ip, void * const sp)
|
||||
void Platform_thread::start(void * const ip, void * const sp)
|
||||
{
|
||||
/* attach UTCB in case of a main thread */
|
||||
if (_main_thread) {
|
||||
@ -168,7 +156,8 @@ int Platform_thread::start(void * const ip, void * const sp)
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
if (core_env().entrypoint().apply(_utcb, lambda)) return -1;
|
||||
if (core_env().entrypoint().apply(_utcb, lambda))
|
||||
return;
|
||||
}
|
||||
|
||||
/* initialize thread registers */
|
||||
@ -176,11 +165,6 @@ int Platform_thread::start(void * const ip, void * const sp)
|
||||
_kobj->regs->sp = reinterpret_cast<addr_t>(sp);
|
||||
|
||||
/* start executing new thread */
|
||||
if (!_pd) {
|
||||
error("no protection domain associated!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned const cpu = _location.xpos();
|
||||
|
||||
Native_utcb &utcb = *Thread::myself()->utcb();
|
||||
@ -189,11 +173,10 @@ int Platform_thread::start(void * const ip, void * const sp)
|
||||
utcb.cap_cnt(0);
|
||||
utcb.cap_add(Capability_space::capid(_kobj.cap()));
|
||||
if (_main_thread) {
|
||||
utcb.cap_add(Capability_space::capid(_pd->parent()));
|
||||
utcb.cap_add(Capability_space::capid(_pd.parent()));
|
||||
utcb.cap_add(Capability_space::capid(_utcb));
|
||||
}
|
||||
Kernel::start_thread(*_kobj, cpu, _pd->kernel_pd(), *_utcb_core_addr);
|
||||
return 0;
|
||||
Kernel::start_thread(*_kobj, cpu, _pd.kernel_pd(), *_utcb_core_addr);
|
||||
}
|
||||
|
||||
|
||||
|
@ -56,7 +56,7 @@ class Core::Platform_thread : Noncopyable
|
||||
typedef String<32> Label;
|
||||
|
||||
Label const _label;
|
||||
Platform_pd * _pd;
|
||||
Platform_pd &_pd;
|
||||
Weak_ptr<Address_space> _address_space { };
|
||||
Pager_object * _pager;
|
||||
Native_utcb * _utcb_core_addr { }; /* UTCB addr in core */
|
||||
@ -115,7 +115,7 @@ class Core::Platform_thread : Noncopyable
|
||||
* \param virt_prio unscaled processor-scheduling priority
|
||||
* \param utcb core local pointer to userland stack
|
||||
*/
|
||||
Platform_thread(size_t const quota, Label const &label,
|
||||
Platform_thread(Platform_pd &, size_t const quota, Label const &label,
|
||||
unsigned const virt_prio, Affinity::Location,
|
||||
addr_t const utcb);
|
||||
|
||||
@ -124,6 +124,11 @@ class Core::Platform_thread : Noncopyable
|
||||
*/
|
||||
~Platform_thread();
|
||||
|
||||
/**
|
||||
* Return true if thread creation succeeded
|
||||
*/
|
||||
bool valid() const { return true; }
|
||||
|
||||
/**
|
||||
* Return information about current exception state
|
||||
*
|
||||
@ -145,24 +150,13 @@ class Core::Platform_thread : Noncopyable
|
||||
*/
|
||||
Kernel::Thread_fault fault_info() { return _kobj->fault(); }
|
||||
|
||||
/**
|
||||
* Join a protection domain
|
||||
*
|
||||
* \param main_thread whether thread is the first in protection domain
|
||||
*
|
||||
* This function has no effect when called more twice for a
|
||||
* given thread.
|
||||
*/
|
||||
void join_pd(Platform_pd *const pd, bool const main_thread,
|
||||
Weak_ptr<Address_space> address_space);
|
||||
|
||||
/**
|
||||
* Run this thread
|
||||
*
|
||||
* \param ip initial instruction pointer
|
||||
* \param sp initial stack pointer
|
||||
*/
|
||||
int start(void * const ip, void * const sp);
|
||||
void start(void *ip, void *sp);
|
||||
|
||||
void restart();
|
||||
|
||||
@ -245,7 +239,7 @@ class Core::Platform_thread : Noncopyable
|
||||
|
||||
Pager_object &pager();
|
||||
|
||||
Platform_pd * pd() const { return _pd; }
|
||||
Platform_pd &pd() const { return _pd; }
|
||||
|
||||
Ram_dataspace_capability utcb() const { return _utcb; }
|
||||
};
|
||||
|
@ -47,7 +47,7 @@ void Pager_entrypoint::entry()
|
||||
Kernel::Thread::Exception_state::EXCEPTION) {
|
||||
if (!po->submit_exception_signal())
|
||||
warning("unresolvable exception: "
|
||||
"pd='", pt->pd()->label(), "', "
|
||||
"pd='", pt->pd().label(), "', "
|
||||
"thread='", pt->label(), "', "
|
||||
"ip=", Hex(pt->state().cpu.ip));
|
||||
continue;
|
||||
|
@ -35,10 +35,7 @@ namespace Hw { extern Untyped_capability _main_thread_cap; }
|
||||
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 Start_result::DENIED;
|
||||
}
|
||||
native_thread().platform_thread->start((void *)&_thread_start, stack_top());
|
||||
|
||||
if (_thread_cap.failed())
|
||||
return Start_result::DENIED;
|
||||
|
@ -32,8 +32,6 @@ struct Core::Platform_pd
|
||||
{
|
||||
Platform_pd(Allocator &, char const *) { }
|
||||
|
||||
bool bind_thread(Platform_thread &) { return true; }
|
||||
|
||||
void assign_parent(Capability<Parent>) { }
|
||||
};
|
||||
|
||||
|
@ -17,13 +17,17 @@
|
||||
/* Genode includes */
|
||||
#include <base/thread_state.h>
|
||||
#include <base/trace/types.h>
|
||||
#include <base/registry.h>
|
||||
#include <base/weak_ptr.h>
|
||||
#include <cpu_session/cpu_session.h>
|
||||
|
||||
/* core includes */
|
||||
#include <pager.h>
|
||||
|
||||
namespace Core { class Platform_thread; }
|
||||
namespace Core {
|
||||
class Platform_thread;
|
||||
class Platform_pd;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@ -34,32 +38,17 @@ namespace Core { class Platform_thread; }
|
||||
* turn, we find the exception handler's 'Signal_context_capability'.
|
||||
*/
|
||||
|
||||
class Core::Platform_thread : public List<Platform_thread>::Element
|
||||
class Core::Platform_thread : Noncopyable
|
||||
{
|
||||
using Location = Affinity::Location;
|
||||
using Execution_time = Trace::Execution_time;
|
||||
|
||||
private:
|
||||
|
||||
struct Registry
|
||||
{
|
||||
Mutex _mutex { };
|
||||
List<Platform_thread> _list { };
|
||||
|
||||
void insert(Platform_thread *thread);
|
||||
void remove(Platform_thread *thread);
|
||||
|
||||
/**
|
||||
* Trigger exception handler for 'Platform_thread' with matching PID.
|
||||
*/
|
||||
void submit_exception(unsigned long pid);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return singleton instance of 'Platform_thread::Registry'
|
||||
*/
|
||||
static Registry &_registry();
|
||||
|
||||
unsigned long _tid = -1;
|
||||
unsigned long _pid = -1;
|
||||
char _name[32] { };
|
||||
|
||||
String<32> const _name;
|
||||
|
||||
/*
|
||||
* Dummy pager object that is solely used for storing the
|
||||
@ -67,84 +56,60 @@ class Core::Platform_thread : public List<Platform_thread>::Element
|
||||
*/
|
||||
Pager_object _pager { };
|
||||
|
||||
/**
|
||||
* Singleton instance of platform-thread registry used to deliver
|
||||
* exceptions.
|
||||
*/
|
||||
static Registry<Platform_thread> &_registry();
|
||||
|
||||
Registry<Platform_thread>::Element _elem { _registry(), *this };
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Platform_thread(size_t, const char *name, unsigned priority,
|
||||
Affinity::Location, addr_t);
|
||||
|
||||
~Platform_thread();
|
||||
Platform_thread(Platform_pd &, size_t, auto const &name, auto...)
|
||||
: _name(name) { }
|
||||
|
||||
/**
|
||||
* Pause this thread
|
||||
* Return true if thread creation succeeded
|
||||
*/
|
||||
void pause();
|
||||
bool valid() const { return true; }
|
||||
|
||||
const char *name() { return _name.string(); }
|
||||
|
||||
/**
|
||||
* Enable/disable single stepping
|
||||
* Notify Genode::Signal handler about sigchld
|
||||
*/
|
||||
void single_step(bool) { }
|
||||
|
||||
/**
|
||||
* Resume this thread
|
||||
*/
|
||||
void resume();
|
||||
|
||||
/**
|
||||
* Dummy implementation of platform-thread interface
|
||||
*/
|
||||
Pager_object &pager() { return _pager; }
|
||||
void pager(Pager_object &) { }
|
||||
int start(void *, void *) { return 0; }
|
||||
|
||||
Thread_state state()
|
||||
{
|
||||
return { .state = Thread_state::State::UNAVAILABLE, .cpu = { } };
|
||||
}
|
||||
|
||||
void state(Thread_state) { }
|
||||
|
||||
const char *name() { return _name; }
|
||||
|
||||
/**
|
||||
* Set the executing CPU for this thread
|
||||
*
|
||||
* SMP is currently not directly supported on Genode/Linux
|
||||
* (but indirectly by the Linux kernel).
|
||||
*/
|
||||
void affinity(Affinity::Location) { }
|
||||
|
||||
/**
|
||||
* Request the affinity of this thread
|
||||
*/
|
||||
Affinity::Location affinity() const { return Affinity::Location(); }
|
||||
static void submit_exception(unsigned pid);
|
||||
|
||||
/**
|
||||
* Register process ID and thread ID of thread
|
||||
*/
|
||||
void thread_id(int pid, int tid) { _pid = pid, _tid = tid; }
|
||||
|
||||
/**
|
||||
* Notify Genode::Signal handler about sigchld
|
||||
/*
|
||||
* Part of the platform-thread interface that is not used on Linux
|
||||
*/
|
||||
static void submit_exception(int pid)
|
||||
|
||||
void pause() { };
|
||||
void single_step(bool) { }
|
||||
void resume() { }
|
||||
Pager_object &pager() { return _pager; }
|
||||
void pager(Pager_object &) { }
|
||||
void start(void *, void *) { }
|
||||
void affinity(Location) { }
|
||||
Location affinity() const { return { }; }
|
||||
void quota(size_t) { }
|
||||
void state(Thread_state) { }
|
||||
Execution_time execution_time() const { return { 0, 0 }; }
|
||||
unsigned long pager_object_badge() const { return 0; }
|
||||
|
||||
Thread_state state()
|
||||
{
|
||||
_registry().submit_exception(pid);
|
||||
return { .state = Thread_state::State::UNAVAILABLE, .cpu = { } };
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CPU quota of the thread to 'quota'
|
||||
*/
|
||||
void quota(size_t const) { /* not supported*/ }
|
||||
|
||||
/**
|
||||
* Return execution time consumed by the thread
|
||||
*/
|
||||
Trace::Execution_time execution_time() const { return { 0, 0 }; }
|
||||
|
||||
unsigned long pager_object_badge() const { return 0; }
|
||||
};
|
||||
|
||||
#endif /* _CORE__INCLUDE__PLATFORM_THREAD_H_ */
|
||||
|
@ -22,80 +22,24 @@
|
||||
using namespace Core;
|
||||
|
||||
|
||||
typedef Token<Scanner_policy_identifier_with_underline> Tid_token;
|
||||
|
||||
|
||||
/*******************************
|
||||
** Platform_thread::Registry **
|
||||
*******************************/
|
||||
|
||||
void Platform_thread::Registry::insert(Platform_thread *thread)
|
||||
void Platform_thread::submit_exception(unsigned pid)
|
||||
{
|
||||
Mutex::Guard guard(_mutex);
|
||||
_list.insert(thread);
|
||||
}
|
||||
|
||||
|
||||
void Platform_thread::Registry::remove(Platform_thread *thread)
|
||||
{
|
||||
Mutex::Guard guard(_mutex);
|
||||
_list.remove(thread);
|
||||
}
|
||||
|
||||
|
||||
void Platform_thread::Registry::submit_exception(unsigned long pid)
|
||||
{
|
||||
Mutex::Guard guard(_mutex);
|
||||
|
||||
/* traverse list to find 'Platform_thread' with matching PID */
|
||||
for (Platform_thread *curr = _list.first(); curr; curr = curr->next()) {
|
||||
|
||||
if (curr->_tid == pid) {
|
||||
Signal_context_capability sigh = curr->_pager._sigh;
|
||||
|
||||
if (sigh.valid())
|
||||
Signal_transmitter(sigh).submit();
|
||||
|
||||
bool submitted = false;
|
||||
_registry().for_each([&] (Platform_thread const &thread) {
|
||||
if (submitted || thread._tid != pid)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Signal_context_capability sigh = thread._pager._sigh;
|
||||
if (sigh.valid())
|
||||
Signal_transmitter(sigh).submit();
|
||||
|
||||
submitted = true;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Platform_thread::Registry &Platform_thread::_registry()
|
||||
Registry<Platform_thread> &Platform_thread::_registry()
|
||||
{
|
||||
static Platform_thread::Registry registry;
|
||||
static Registry<Platform_thread> registry { };
|
||||
return registry;
|
||||
}
|
||||
|
||||
|
||||
/*********************
|
||||
** Platform_thread **
|
||||
*********************/
|
||||
|
||||
Platform_thread::Platform_thread(size_t, const char *name, unsigned,
|
||||
Affinity::Location, addr_t)
|
||||
{
|
||||
copy_cstring(_name, name, min(sizeof(_name), Genode::strlen(name) + 1));
|
||||
|
||||
_registry().insert(this);
|
||||
}
|
||||
|
||||
|
||||
Platform_thread::~Platform_thread()
|
||||
{
|
||||
_registry().remove(this);
|
||||
}
|
||||
|
||||
|
||||
void Platform_thread::pause()
|
||||
{
|
||||
warning(__func__, "not implemented");
|
||||
}
|
||||
|
||||
|
||||
void Platform_thread::resume()
|
||||
{
|
||||
warning(__func__, "not implemented");
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,6 @@ class Core::Platform_pd : public Address_space
|
||||
private:
|
||||
|
||||
Native_capability _parent { };
|
||||
int _thread_cnt;
|
||||
addr_t const _pd_sel;
|
||||
const char * _label;
|
||||
|
||||
@ -42,6 +41,8 @@ class Core::Platform_pd : public Address_space
|
||||
|
||||
public:
|
||||
|
||||
bool has_any_threads = false;
|
||||
|
||||
/**
|
||||
* Constructors
|
||||
*/
|
||||
@ -53,18 +54,6 @@ class Core::Platform_pd : public Address_space
|
||||
*/
|
||||
~Platform_pd();
|
||||
|
||||
/**
|
||||
* Bind thread to protection domain
|
||||
*/
|
||||
bool bind_thread(Platform_thread &thread);
|
||||
|
||||
/**
|
||||
* Unbind thread from protection domain
|
||||
*
|
||||
* Free the thread's slot and update thread object.
|
||||
*/
|
||||
void unbind_thread(Platform_thread &thread);
|
||||
|
||||
/**
|
||||
* Assign parent interface to protection domain
|
||||
*/
|
||||
|
@ -39,7 +39,7 @@ class Core::Platform_thread
|
||||
{
|
||||
private:
|
||||
|
||||
Platform_pd *_pd;
|
||||
Platform_pd &_pd;
|
||||
Pager_object *_pager;
|
||||
addr_t _id_base;
|
||||
addr_t _sel_exc_base;
|
||||
@ -93,7 +93,7 @@ class Core::Platform_thread
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Platform_thread(size_t quota, char const *name,
|
||||
Platform_thread(Platform_pd &, size_t quota, char const *name,
|
||||
unsigned priority,
|
||||
Affinity::Location affinity,
|
||||
addr_t utcb);
|
||||
@ -103,16 +103,18 @@ class Core::Platform_thread
|
||||
*/
|
||||
~Platform_thread();
|
||||
|
||||
/**
|
||||
* Return true if thread creation succeeded
|
||||
*/
|
||||
bool valid() const { return true; }
|
||||
|
||||
/**
|
||||
* Start thread
|
||||
*
|
||||
* \param ip instruction pointer to start at
|
||||
* \param sp stack pointer to use
|
||||
*
|
||||
* \retval 0 successful
|
||||
* \retval -1 thread/vCPU could not be started
|
||||
* \param ip instruction pointer to start at
|
||||
* \param sp stack pointer to use
|
||||
*/
|
||||
int start(void *ip, void *sp);
|
||||
void start(void *ip, void *sp);
|
||||
|
||||
/**
|
||||
* Pause this thread
|
||||
@ -200,16 +202,6 @@ class Core::Platform_thread
|
||||
*/
|
||||
const char *pd_name() const;
|
||||
|
||||
/**
|
||||
* Associate thread with protection domain
|
||||
*/
|
||||
void bind_to_pd(Platform_pd *pd, bool main_thread)
|
||||
{
|
||||
_pd = pd;
|
||||
|
||||
if (main_thread) _features |= MAIN_THREAD;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CPU quota of the thread to 'quota'
|
||||
*/
|
||||
|
@ -21,20 +21,6 @@
|
||||
using namespace Core;
|
||||
|
||||
|
||||
bool Platform_pd::bind_thread(Platform_thread &thread)
|
||||
{
|
||||
thread.bind_to_pd(this, _thread_cnt == 0);
|
||||
_thread_cnt++;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Platform_pd::unbind_thread(Platform_thread &)
|
||||
{
|
||||
warning(__func__, "not implemented");
|
||||
}
|
||||
|
||||
|
||||
void Platform_pd::assign_parent(Native_capability parent)
|
||||
{
|
||||
if (!_parent.valid() && parent.valid())
|
||||
@ -44,7 +30,7 @@ void Platform_pd::assign_parent(Native_capability parent)
|
||||
|
||||
Platform_pd::Platform_pd(Allocator &, char const *label, signed, bool)
|
||||
:
|
||||
_thread_cnt(0), _pd_sel(cap_map().insert()), _label(label)
|
||||
_pd_sel(cap_map().insert()), _label(label)
|
||||
{
|
||||
if (_pd_sel == Native_thread::INVALID_INDEX) {
|
||||
error("platform pd creation failed ");
|
||||
|
@ -98,21 +98,20 @@ void Platform_thread::prepare_migration()
|
||||
}
|
||||
|
||||
|
||||
int Platform_thread::start(void *ip, void *sp)
|
||||
void Platform_thread::start(void *ip, void *sp)
|
||||
{
|
||||
using namespace Nova;
|
||||
|
||||
if (!_pager) {
|
||||
error("pager undefined");
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
|
||||
Pager_object &pager = *_pager;
|
||||
|
||||
if (!_pd || (main_thread() && !vcpu() &&
|
||||
_pd->parent_pt_sel() == Native_thread::INVALID_INDEX)) {
|
||||
if (main_thread() && !vcpu() && (_pd.parent_pt_sel() == Native_thread::INVALID_INDEX)) {
|
||||
error("protection domain undefined");
|
||||
return -2;
|
||||
return;
|
||||
}
|
||||
|
||||
Utcb &utcb = *reinterpret_cast<Utcb *>(Thread::myself()->utcb());
|
||||
@ -121,7 +120,7 @@ int Platform_thread::start(void *ip, void *sp)
|
||||
|
||||
if (!_create_and_map_oom_portal(utcb)) {
|
||||
error("setup of out-of-memory notification portal - failed");
|
||||
return -8;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!main_thread()) {
|
||||
@ -130,19 +129,19 @@ int Platform_thread::start(void *ip, void *sp)
|
||||
|
||||
if (_sel_exc_base == Native_thread::INVALID_INDEX) {
|
||||
error("exception base not specified");
|
||||
return -3;
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t res = syscall_retry(pager,
|
||||
[&]() {
|
||||
return create_ec(_sel_ec(), _pd->pd_sel(), kernel_cpu_id,
|
||||
return create_ec(_sel_ec(), _pd.pd_sel(), kernel_cpu_id,
|
||||
utcb_addr, initial_sp, _sel_exc_base,
|
||||
!worker());
|
||||
});
|
||||
|
||||
if (res != Nova::NOVA_OK) {
|
||||
error("creation of new thread failed ", res);
|
||||
return -4;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!vcpu())
|
||||
@ -151,7 +150,7 @@ int Platform_thread::start(void *ip, void *sp)
|
||||
if (res != NOVA_OK) {
|
||||
revoke(Obj_crd(_sel_ec(), 0));
|
||||
error("creation of new thread/vcpu failed ", res);
|
||||
return -3;
|
||||
return;
|
||||
}
|
||||
|
||||
if (worker()) {
|
||||
@ -162,13 +161,12 @@ int Platform_thread::start(void *ip, void *sp)
|
||||
pager.initial_eip((addr_t)ip);
|
||||
pager.initial_esp(initial_sp);
|
||||
pager.client_set_ec(_sel_ec());
|
||||
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!vcpu() && _sel_exc_base != Native_thread::INVALID_INDEX) {
|
||||
error("thread already started");
|
||||
return -5;
|
||||
return;
|
||||
}
|
||||
|
||||
addr_t pd_utcb = 0;
|
||||
@ -178,7 +176,7 @@ int Platform_thread::start(void *ip, void *sp)
|
||||
|
||||
pd_utcb = stack_area_virtual_base() + stack_virtual_size() - get_page_size();
|
||||
|
||||
addr_t remap_src[] = { _pd->parent_pt_sel() };
|
||||
addr_t remap_src[] = { _pd.parent_pt_sel() };
|
||||
addr_t remap_dst[] = { PT_SEL_PARENT };
|
||||
|
||||
/* remap exception portals for first thread */
|
||||
@ -186,18 +184,18 @@ int Platform_thread::start(void *ip, void *sp)
|
||||
if (map_local(source_pd, utcb,
|
||||
Obj_crd(remap_src[i], 0),
|
||||
Obj_crd(pager.exc_pt_sel_client() + remap_dst[i], 0)))
|
||||
return -6;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* create first thread in task */
|
||||
enum { THREAD_GLOBAL = true };
|
||||
uint8_t res = create_ec(_sel_ec(), _pd->pd_sel(), kernel_cpu_id,
|
||||
uint8_t res = create_ec(_sel_ec(), _pd.pd_sel(), kernel_cpu_id,
|
||||
pd_utcb, 0, _sel_exc_base,
|
||||
THREAD_GLOBAL);
|
||||
if (res != NOVA_OK) {
|
||||
error("create_ec returned ", res);
|
||||
return -7;
|
||||
return;
|
||||
}
|
||||
|
||||
pager.client_set_ec(_sel_ec());
|
||||
@ -213,7 +211,7 @@ int Platform_thread::start(void *ip, void *sp)
|
||||
res = syscall_retry(pager,
|
||||
[&]() {
|
||||
/* let the thread run */
|
||||
return create_sc(_sel_sc(), _pd->pd_sel(), _sel_ec(),
|
||||
return create_sc(_sel_sc(), _pd.pd_sel(), _sel_ec(),
|
||||
Qpd(Qpd::DEFAULT_QUANTUM, _priority));
|
||||
});
|
||||
}
|
||||
@ -227,12 +225,10 @@ int Platform_thread::start(void *ip, void *sp)
|
||||
|
||||
/* cap_selector free for _sel_ec is done in de-constructor */
|
||||
revoke(Obj_crd(_sel_ec(), 0));
|
||||
return -8;
|
||||
return;
|
||||
}
|
||||
|
||||
_features |= SC_CREATED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -255,14 +251,14 @@ void Platform_thread::resume()
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_pd || !_pager) {
|
||||
error("protection domain undefined - resuming thread failed");
|
||||
if (!_pager) {
|
||||
error("pager undefined - resuming thread failed");
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t res = syscall_retry(*_pager,
|
||||
[&]() {
|
||||
return create_sc(_sel_sc(), _pd->pd_sel(), _sel_ec(),
|
||||
return create_sc(_sel_sc(), _pd.pd_sel(), _sel_ec(),
|
||||
Qpd(Qpd::DEFAULT_QUANTUM, _priority));
|
||||
});
|
||||
|
||||
@ -298,8 +294,8 @@ void Platform_thread::single_step(bool on)
|
||||
_pager->single_step(on);
|
||||
}
|
||||
|
||||
const char * Platform_thread::pd_name() const {
|
||||
return _pd ? _pd->name() : "unknown"; }
|
||||
|
||||
const char * Platform_thread::pd_name() const { return _pd.name(); }
|
||||
|
||||
|
||||
Trace::Execution_time Platform_thread::execution_time() const
|
||||
@ -326,7 +322,7 @@ Trace::Execution_time Platform_thread::execution_time() const
|
||||
void Platform_thread::pager(Pager_object &pager)
|
||||
{
|
||||
_pager = &pager;
|
||||
_pager->assign_pd(_pd->pd_sel());
|
||||
_pager->assign_pd(_pd.pd_sel());
|
||||
}
|
||||
|
||||
|
||||
@ -347,16 +343,21 @@ void Platform_thread::thread_type(Cpu_session::Native_cpu::Thread_type thread_ty
|
||||
}
|
||||
|
||||
|
||||
Platform_thread::Platform_thread(size_t, const char *name, unsigned prio,
|
||||
Affinity::Location affinity, addr_t)
|
||||
Platform_thread::Platform_thread(Platform_pd &pd, size_t, const char *name,
|
||||
unsigned prio, Affinity::Location affinity, addr_t)
|
||||
:
|
||||
_pd(0), _pager(0), _id_base(cap_map().insert(2)),
|
||||
_pd(pd), _pager(0), _id_base(cap_map().insert(2)),
|
||||
_sel_exc_base(Native_thread::INVALID_INDEX),
|
||||
_location(platform_specific().sanitize(affinity)),
|
||||
_features(0),
|
||||
_priority((uint8_t)(scale_priority(prio, name))),
|
||||
_name(name)
|
||||
{ }
|
||||
{
|
||||
if (!pd.has_any_threads)
|
||||
_features |= MAIN_THREAD;
|
||||
|
||||
pd.has_any_threads = true;
|
||||
}
|
||||
|
||||
|
||||
Platform_thread::~Platform_thread()
|
||||
|
@ -47,11 +47,12 @@ class Core::Platform_thread
|
||||
char _name[32]; /* thread name that will be
|
||||
registered at the kernel
|
||||
debugger */
|
||||
Platform_pd *_platform_pd; /* protection domain thread
|
||||
is bound to */
|
||||
Platform_pd &_pd;
|
||||
unsigned _priority; /* thread priority */
|
||||
Pager_object *_pager;
|
||||
|
||||
bool _bound_to_pd = false;
|
||||
|
||||
public:
|
||||
|
||||
enum { THREAD_INVALID = -1 }; /* invalid thread number */
|
||||
@ -60,7 +61,7 @@ class Core::Platform_thread
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Platform_thread(size_t, const char *name,
|
||||
Platform_thread(Platform_pd &pd, size_t, const char *name,
|
||||
unsigned priority,
|
||||
Affinity::Location,
|
||||
addr_t utcb);
|
||||
@ -68,25 +69,26 @@ class Core::Platform_thread
|
||||
/**
|
||||
* Constructor used for core-internal threads
|
||||
*/
|
||||
Platform_thread(char const *name)
|
||||
: Platform_thread(0, name, 0, Affinity::Location(), 0) { }
|
||||
Platform_thread(Platform_pd &pd, char const *name)
|
||||
: Platform_thread(pd, 0, name, 0, Affinity::Location(), 0) { }
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~Platform_thread();
|
||||
|
||||
/**
|
||||
* Return true if thread creation succeeded
|
||||
*/
|
||||
bool valid() const { return _bound_to_pd; }
|
||||
|
||||
/**
|
||||
* Start thread
|
||||
*
|
||||
* \param ip instruction pointer to start at
|
||||
* \param sp stack pointer to use
|
||||
* \param cpu_no target cpu
|
||||
*
|
||||
* \retval 0 successful
|
||||
* \retval -1 thread could not be started
|
||||
* \param ip instruction pointer to start at
|
||||
* \param sp stack pointer to use
|
||||
*/
|
||||
int start(void *ip, void *sp, unsigned int cpu_no = 0);
|
||||
void start(void *ip, void *sp);
|
||||
|
||||
/**
|
||||
* Pause this thread
|
||||
@ -108,10 +110,8 @@ class Core::Platform_thread
|
||||
*
|
||||
* \param thread_id local thread ID
|
||||
* \param l4_thread_id final L4 thread ID
|
||||
* \param pd platform pd, thread is bound to
|
||||
*/
|
||||
void bind(int thread_id, Okl4::L4_ThreadId_t l4_thread_id,
|
||||
Platform_pd &pd);
|
||||
void bind(int thread_id, Okl4::L4_ThreadId_t l4_thread_id);
|
||||
|
||||
/**
|
||||
* Unbind this thread
|
||||
@ -148,7 +148,7 @@ class Core::Platform_thread
|
||||
/**
|
||||
* Get the 'Platform_pd' object this thread belongs to
|
||||
*/
|
||||
Platform_pd* pd() { return _platform_pd; }
|
||||
Platform_pd &pd() { return _pd; }
|
||||
|
||||
/**
|
||||
* Return identification of thread when faulting
|
||||
|
@ -178,12 +178,10 @@ Core::Platform::Platform()
|
||||
* not destroy this task, it should be no problem.
|
||||
*/
|
||||
Platform_thread &core_thread =
|
||||
*new (&_thread_slab) Platform_thread("core.main");
|
||||
*new (&_thread_slab) Platform_thread(*_core_pd, "core.main");
|
||||
|
||||
core_thread.set_l4_thread_id(Okl4::L4_rootserver);
|
||||
|
||||
_core_pd->bind_thread(core_thread);
|
||||
|
||||
/* core log as ROM module */
|
||||
{
|
||||
unsigned const pages = 1;
|
||||
|
@ -179,7 +179,7 @@ bool Platform_pd::bind_thread(Platform_thread &thread)
|
||||
l4_thread_id = make_l4_id(_pd_id, thread_id);
|
||||
|
||||
/* finally inform thread about binding */
|
||||
thread.bind(thread_id, l4_thread_id, *this);
|
||||
thread.bind(thread_id, l4_thread_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -200,7 +200,7 @@ void Platform_pd::space_pager(Platform_thread &thread)
|
||||
using namespace Okl4;
|
||||
|
||||
L4_Word_t control = L4_SpaceCtrl_space_pager;
|
||||
L4_SpaceId_t pager_space = L4_SpaceId(thread.pd()->pd_id());
|
||||
L4_SpaceId_t pager_space = L4_SpaceId(thread.pd().pd_id());
|
||||
L4_ClistId_t cap_list = L4_rootclist;
|
||||
L4_Word_t utcb_area_size = L4_GetUtcbSize()*(1 << Thread_id_bits::THREAD);
|
||||
L4_Word_t utcb_location = platform_specific().utcb_base()
|
||||
|
@ -29,17 +29,16 @@ using namespace Core;
|
||||
using namespace Okl4;
|
||||
|
||||
|
||||
int Platform_thread::start(void *ip, void *sp, unsigned)
|
||||
void Platform_thread::start(void *ip, void *sp)
|
||||
{
|
||||
if (!_platform_pd) {
|
||||
if (!_bound_to_pd) {
|
||||
warning("thread ", _thread_id, " is not bound to a PD");
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* activate local thread by assigning a UTCB address and thread ID */
|
||||
int space_no = _platform_pd->pd_id();
|
||||
L4_ThreadId_t new_thread_id = _platform_pd->make_l4_id(space_no,
|
||||
_thread_id);
|
||||
int space_no = _pd.pd_id();
|
||||
L4_ThreadId_t new_thread_id = _pd.make_l4_id(space_no, _thread_id);
|
||||
L4_SpaceId_t space_id = L4_SpaceId(space_no);
|
||||
L4_ThreadId_t scheduler = L4_rootserver;
|
||||
|
||||
@ -51,7 +50,7 @@ int Platform_thread::start(void *ip, void *sp, unsigned)
|
||||
L4_Word_t resources = 0;
|
||||
L4_Word_t utcb_size_per_task = L4_GetUtcbSize()*(1 << Thread_id_bits::THREAD);
|
||||
L4_Word_t utcb_location = platform_specific().utcb_base()
|
||||
+ _platform_pd->pd_id()*utcb_size_per_task
|
||||
+ _pd.pd_id()*utcb_size_per_task
|
||||
+ _thread_id*L4_GetUtcbSize();
|
||||
/*
|
||||
* On some ARM architectures, UTCBs are allocated by the kernel.
|
||||
@ -68,8 +67,8 @@ int Platform_thread::start(void *ip, void *sp, unsigned)
|
||||
*
|
||||
* Note: This is used by OKLinux only
|
||||
*/
|
||||
if(_platform_pd && _platform_pd->space_pager()) {
|
||||
pager = _platform_pd->space_pager()->_l4_thread_id;
|
||||
if(_pd.space_pager()) {
|
||||
pager = _pd.space_pager()->_l4_thread_id;
|
||||
exception_handler = pager;
|
||||
}
|
||||
|
||||
@ -79,7 +78,7 @@ int Platform_thread::start(void *ip, void *sp, unsigned)
|
||||
resources, (void *)utcb_location);
|
||||
if (ret != 1) {
|
||||
error("L4_ThreadControl returned ", ret, ", error=", ret, L4_ErrorCode());
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* make the symbolic thread name known to the kernel debugger */
|
||||
@ -102,7 +101,6 @@ int Platform_thread::start(void *ip, void *sp, unsigned)
|
||||
warning("could not set thread prioritry to default");
|
||||
|
||||
set_l4_thread_id(new_thread_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -118,12 +116,10 @@ void Platform_thread::resume()
|
||||
}
|
||||
|
||||
|
||||
void Platform_thread::bind(int thread_id, L4_ThreadId_t l4_thread_id,
|
||||
Platform_pd &pd)
|
||||
void Platform_thread::bind(int thread_id, L4_ThreadId_t l4_thread_id)
|
||||
{
|
||||
_thread_id = thread_id;
|
||||
_l4_thread_id = l4_thread_id;
|
||||
_platform_pd = &pd;
|
||||
}
|
||||
|
||||
|
||||
@ -134,10 +130,6 @@ void Platform_thread::unbind()
|
||||
|
||||
if (res != 1)
|
||||
error("deleting thread ", Hex(_l4_thread_id.raw), " failed");
|
||||
|
||||
_thread_id = THREAD_INVALID;
|
||||
_l4_thread_id = L4_nilthread;
|
||||
_platform_pd = nullptr;
|
||||
}
|
||||
|
||||
|
||||
@ -147,13 +139,14 @@ unsigned long Platform_thread::pager_object_badge() const
|
||||
}
|
||||
|
||||
|
||||
Platform_thread::Platform_thread(size_t, const char *name, unsigned prio,
|
||||
Affinity::Location, addr_t)
|
||||
Platform_thread::Platform_thread(Platform_pd &pd, size_t, const char *name,
|
||||
unsigned prio, Affinity::Location, addr_t)
|
||||
:
|
||||
_l4_thread_id(L4_nilthread), _platform_pd(0),
|
||||
_priority(prio), _pager(0)
|
||||
_l4_thread_id(L4_nilthread), _pd(pd), _priority(prio), _pager(0)
|
||||
{
|
||||
copy_cstring(_name, name, sizeof(_name));
|
||||
|
||||
_bound_to_pd = pd.bind_thread(*this);
|
||||
}
|
||||
|
||||
|
||||
@ -163,6 +156,6 @@ Platform_thread::~Platform_thread()
|
||||
* We inform our protection domain about thread destruction, which will end up in
|
||||
* Thread::unbind()
|
||||
*/
|
||||
if (_platform_pd)
|
||||
_platform_pd->unbind_thread(*this);
|
||||
if (_bound_to_pd)
|
||||
_pd.unbind_thread(*this);
|
||||
}
|
||||
|
@ -38,9 +38,7 @@ Thread::Start_result Thread::start()
|
||||
{
|
||||
/* create and start platform thread */
|
||||
native_thread().pt = new (Core::platform_specific().thread_slab())
|
||||
Core::Platform_thread(_stack->name().string());
|
||||
|
||||
Core::platform_specific().core_pd().bind_thread(*native_thread().pt);
|
||||
Core::Platform_thread(Core::platform_specific().core_pd(), _stack->name().string());
|
||||
|
||||
native_thread().pt->start((void *)_thread_start, stack_top());
|
||||
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include <base/internal/pistachio.h>
|
||||
|
||||
/* core includes */
|
||||
#include <platform_thread.h>
|
||||
#include <address_space.h>
|
||||
|
||||
namespace Core {
|
||||
@ -33,6 +32,13 @@ namespace Core {
|
||||
|
||||
class Core::Platform_pd : public Address_space
|
||||
{
|
||||
public:
|
||||
|
||||
struct Thread_id { unsigned value; };
|
||||
|
||||
enum class Alloc_thread_id_error { EXHAUSTED };
|
||||
using Alloc_thread_id_result = Attempt<Thread_id, Alloc_thread_id_error>;
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
@ -67,9 +73,9 @@ class Core::Platform_pd : public Address_space
|
||||
/**
|
||||
* Manually construct L4 thread ID from its components
|
||||
*/
|
||||
Pistachio::L4_ThreadId_t make_l4_id(unsigned pd_no,
|
||||
unsigned thread_no,
|
||||
unsigned version)
|
||||
static Pistachio::L4_ThreadId_t make_l4_id(unsigned pd_no,
|
||||
unsigned thread_no,
|
||||
unsigned version)
|
||||
{
|
||||
/*
|
||||
* We have to make sure that the 6 lower version bits are
|
||||
@ -87,31 +93,7 @@ class Core::Platform_pd : public Address_space
|
||||
** Threads of this protection domain object **
|
||||
**********************************************/
|
||||
|
||||
Platform_thread *_threads[THREAD_MAX];
|
||||
|
||||
/**
|
||||
* Initialize thread allocator
|
||||
*/
|
||||
void _init_threads();
|
||||
|
||||
/**
|
||||
* Thread iteration for one PD
|
||||
*/
|
||||
Platform_thread *_next_thread();
|
||||
|
||||
/**
|
||||
* Thread allocation
|
||||
*
|
||||
* Again a special case for Core thread0.
|
||||
*/
|
||||
int _alloc_thread(int thread_id, Platform_thread &thread);
|
||||
|
||||
/**
|
||||
* Thread deallocation
|
||||
*
|
||||
* No special case for Core thread0 here - we just never call it.
|
||||
*/
|
||||
void _free_thread(int thread_id);
|
||||
Platform_thread *_threads[THREAD_MAX] { };
|
||||
|
||||
|
||||
/******************
|
||||
@ -210,25 +192,29 @@ class Core::Platform_pd : public Address_space
|
||||
*/
|
||||
void upgrade_ram_quota(size_t) { }
|
||||
|
||||
/**
|
||||
* Allocate PD-local ID for a new 'Platform_thread'
|
||||
*/
|
||||
Alloc_thread_id_result alloc_thread_id(Platform_thread &);
|
||||
|
||||
/**
|
||||
* Release PD-local thread ID at destruction of 'Platform_thread'
|
||||
*/
|
||||
void free_thread_id(Thread_id);
|
||||
|
||||
/**
|
||||
* Return L4 thread ID from the PD's task ID and the PD-local thread ID
|
||||
*/
|
||||
Pistachio::L4_ThreadId_t l4_thread_id(Thread_id const id) const
|
||||
{
|
||||
return make_l4_id(_pd_id, id.value, _version);
|
||||
}
|
||||
|
||||
static Pistachio::L4_Word_t _core_utcb_ptr;
|
||||
static void touch_utcb_space();
|
||||
|
||||
/**
|
||||
* Bind thread to protection domain
|
||||
*
|
||||
* This function allocates the physical L4 thread ID.
|
||||
*/
|
||||
bool bind_thread(Platform_thread &thread);
|
||||
|
||||
int bind_initial_thread(Platform_thread &thread);
|
||||
|
||||
/**
|
||||
* Unbind thread from protection domain
|
||||
*
|
||||
* Free the thread's slot and update thread object.
|
||||
*/
|
||||
void unbind_thread(Platform_thread &thread);
|
||||
|
||||
/**
|
||||
* Assign parent interface to protection domain
|
||||
*/
|
||||
|
@ -56,86 +56,92 @@ class Core::Platform_thread : Interface
|
||||
Platform_thread(Platform_thread const &);
|
||||
Platform_thread &operator = (Platform_thread const &);
|
||||
|
||||
typedef String<32> Name;
|
||||
using Name = String<32>;
|
||||
|
||||
int _thread_id = THREAD_INVALID;
|
||||
L4_ThreadId_t _l4_thread_id = L4_nilthread;
|
||||
Name const _name; /* thread name at kernel debugger */
|
||||
Platform_pd *_platform_pd = nullptr;
|
||||
unsigned _priority = 0;
|
||||
Platform_pd &_pd;
|
||||
unsigned const _priority = 0;
|
||||
Pager_object *_pager = nullptr;
|
||||
Affinity::Location _location;
|
||||
Affinity::Location _location { };
|
||||
|
||||
using Id = Platform_pd::Alloc_thread_id_result;
|
||||
|
||||
Id const _id { _pd.alloc_thread_id(*this) };
|
||||
|
||||
Pistachio::L4_ThreadId_t _l4_id_from_pd_thread_id() const
|
||||
{
|
||||
using namespace Pistachio;
|
||||
return _id.convert<L4_ThreadId_t>(
|
||||
[&] (Platform_pd::Thread_id id) { return _pd.l4_thread_id(id); },
|
||||
[&] (Platform_pd::Alloc_thread_id_error) { return L4_nilthread; }
|
||||
);
|
||||
}
|
||||
|
||||
Pistachio::L4_ThreadId_t const _l4_id = _l4_id_from_pd_thread_id();
|
||||
|
||||
public:
|
||||
|
||||
enum { THREAD_INVALID = -1 };
|
||||
enum { DEFAULT_PRIORITY = 128 };
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Platform_thread(size_t, char const *name, unsigned priority,
|
||||
Platform_thread(Platform_pd &pd, size_t, char const *name, unsigned priority,
|
||||
Affinity::Location location, addr_t)
|
||||
:
|
||||
_name(name), _priority(priority), _location(location)
|
||||
_name(name), _pd(pd), _priority(priority), _location(location)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Constructor used for initial roottask thread "core.main"
|
||||
*/
|
||||
Platform_thread(Platform_pd &pd, Pistachio::L4_ThreadId_t l4_id)
|
||||
:
|
||||
_name("core.main"), _pd(pd), _l4_id(l4_id)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Constructor used for core-internal threads
|
||||
*/
|
||||
Platform_thread(char const *name)
|
||||
: _name(name), _location(Affinity::Location()) { }
|
||||
Platform_thread(Platform_pd &pd, char const *name) : _name(name), _pd(pd) { }
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~Platform_thread();
|
||||
|
||||
/**
|
||||
* Return true if thread creation suceeded
|
||||
*/
|
||||
bool valid() const { return _id.ok(); }
|
||||
|
||||
/**
|
||||
* Start thread
|
||||
*
|
||||
* \param ip instruction pointer to start at
|
||||
* \param sp stack pointer to use
|
||||
*
|
||||
* \retval 0 successful
|
||||
* \retval -1 thread could not be started
|
||||
*/
|
||||
int start(void *ip, void *sp);
|
||||
void start(void *ip, void *sp);
|
||||
|
||||
/**
|
||||
* Pause this thread
|
||||
*/
|
||||
void pause();
|
||||
void pause() { /* not implemented */ }
|
||||
|
||||
/**
|
||||
* Enable/disable single stepping
|
||||
*/
|
||||
void single_step(bool) { }
|
||||
void single_step(bool) { /* not implemented */ }
|
||||
|
||||
/**
|
||||
* Resume this thread
|
||||
*/
|
||||
void resume();
|
||||
|
||||
/**
|
||||
* This thread is about to be bound
|
||||
*
|
||||
* \param thread_id local thread ID
|
||||
* \param l4_thread_id final L4 thread ID
|
||||
* \param pd platform pd, thread is bound to
|
||||
*/
|
||||
void bind(int thread_id, Pistachio::L4_ThreadId_t l4_thread_id,
|
||||
Platform_pd &pd);
|
||||
|
||||
/**
|
||||
* Unbind this thread
|
||||
*/
|
||||
void unbind();
|
||||
void resume() { /* not implemented */ }
|
||||
|
||||
/**
|
||||
* Override thread state with 's'
|
||||
*/
|
||||
void state(Thread_state s);
|
||||
void state(Thread_state) { /* not implemented */ }
|
||||
|
||||
/**
|
||||
* Read thread state
|
||||
@ -165,7 +171,7 @@ class Core::Platform_thread : Interface
|
||||
*/
|
||||
unsigned long pager_object_badge() const
|
||||
{
|
||||
return convert_native_thread_id_to_badge(_l4_thread_id);
|
||||
return convert_native_thread_id_to_badge(native_thread_id());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -193,12 +199,9 @@ class Core::Platform_thread : Interface
|
||||
** Pistachio-specific Accessors **
|
||||
**********************************/
|
||||
|
||||
int thread_id() const { return _thread_id; }
|
||||
Pistachio::L4_ThreadId_t native_thread_id() const { return _l4_thread_id; }
|
||||
Name name() const { return _name; }
|
||||
Pistachio::L4_ThreadId_t native_thread_id() const { return _l4_id; }
|
||||
|
||||
/* use only for core... */
|
||||
void set_l4_thread_id(Pistachio::L4_ThreadId_t id) { _l4_thread_id = id; }
|
||||
Name name() const { return _name; }
|
||||
};
|
||||
|
||||
#endif /* _CORE__INCLUDE__PLATFORM_THREAD_H_ */
|
||||
|
@ -214,14 +214,13 @@ Core::Platform::Sigma0 &Core::Platform::sigma0()
|
||||
|
||||
Core::Platform::Core_pager::Core_pager(Platform_pd &core_pd)
|
||||
:
|
||||
Platform_thread("core.pager"),
|
||||
Platform_thread(core_pd, "core.pager"),
|
||||
Pager_object(Cpu_session_capability(), Thread_capability(),
|
||||
0, Affinity::Location(),
|
||||
Session_label(), Cpu_session::Name(name()))
|
||||
{
|
||||
Platform_thread::pager(sigma0());
|
||||
|
||||
core_pd.bind_thread(*this);
|
||||
cap(Capability_space::import(native_thread_id(), Rpc_obj_key()));
|
||||
|
||||
/* stack begins at the top end of the '_core_pager_stack' array */
|
||||
@ -594,13 +593,10 @@ Core::Platform::Platform()
|
||||
* thread_id of first task. But since we do not destroy this
|
||||
* task, it should be no problem.
|
||||
*/
|
||||
static Platform_thread core_thread("core.main");
|
||||
static Platform_thread core_thread(core_pd(), Pistachio::L4_MyGlobalId());
|
||||
|
||||
core_thread.set_l4_thread_id(Pistachio::L4_MyGlobalId());
|
||||
core_thread.pager(sigma0());
|
||||
|
||||
core_pd().bind_thread(core_thread);
|
||||
|
||||
auto export_page_as_rom_module = [&] (auto rom_name, auto content_fn)
|
||||
{
|
||||
size_t const size = 1 << get_page_size_log2();
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
/* Genode includes */
|
||||
#include <util.h>
|
||||
#include <platform_pd.h>
|
||||
#include <platform_thread.h>
|
||||
|
||||
/* base-internal includes */
|
||||
#include <base/internal/pistachio.h>
|
||||
@ -116,96 +116,27 @@ void Platform_pd::_free_pd()
|
||||
}
|
||||
|
||||
|
||||
void Platform_pd::_init_threads()
|
||||
Platform_pd::Alloc_thread_id_result Platform_pd::alloc_thread_id(Platform_thread &thread)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < THREAD_MAX; ++i)
|
||||
_threads[i] = 0;
|
||||
}
|
||||
|
||||
|
||||
Platform_thread* Platform_pd::_next_thread()
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
/* look for bound thread */
|
||||
for (i = 0; i < THREAD_MAX; ++i)
|
||||
if (_threads[i]) break;
|
||||
|
||||
/* no bound threads */
|
||||
if (i == THREAD_MAX) return 0;
|
||||
|
||||
return _threads[i];
|
||||
}
|
||||
|
||||
|
||||
int Platform_pd::_alloc_thread(int thread_id, Platform_thread &thread)
|
||||
{
|
||||
int i = thread_id;
|
||||
|
||||
/* look for free thread */
|
||||
if (thread_id == Platform_thread::THREAD_INVALID) {
|
||||
|
||||
/* start from 1 here, because thread 0 is our placeholder thread */
|
||||
for (i = 1; i < THREAD_MAX; ++i)
|
||||
if (!_threads[i]) break;
|
||||
|
||||
/* no free threads available */
|
||||
if (i == THREAD_MAX) return -1;
|
||||
} else {
|
||||
if (_threads[i]) return -2;
|
||||
for (unsigned i = 0; i < THREAD_MAX; i++) {
|
||||
if (_threads[i] == nullptr) {
|
||||
_threads[i] = &thread;
|
||||
return Thread_id { i };
|
||||
}
|
||||
}
|
||||
|
||||
_threads[i] = &thread;
|
||||
|
||||
return i;
|
||||
return Alloc_thread_id_error::EXHAUSTED;
|
||||
}
|
||||
|
||||
|
||||
void Platform_pd::_free_thread(int thread_id)
|
||||
void Platform_pd::free_thread_id(Thread_id const id)
|
||||
{
|
||||
if (!_threads[thread_id])
|
||||
warning("double-free of thread ", Hex(_pd_id), ".", Hex(thread_id), " detected");
|
||||
if (id.value >= THREAD_MAX)
|
||||
return;
|
||||
|
||||
_threads[thread_id] = 0;
|
||||
}
|
||||
if (!_threads[id.value])
|
||||
warning("double-free of thread ", Hex(_pd_id), ".", Hex(id.value), " detected");
|
||||
|
||||
|
||||
/***************************
|
||||
** Public object members **
|
||||
***************************/
|
||||
|
||||
bool Platform_pd::bind_thread(Platform_thread &thread)
|
||||
{
|
||||
using namespace Pistachio;
|
||||
|
||||
/* thread_id is THREAD_INVALID by default - only core is the special case */
|
||||
int thread_id = thread.thread_id();
|
||||
L4_ThreadId_t l4_thread_id;
|
||||
|
||||
int t = _alloc_thread(thread_id, thread);
|
||||
if (t < 0)
|
||||
return false;
|
||||
|
||||
thread_id = t;
|
||||
l4_thread_id = make_l4_id(_pd_id, thread_id, _version);
|
||||
|
||||
/* finally inform thread about binding */
|
||||
thread.bind(thread_id, l4_thread_id, *this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Platform_pd::unbind_thread(Platform_thread &thread)
|
||||
{
|
||||
int thread_id = thread.thread_id();
|
||||
|
||||
/* unbind thread before proceeding */
|
||||
thread.unbind();
|
||||
|
||||
_free_thread(thread_id);
|
||||
_threads[id.value] = nullptr;
|
||||
}
|
||||
|
||||
|
||||
@ -302,8 +233,6 @@ Platform_pd::Platform_pd(bool) : _l4_task_id(L4_MyGlobalId())
|
||||
*/
|
||||
Pd_alloc free(false, true, 2);
|
||||
|
||||
_init_threads();
|
||||
|
||||
/* init remainder */
|
||||
for (unsigned i = 0 ; i < PD_MAX; ++i) _pds()[i] = free;
|
||||
|
||||
@ -322,8 +251,6 @@ Platform_pd::Platform_pd(Allocator &, char const *, signed pd_id, bool create)
|
||||
if (!create)
|
||||
panic("create must be true.");
|
||||
|
||||
_init_threads();
|
||||
|
||||
int const id = _alloc_pd(pd_id);
|
||||
if (id < 0) {
|
||||
error("pd alloc failed");
|
||||
@ -338,10 +265,6 @@ Platform_pd::Platform_pd(Allocator &, char const *, signed pd_id, bool create)
|
||||
|
||||
Platform_pd::~Platform_pd()
|
||||
{
|
||||
/* unbind all threads */
|
||||
while (Platform_thread *t = _next_thread())
|
||||
unbind_thread(*t);
|
||||
|
||||
_destroy_pd();
|
||||
_free_pd();
|
||||
}
|
||||
|
@ -34,8 +34,8 @@ void Platform_thread::affinity(Affinity::Location location)
|
||||
return;
|
||||
}
|
||||
|
||||
if (_l4_thread_id != L4_nilthread) {
|
||||
if (L4_Set_ProcessorNo(_l4_thread_id, cpu_no) == 0)
|
||||
if (native_thread_id() != L4_nilthread) {
|
||||
if (L4_Set_ProcessorNo(native_thread_id(), cpu_no) == 0)
|
||||
error("could not set processor number");
|
||||
else
|
||||
_location = location;
|
||||
@ -49,9 +49,12 @@ Affinity::Location Platform_thread::affinity() const
|
||||
}
|
||||
|
||||
|
||||
int Platform_thread::start(void *ip, void *sp)
|
||||
void Platform_thread::start(void *ip, void *sp)
|
||||
{
|
||||
L4_ThreadId_t thread = _l4_thread_id;
|
||||
if (_id.failed())
|
||||
return;
|
||||
|
||||
L4_ThreadId_t thread = native_thread_id();
|
||||
L4_ThreadId_t pager = _pager
|
||||
? Capability_space::ipc_cap_data(_pager->cap()).dst
|
||||
: L4_nilthread;
|
||||
@ -59,29 +62,26 @@ int Platform_thread::start(void *ip, void *sp)
|
||||
/* XXX should always be the root task */
|
||||
L4_ThreadId_t preempter = L4_Myself();
|
||||
|
||||
if (_thread_id == THREAD_INVALID) {
|
||||
error("attempt to start a thread with invalid ID");
|
||||
return -1;
|
||||
}
|
||||
L4_Word_t const utcb_location = _id.convert<L4_Word_t>(
|
||||
[&] (Platform_pd::Thread_id id) { return _pd._utcb_location(id.value); },
|
||||
[&] (Platform_pd::Alloc_thread_id_error) { return 0UL; });
|
||||
|
||||
L4_Word_t utcb_location = _platform_pd->_utcb_location(_thread_id);
|
||||
|
||||
int ret = L4_ThreadControl(thread, _platform_pd->_l4_task_id,
|
||||
int ret = L4_ThreadControl(thread, _pd._l4_task_id,
|
||||
preempter, L4_Myself(), (void *)utcb_location);
|
||||
|
||||
if (ret != 1) {
|
||||
error(__func__, ": L4_ThreadControl returned ", Hex(L4_ErrorCode()));
|
||||
return -2;
|
||||
return;
|
||||
}
|
||||
|
||||
/* set real pager */
|
||||
ret = L4_ThreadControl(thread, _platform_pd->_l4_task_id,
|
||||
ret = L4_ThreadControl(thread, _pd._l4_task_id,
|
||||
L4_nilthread, pager, (void *)-1);
|
||||
|
||||
if (ret != 1) {
|
||||
error(__func__, ": L4_ThreadControl returned ", Hex(L4_ErrorCode()));
|
||||
error("setting pager failed");
|
||||
return -3;
|
||||
return;
|
||||
}
|
||||
|
||||
/* get the thread running on the right cpu */
|
||||
@ -103,51 +103,11 @@ int Platform_thread::start(void *ip, void *sp)
|
||||
|
||||
if (L4_IpcFailed(tag)) {
|
||||
error("starting thread failed. (IPC error)");
|
||||
return -4;
|
||||
return;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void Platform_thread::pause()
|
||||
{
|
||||
warning(__func__, " not implemented");
|
||||
}
|
||||
|
||||
|
||||
void Platform_thread::resume()
|
||||
{
|
||||
warning(__func__, " not implemented");
|
||||
}
|
||||
|
||||
|
||||
void Platform_thread::bind(int thread_id, L4_ThreadId_t l4_thread_id,
|
||||
Platform_pd &pd)
|
||||
{
|
||||
_thread_id = thread_id;
|
||||
_l4_thread_id = l4_thread_id;
|
||||
_platform_pd = &pd;
|
||||
}
|
||||
|
||||
|
||||
void Platform_thread::unbind()
|
||||
{
|
||||
L4_Word_t res = L4_ThreadControl(_l4_thread_id, L4_nilthread,
|
||||
L4_nilthread, L4_nilthread, (void *)-1);
|
||||
|
||||
if (res != 1)
|
||||
error("deleting thread ", Formatted_tid(_l4_thread_id), " failed");
|
||||
|
||||
_thread_id = THREAD_INVALID;
|
||||
_l4_thread_id = L4_nilthread;
|
||||
_platform_pd = 0;
|
||||
}
|
||||
|
||||
|
||||
void Platform_thread::state(Thread_state) { }
|
||||
|
||||
|
||||
Thread_state Platform_thread::state()
|
||||
{
|
||||
Thread_state s { };
|
||||
@ -160,7 +120,7 @@ Thread_state Platform_thread::state()
|
||||
DELIVER = 1 << 9,
|
||||
};
|
||||
|
||||
L4_ExchangeRegisters(_l4_thread_id,
|
||||
L4_ExchangeRegisters(native_thread_id(),
|
||||
DELIVER,
|
||||
0, 0, 0, 0, L4_nilthread,
|
||||
&dummy, &sp, &ip, &dummy, &dummy,
|
||||
@ -174,10 +134,16 @@ Thread_state Platform_thread::state()
|
||||
|
||||
Platform_thread::~Platform_thread()
|
||||
{
|
||||
/*
|
||||
* We inform our protection domain about thread destruction, which will end up in
|
||||
* Thread::unbind()
|
||||
*/
|
||||
if (_platform_pd)
|
||||
_platform_pd->unbind_thread(*this);
|
||||
_id.with_result(
|
||||
[&] (Platform_pd::Thread_id id) {
|
||||
|
||||
L4_Word_t res = L4_ThreadControl(native_thread_id(), L4_nilthread,
|
||||
L4_nilthread, L4_nilthread, (void *)-1);
|
||||
if (res != 1)
|
||||
error("deleting thread ", Formatted_tid(native_thread_id()), " failed");
|
||||
|
||||
_pd.free_thread_id(id);
|
||||
},
|
||||
[&] (Platform_pd::Alloc_thread_id_error) { }
|
||||
);
|
||||
}
|
||||
|
@ -39,9 +39,7 @@ Thread::Start_result Thread::start()
|
||||
{
|
||||
/* create and start platform thread */
|
||||
native_thread().pt = new (platform().core_mem_alloc())
|
||||
Platform_thread(_stack->name().string());
|
||||
|
||||
platform_specific().core_pd().bind_thread(*native_thread().pt);
|
||||
Platform_thread(platform_specific().core_pd(), _stack->name().string());
|
||||
|
||||
native_thread().pt->pager(platform_specific().core_pager());
|
||||
native_thread().l4id = native_thread().pt->native_thread_id();
|
||||
|
@ -30,6 +30,16 @@ namespace Core { class Platform_pd; }
|
||||
|
||||
class Core::Platform_pd : public Address_space
|
||||
{
|
||||
public:
|
||||
|
||||
/*
|
||||
* Allocator for core-managed selectors within the PD's CSpace
|
||||
*/
|
||||
struct Sel_alloc : Bit_allocator<1 << NUM_CORE_MANAGED_SEL_LOG2>
|
||||
{
|
||||
Sel_alloc() { _reserve(0, INITIAL_SEL_END); }
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
unsigned const _id; /* used as index in top-level CNode */
|
||||
@ -47,22 +57,9 @@ class Core::Platform_pd : public Address_space
|
||||
|
||||
Native_capability _parent { };
|
||||
|
||||
/*
|
||||
* Allocator for core-managed selectors within the PD's CSpace
|
||||
*/
|
||||
typedef Bit_allocator<1 << NUM_CORE_MANAGED_SEL_LOG2> Sel_bit_alloc;
|
||||
|
||||
struct Sel_alloc : Sel_bit_alloc
|
||||
{
|
||||
Sel_alloc() { _reserve(0, INITIAL_SEL_END); }
|
||||
};
|
||||
|
||||
Sel_alloc _sel_alloc { };
|
||||
Mutex _sel_alloc_mutex { };
|
||||
|
||||
Cap_sel alloc_sel();
|
||||
void free_sel(Cap_sel sel);
|
||||
|
||||
addr_t _init_page_directory() const;
|
||||
void _deinit_page_directory(addr_t) const;
|
||||
|
||||
@ -79,16 +76,24 @@ class Core::Platform_pd : public Address_space
|
||||
~Platform_pd();
|
||||
|
||||
/**
|
||||
* Bind thread to protection domain
|
||||
* Allocate capability selector
|
||||
*/
|
||||
bool bind_thread(Platform_thread &);
|
||||
Cap_sel alloc_sel();
|
||||
|
||||
/**
|
||||
* Unbind thread from protection domain
|
||||
*
|
||||
* Free the thread's slot and update thread object.
|
||||
* Release capability selector
|
||||
*/
|
||||
void unbind_thread(Platform_thread &);
|
||||
void free_sel(Cap_sel);
|
||||
|
||||
/**
|
||||
* Map physical IPC buffer to virtual UTCB address
|
||||
*/
|
||||
void map_ipc_buffer(Ipc_buffer_phys, Utcb_virt);
|
||||
|
||||
/**
|
||||
* Unmap IPC buffer from PD, at 'Platform_thread' destruction time
|
||||
*/
|
||||
void unmap_ipc_buffer(Utcb_virt);
|
||||
|
||||
/**
|
||||
* Assign parent interface to protection domain
|
||||
|
@ -53,7 +53,7 @@ class Core::Platform_thread : public List<Platform_thread>::Element
|
||||
* The value for the PD's main thread is INITIAL_IPC_BUFFER_VIRT.
|
||||
* For all other threads, the value is somewhere within the stack area.
|
||||
*/
|
||||
addr_t const _utcb;
|
||||
Utcb_virt const _utcb;
|
||||
|
||||
Thread_info _info { };
|
||||
|
||||
@ -72,21 +72,23 @@ class Core::Platform_thread : public List<Platform_thread>::Element
|
||||
|
||||
friend class Platform_pd;
|
||||
|
||||
Platform_pd *_pd = nullptr;
|
||||
Platform_pd &_pd;
|
||||
|
||||
enum { INITIAL_IPC_BUFFER_VIRT = 0x1000 };
|
||||
|
||||
Affinity::Location _location;
|
||||
uint16_t _priority;
|
||||
|
||||
bool main_thread() const { return _utcb == INITIAL_IPC_BUFFER_VIRT; }
|
||||
bool _bound_to_pd = false;
|
||||
|
||||
bool main_thread() const { return _utcb.addr == INITIAL_IPC_BUFFER_VIRT; }
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Platform_thread(size_t, const char *name, unsigned priority,
|
||||
Platform_thread(Platform_pd &pd, size_t, const char *name, unsigned priority,
|
||||
Affinity::Location, addr_t utcb);
|
||||
|
||||
/**
|
||||
@ -94,17 +96,19 @@ class Core::Platform_thread : public List<Platform_thread>::Element
|
||||
*/
|
||||
~Platform_thread();
|
||||
|
||||
/**
|
||||
* Return true if thread creation succeeded
|
||||
*/
|
||||
bool valid() const { return _bound_to_pd; }
|
||||
|
||||
/**
|
||||
* Start thread
|
||||
*
|
||||
* \param ip instruction pointer to start at
|
||||
* \param sp stack pointer to use
|
||||
* \param cpu_no target cpu
|
||||
*
|
||||
* \retval 0 successful
|
||||
* \retval -1 thread could not be started
|
||||
*/
|
||||
int start(void *ip, void *sp, unsigned int cpu_no = 0);
|
||||
void start(void *ip, void *sp, unsigned int cpu_no = 0);
|
||||
|
||||
/**
|
||||
* Pause this thread
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
/* base-internal includes */
|
||||
#include <base/internal/assert.h>
|
||||
#include <base/internal/native_utcb.h>
|
||||
|
||||
/* core includes */
|
||||
#include <map_local.h>
|
||||
@ -36,17 +37,22 @@ namespace Core {
|
||||
void start_sel4_thread(Cap_sel tcb_sel, addr_t ip, addr_t sp, unsigned cpu,
|
||||
addr_t tls_ipcbuffer);
|
||||
void affinity_sel4_thread(Cap_sel const &tcb_sel, unsigned cpu);
|
||||
|
||||
struct Ipc_buffer_phys { addr_t addr; };
|
||||
|
||||
using Utcb_virt = Native_utcb::Virt;
|
||||
}
|
||||
|
||||
|
||||
struct Genode::Thread_info
|
||||
{
|
||||
Cap_sel tcb_sel { 0 };
|
||||
Cap_sel ep_sel { 0 };
|
||||
Cap_sel tcb_sel { 0 };
|
||||
Cap_sel ep_sel { 0 };
|
||||
Cap_sel lock_sel { 0 };
|
||||
Cap_sel vcpu_sel { 0 };
|
||||
|
||||
addr_t ipc_buffer_phys { 0 };
|
||||
Core::Ipc_buffer_phys ipc_buffer_phys { 0 };
|
||||
|
||||
addr_t vcpu_state_phys { 0 };
|
||||
|
||||
inline void write_thread_info_to_ipc_buffer(Cap_sel pd_ep_sel);
|
||||
@ -55,7 +61,7 @@ struct Genode::Thread_info
|
||||
|
||||
inline void init_tcb(Core::Platform &, Range_allocator &,
|
||||
unsigned const prio, unsigned const cpu);
|
||||
inline void init(addr_t const utcb_virt_addr, unsigned const prio);
|
||||
inline void init(Core::Utcb_virt const utcb_virt, unsigned const prio);
|
||||
inline void destruct();
|
||||
|
||||
bool init_vcpu(Core::Platform &, Cap_sel ept);
|
||||
@ -84,7 +90,7 @@ void Genode::Thread_info::init_tcb(Core::Platform &platform,
|
||||
}
|
||||
|
||||
|
||||
void Genode::Thread_info::init(addr_t const utcb_virt_addr, unsigned const prio)
|
||||
void Genode::Thread_info::init(Core::Utcb_virt const utcb_virt, unsigned const prio)
|
||||
{
|
||||
using namespace Core;
|
||||
|
||||
@ -92,8 +98,8 @@ void Genode::Thread_info::init(addr_t const utcb_virt_addr, unsigned const prio)
|
||||
Range_allocator &phys_alloc = platform.ram_alloc();
|
||||
|
||||
/* create IPC buffer of one page */
|
||||
ipc_buffer_phys = Untyped_memory::alloc_page(phys_alloc);
|
||||
Untyped_memory::convert_to_page_frames(ipc_buffer_phys, 1);
|
||||
ipc_buffer_phys = { Untyped_memory::alloc_page(phys_alloc) };
|
||||
Untyped_memory::convert_to_page_frames(ipc_buffer_phys.addr, 1);
|
||||
|
||||
/* allocate TCB within core's CNode */
|
||||
init_tcb(platform, phys_alloc, prio, 0);
|
||||
@ -119,9 +125,9 @@ void Genode::Thread_info::init(addr_t const utcb_virt_addr, unsigned const prio)
|
||||
/* assign IPC buffer to thread */
|
||||
{
|
||||
/* determine page frame selector of the allocated IPC buffer */
|
||||
Cap_sel ipc_buffer_sel = Untyped_memory::frame_sel(ipc_buffer_phys);
|
||||
Cap_sel ipc_buffer_sel = Untyped_memory::frame_sel(ipc_buffer_phys.addr);
|
||||
|
||||
int const ret = seL4_TCB_SetIPCBuffer(tcb_sel.value(), utcb_virt_addr,
|
||||
int const ret = seL4_TCB_SetIPCBuffer(tcb_sel.value(), utcb_virt.addr,
|
||||
ipc_buffer_sel.value());
|
||||
ASSERT(ret == 0);
|
||||
}
|
||||
@ -150,11 +156,11 @@ void Genode::Thread_info::destruct()
|
||||
platform_specific().core_sel_alloc().free(vcpu_sel);
|
||||
}
|
||||
|
||||
if (ipc_buffer_phys) {
|
||||
if (ipc_buffer_phys.addr) {
|
||||
Core::Platform &platform = platform_specific();
|
||||
Range_allocator &phys_alloc = platform.ram_alloc();
|
||||
Untyped_memory::convert_to_untyped_frames(ipc_buffer_phys, 4096);
|
||||
Untyped_memory::free_page(phys_alloc, ipc_buffer_phys);
|
||||
Untyped_memory::convert_to_untyped_frames(ipc_buffer_phys.addr, 4096);
|
||||
Untyped_memory::free_page(phys_alloc, ipc_buffer_phys.addr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,40 +49,8 @@ Bit_allocator<1024> &Platform_pd::pd_id_alloc()
|
||||
}
|
||||
|
||||
|
||||
bool Platform_pd::bind_thread(Platform_thread &thread)
|
||||
void Platform_pd::map_ipc_buffer(Ipc_buffer_phys const from, Utcb_virt const to)
|
||||
{
|
||||
try {
|
||||
/* allocate fault handler selector in the PD's CSpace */
|
||||
thread._fault_handler_sel = alloc_sel();
|
||||
/* allocate endpoint selector in the PD's CSpace */
|
||||
thread._ep_sel = alloc_sel();
|
||||
thread._vcpu_sel = alloc_sel();
|
||||
/* allocate asynchronous selector used for locks in the PD's CSpace */
|
||||
thread._lock_sel = thread.main_thread() ? Cap_sel(INITIAL_SEL_LOCK)
|
||||
: alloc_sel();
|
||||
thread._vcpu_notify_sel = alloc_sel();
|
||||
} catch (Platform_pd::Sel_bit_alloc::Out_of_indices) {
|
||||
if (thread._fault_handler_sel.value()) {
|
||||
free_sel(thread._fault_handler_sel);
|
||||
thread._fault_handler_sel = Cap_sel(0);
|
||||
}
|
||||
if (thread._ep_sel.value()) {
|
||||
free_sel(thread._ep_sel);
|
||||
thread._ep_sel = Cap_sel(0);
|
||||
}
|
||||
if (thread._vcpu_sel.value()) {
|
||||
free_sel(thread._vcpu_sel);
|
||||
thread._vcpu_sel = Cap_sel(0);
|
||||
}
|
||||
if (thread._vcpu_notify_sel.value()) {
|
||||
free_sel(thread._vcpu_notify_sel);
|
||||
thread._vcpu_notify_sel = Cap_sel(0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
thread._pd = this;
|
||||
|
||||
/*
|
||||
* Map IPC buffer
|
||||
*
|
||||
@ -99,23 +67,14 @@ bool Platform_pd::bind_thread(Platform_thread &thread)
|
||||
.executable = false,
|
||||
.flush_support = true };
|
||||
enum { ONE_PAGE = 1 };
|
||||
_vm_space.alloc_page_tables(thread._utcb, get_page_size());
|
||||
_vm_space.map(thread._info.ipc_buffer_phys, thread._utcb, ONE_PAGE, attr);
|
||||
return true;
|
||||
_vm_space.alloc_page_tables(to.addr, get_page_size());
|
||||
_vm_space.map(from.addr, to.addr, ONE_PAGE, attr);
|
||||
}
|
||||
|
||||
|
||||
void Platform_pd::unbind_thread(Platform_thread &thread)
|
||||
void Platform_pd::unmap_ipc_buffer(Utcb_virt const utcb)
|
||||
{
|
||||
if (not thread.main_thread())
|
||||
free_sel(thread._lock_sel);
|
||||
|
||||
free_sel(thread._fault_handler_sel);
|
||||
free_sel(thread._ep_sel);
|
||||
free_sel(thread._vcpu_sel);
|
||||
free_sel(thread._vcpu_notify_sel);
|
||||
|
||||
_vm_space.unmap(thread._utcb, 1);
|
||||
_vm_space.unmap(utcb.addr, 1);
|
||||
}
|
||||
|
||||
|
||||
|
@ -94,10 +94,10 @@ bool Core::install_mapping(Mapping const &mapping, unsigned long pager_object_ba
|
||||
** Utilities to support the Platform_thread interface **
|
||||
********************************************************/
|
||||
|
||||
static void prepopulate_ipc_buffer(addr_t const ipc_buffer_phys,
|
||||
Cap_sel const ep_sel,
|
||||
Cap_sel const lock_sel,
|
||||
addr_t const utcb_virt)
|
||||
static void prepopulate_ipc_buffer(Ipc_buffer_phys const ipc_buffer_phys,
|
||||
Cap_sel const ep_sel,
|
||||
Cap_sel const lock_sel,
|
||||
Utcb_virt const utcb_virt)
|
||||
{
|
||||
/* IPC buffer is one page */
|
||||
size_t const page_rounded_size = get_page_size();
|
||||
@ -108,7 +108,7 @@ static void prepopulate_ipc_buffer(addr_t const ipc_buffer_phys,
|
||||
[&] (void *virt_ptr) {
|
||||
|
||||
/* map the IPC buffer to core-local virtual addresses */
|
||||
map_local(ipc_buffer_phys, (addr_t)virt_ptr, 1);
|
||||
map_local(ipc_buffer_phys.addr, (addr_t)virt_ptr, 1);
|
||||
|
||||
/* populate IPC buffer with thread information */
|
||||
Native_utcb &utcb = *(Native_utcb *)virt_ptr;
|
||||
@ -139,25 +139,24 @@ static void prepopulate_ipc_buffer(addr_t const ipc_buffer_phys,
|
||||
** Platform_thread interface **
|
||||
*******************************/
|
||||
|
||||
int Platform_thread::start(void *ip, void *sp, unsigned int)
|
||||
void Platform_thread::start(void *ip, void *sp, unsigned int)
|
||||
{
|
||||
ASSERT(_pd);
|
||||
ASSERT(_pager);
|
||||
|
||||
/* pager endpoint in core */
|
||||
Cap_sel const pager_sel(Capability_space::ipc_cap_data(_pager->cap()).sel);
|
||||
|
||||
/* install page-fault handler endpoint selector to the PD's CSpace */
|
||||
_pd->cspace_cnode(_fault_handler_sel).copy(platform_specific().core_cnode(),
|
||||
pager_sel, _fault_handler_sel);
|
||||
_pd.cspace_cnode(_fault_handler_sel).copy(platform_specific().core_cnode(),
|
||||
pager_sel, _fault_handler_sel);
|
||||
|
||||
/* install the thread's endpoint selector to the PD's CSpace */
|
||||
_pd->cspace_cnode(_ep_sel).copy(platform_specific().core_cnode(),
|
||||
_info.ep_sel, _ep_sel);
|
||||
_pd.cspace_cnode(_ep_sel).copy(platform_specific().core_cnode(),
|
||||
_info.ep_sel, _ep_sel);
|
||||
|
||||
/* install the thread's notification object to the PD's CSpace */
|
||||
_pd->cspace_cnode(_lock_sel).mint(platform_specific().core_cnode(),
|
||||
_info.lock_sel, _lock_sel);
|
||||
_pd.cspace_cnode(_lock_sel).mint(platform_specific().core_cnode(),
|
||||
_info.lock_sel, _lock_sel);
|
||||
|
||||
/*
|
||||
* Populate the thread's IPC buffer with initial information about the
|
||||
@ -168,21 +167,20 @@ int Platform_thread::start(void *ip, void *sp, unsigned int)
|
||||
|
||||
/* bind thread to PD and CSpace */
|
||||
seL4_CNode_CapData const guard_cap_data =
|
||||
seL4_CNode_CapData_new(0, CONFIG_WORD_SIZE - _pd->cspace_size_log2());
|
||||
seL4_CNode_CapData_new(0, CONFIG_WORD_SIZE - _pd.cspace_size_log2());
|
||||
|
||||
seL4_CNode_CapData const no_cap_data = { { 0 } };
|
||||
|
||||
int const ret = seL4_TCB_SetSpace(_info.tcb_sel.value(),
|
||||
_fault_handler_sel.value(),
|
||||
_pd->cspace_cnode_1st().sel().value(),
|
||||
_pd.cspace_cnode_1st().sel().value(),
|
||||
guard_cap_data.words[0],
|
||||
_pd->page_directory_sel().value(),
|
||||
_pd.page_directory_sel().value(),
|
||||
no_cap_data.words[0]);
|
||||
ASSERT(ret == 0);
|
||||
|
||||
start_sel4_thread(_info.tcb_sel, (addr_t)ip, (addr_t)(sp), _location.xpos(),
|
||||
_utcb);
|
||||
return 0;
|
||||
_utcb.addr);
|
||||
}
|
||||
|
||||
|
||||
@ -207,17 +205,18 @@ void Platform_thread::state(Thread_state) { }
|
||||
|
||||
bool Platform_thread::install_mapping(Mapping const &mapping)
|
||||
{
|
||||
return _pd->install_mapping(mapping, name());
|
||||
return _pd.install_mapping(mapping, name());
|
||||
}
|
||||
|
||||
|
||||
Platform_thread::Platform_thread(size_t, const char *name, unsigned priority,
|
||||
Affinity::Location location, addr_t utcb)
|
||||
Platform_thread::Platform_thread(Platform_pd &pd, size_t, const char *name,
|
||||
unsigned priority, Affinity::Location location,
|
||||
addr_t utcb)
|
||||
:
|
||||
_name(name),
|
||||
_utcb(utcb ? utcb : addr_t(INITIAL_IPC_BUFFER_VIRT)),
|
||||
_pager_obj_sel(platform_specific().core_sel_alloc().alloc()),
|
||||
_location(location),
|
||||
_pd(pd), _location(location),
|
||||
_priority((uint16_t)(Cpu_session::scale_priority(CONFIG_NUM_PRIORITIES, priority)))
|
||||
|
||||
{
|
||||
@ -228,14 +227,52 @@ Platform_thread::Platform_thread(size_t, const char *name, unsigned priority,
|
||||
|
||||
_info.init(_utcb, _priority);
|
||||
platform_thread_registry().insert(*this);
|
||||
|
||||
try {
|
||||
/* allocate fault handler selector in the PD's CSpace */
|
||||
_fault_handler_sel = _pd.alloc_sel();
|
||||
/* allocate endpoint selector in the PD's CSpace */
|
||||
_ep_sel = _pd.alloc_sel();
|
||||
_vcpu_sel = _pd.alloc_sel();
|
||||
/* allocate asynchronous selector used for locks in the PD's CSpace */
|
||||
_lock_sel = main_thread() ? Cap_sel(INITIAL_SEL_LOCK)
|
||||
: _pd.alloc_sel();
|
||||
_vcpu_notify_sel = _pd.alloc_sel();
|
||||
|
||||
_pd.map_ipc_buffer(_info.ipc_buffer_phys, _utcb);
|
||||
_bound_to_pd = true;
|
||||
} catch (Platform_pd::Sel_alloc::Out_of_indices) {
|
||||
|
||||
/* revert allocations */
|
||||
if (_fault_handler_sel.value()) _pd.free_sel(_fault_handler_sel);
|
||||
if (_ep_sel.value()) _pd.free_sel(_ep_sel);
|
||||
if (_vcpu_sel.value()) _pd.free_sel(_vcpu_sel);
|
||||
if (_vcpu_notify_sel.value()) _pd.free_sel(_vcpu_notify_sel);
|
||||
|
||||
_fault_handler_sel = Cap_sel { 0 };
|
||||
_ep_sel = Cap_sel { 0 };
|
||||
_vcpu_sel = Cap_sel { 0 };
|
||||
_vcpu_notify_sel = Cap_sel { 0 };
|
||||
|
||||
_bound_to_pd = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Platform_thread::~Platform_thread()
|
||||
{
|
||||
if (_pd) {
|
||||
seL4_TCB_Suspend(_info.tcb_sel.value());
|
||||
_pd->unbind_thread(*this);
|
||||
seL4_TCB_Suspend(_info.tcb_sel.value());
|
||||
|
||||
if (_bound_to_pd) {
|
||||
if (!main_thread())
|
||||
_pd.free_sel(_lock_sel);
|
||||
|
||||
_pd.free_sel(_fault_handler_sel);
|
||||
_pd.free_sel(_ep_sel);
|
||||
_pd.free_sel(_vcpu_sel);
|
||||
_pd.free_sel(_vcpu_notify_sel);
|
||||
|
||||
_pd.unmap_ipc_buffer(_utcb);
|
||||
}
|
||||
|
||||
if (_pager) {
|
||||
@ -252,6 +289,7 @@ Platform_thread::~Platform_thread()
|
||||
platform_specific().core_sel_alloc().free(_pager_obj_sel);
|
||||
}
|
||||
|
||||
|
||||
Trace::Execution_time Platform_thread::execution_time() const
|
||||
{
|
||||
if (!Thread::myself() || !Thread::myself()->utcb()) {
|
||||
@ -271,6 +309,7 @@ Trace::Execution_time Platform_thread::execution_time() const
|
||||
return { ec_time, sc_time, 10000, _priority};
|
||||
}
|
||||
|
||||
|
||||
void Platform_thread::setup_vcpu(Cap_sel ept, Cap_sel notification)
|
||||
{
|
||||
if (!_info.init_vcpu(platform_specific(), ept)) {
|
||||
@ -279,10 +318,10 @@ void Platform_thread::setup_vcpu(Cap_sel ept, Cap_sel notification)
|
||||
}
|
||||
|
||||
/* install the thread's endpoint selector to the PD's CSpace */
|
||||
_pd->cspace_cnode(_vcpu_sel).copy(platform_specific().core_cnode(),
|
||||
_info.vcpu_sel, _vcpu_sel);
|
||||
_pd->cspace_cnode(_vcpu_notify_sel).copy(platform_specific().core_cnode(),
|
||||
notification, _vcpu_notify_sel);
|
||||
_pd.cspace_cnode(_vcpu_sel).copy(platform_specific().core_cnode(),
|
||||
_info.vcpu_sel, _vcpu_sel);
|
||||
_pd.cspace_cnode(_vcpu_notify_sel).copy(platform_specific().core_cnode(),
|
||||
notification, _vcpu_notify_sel);
|
||||
|
||||
prepopulate_ipc_buffer(_info.ipc_buffer_phys, _vcpu_sel, _vcpu_notify_sel,
|
||||
_utcb);
|
||||
|
@ -32,7 +32,7 @@ using namespace Core;
|
||||
|
||||
void Thread::_init_platform_thread(size_t, Type type)
|
||||
{
|
||||
addr_t const utcb_virt_addr = (addr_t)&_stack->utcb();
|
||||
Utcb_virt const utcb_virt { (addr_t)&_stack->utcb() };
|
||||
|
||||
if (type == MAIN) {
|
||||
native_thread().tcb_sel = seL4_CapInitThreadTCB;
|
||||
@ -41,12 +41,12 @@ void Thread::_init_platform_thread(size_t, Type type)
|
||||
}
|
||||
|
||||
Thread_info thread_info;
|
||||
thread_info.init(utcb_virt_addr, CONFIG_NUM_PRIORITIES - 1);
|
||||
thread_info.init(utcb_virt, CONFIG_NUM_PRIORITIES - 1);
|
||||
|
||||
if (!map_local(thread_info.ipc_buffer_phys, utcb_virt_addr, 1)) {
|
||||
if (!map_local(thread_info.ipc_buffer_phys.addr, utcb_virt.addr, 1)) {
|
||||
error(__func__, ": could not map IPC buffer "
|
||||
"phys=", Hex(thread_info.ipc_buffer_phys), " "
|
||||
"local=%", Hex(utcb_virt_addr));
|
||||
"phys=", Hex(thread_info.ipc_buffer_phys.addr), " "
|
||||
"local=%", Hex(utcb_virt.addr));
|
||||
}
|
||||
|
||||
native_thread().tcb_sel = thread_info.tcb_sel.value();
|
||||
@ -102,7 +102,7 @@ void Thread::_thread_start()
|
||||
Thread::Start_result Thread::start()
|
||||
{
|
||||
/* write ipcbuffer address to utcb*/
|
||||
utcb()->ipcbuffer(addr_t(utcb()));
|
||||
utcb()->ipcbuffer(Native_utcb::Virt { addr_t(utcb()) });
|
||||
|
||||
start_sel4_thread(Cap_sel(native_thread().tcb_sel), (addr_t)&_thread_start,
|
||||
(addr_t)stack_top(), _affinity.xpos(), addr_t(utcb()));
|
||||
|
@ -38,7 +38,9 @@ struct Genode::Native_utcb
|
||||
|
||||
static addr_t constexpr tls_ipcbuffer_offset = (ELEMENTS - 3) * sizeof(_raw[0]);
|
||||
|
||||
void ipcbuffer(addr_t const addr) { _raw[ELEMENTS - 3] = addr; }
|
||||
struct Virt { addr_t addr; };
|
||||
|
||||
void ipcbuffer(Virt const virt) { _raw[ELEMENTS - 3] = virt.addr; }
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__BASE__INTERNAL__NATIVE_UTCB_H_ */
|
||||
|
@ -57,27 +57,33 @@ Cpu_session_component::create_thread(Capability<Pd_session> pd_cap,
|
||||
|
||||
Mutex::Guard slab_lock_guard(_thread_alloc_lock);
|
||||
|
||||
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, name,
|
||||
_priority, utcb);
|
||||
pd->with_threads([&] (Pd_session_component::Threads &pd_threads) {
|
||||
pd->with_platform_pd([&] (Platform_pd &platform_pd) {
|
||||
try {
|
||||
Cpu_thread_component &thread = *new (&_thread_alloc)
|
||||
Cpu_thread_component(
|
||||
cap(), *this, _thread_ep, _pager_ep, *pd, platform_pd,
|
||||
pd_threads, _trace_control_area, _trace_sources,
|
||||
weight, _weight_to_quota(weight.value),
|
||||
_thread_affinity(affinity), _label, name,
|
||||
_priority, utcb);
|
||||
|
||||
if (!thread.valid()) {
|
||||
destroy(_thread_alloc, &thread);
|
||||
return;
|
||||
}
|
||||
if (!thread.valid()) { /* 'Platform_thread' creation failed */
|
||||
destroy(&_thread_alloc, &thread);
|
||||
result = Create_thread_error::DENIED;
|
||||
return;
|
||||
}
|
||||
|
||||
thread.session_exception_sigh(_exception_sigh);
|
||||
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_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; }
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if (result.failed()) {
|
||||
|
@ -12,7 +12,7 @@
|
||||
*/
|
||||
|
||||
/* core includes */
|
||||
#include <cpu_thread_component.h>
|
||||
#include <cpu_session_component.h>
|
||||
|
||||
using namespace Core;
|
||||
|
||||
@ -26,6 +26,9 @@ void Cpu_thread_component::_update_exception_sigh()
|
||||
}
|
||||
|
||||
|
||||
void Cpu_thread_component::destroy() { _cpu.kill_thread(cap()); }
|
||||
|
||||
|
||||
void Cpu_thread_component::quota(size_t quota)
|
||||
{
|
||||
_platform_thread.quota(quota);
|
||||
|
@ -28,7 +28,10 @@
|
||||
#include <trace/control_area.h>
|
||||
#include <trace/source_registry.h>
|
||||
|
||||
namespace Core { class Cpu_thread_component; }
|
||||
namespace Core {
|
||||
class Cpu_session_component;
|
||||
class Cpu_thread_component;
|
||||
}
|
||||
|
||||
|
||||
class Core::Cpu_thread_component : public Rpc_object<Cpu_thread>,
|
||||
@ -39,6 +42,8 @@ class Core::Cpu_thread_component : public Rpc_object<Cpu_thread>,
|
||||
|
||||
typedef Trace::Thread_name Thread_name;
|
||||
|
||||
using Pd_threads = Pd_session_component::Threads;
|
||||
|
||||
private:
|
||||
|
||||
friend class List<Cpu_thread_component>;
|
||||
@ -46,17 +51,13 @@ class Core::Cpu_thread_component : public Rpc_object<Cpu_thread>,
|
||||
|
||||
Rpc_entrypoint &_ep;
|
||||
Pager_entrypoint &_pager_ep;
|
||||
Cpu_session_component &_cpu;
|
||||
Region_map_component &_address_space_region_map;
|
||||
Cpu_session::Weight const _weight;
|
||||
Session_label const _session_label;
|
||||
Thread_name const _name;
|
||||
Pd_threads::Element _pd_element;
|
||||
Platform_thread _platform_thread;
|
||||
bool const _bound_to_pd;
|
||||
|
||||
bool _bind_to_pd(Pd_session_component &pd)
|
||||
{
|
||||
return pd.bind_thread(_platform_thread);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception handler as defined by 'Cpu_session::exception_sigh'
|
||||
@ -138,9 +139,12 @@ class Core::Cpu_thread_component : public Rpc_object<Cpu_thread>,
|
||||
* \param utcb user-local UTCB base
|
||||
*/
|
||||
Cpu_thread_component(Cpu_session_capability cpu_session_cap,
|
||||
Cpu_session_component &cpu,
|
||||
Rpc_entrypoint &ep,
|
||||
Pager_entrypoint &pager_ep,
|
||||
Pd_session_component &pd,
|
||||
Platform_pd &platform_pd,
|
||||
Pd_threads &pd_threads,
|
||||
Trace::Control_area &trace_control_area,
|
||||
Trace::Source_registry &trace_sources,
|
||||
Cpu_session::Weight weight,
|
||||
@ -151,12 +155,12 @@ class Core::Cpu_thread_component : public Rpc_object<Cpu_thread>,
|
||||
unsigned priority,
|
||||
addr_t utcb)
|
||||
:
|
||||
_ep(ep), _pager_ep(pager_ep),
|
||||
_ep(ep), _pager_ep(pager_ep), _cpu(cpu),
|
||||
_address_space_region_map(pd.address_space_region_map()),
|
||||
_weight(weight),
|
||||
_session_label(label), _name(name),
|
||||
_platform_thread(quota, name.string(), priority, location, utcb),
|
||||
_bound_to_pd(_bind_to_pd(pd)),
|
||||
_pd_element(pd_threads, *this),
|
||||
_platform_thread(platform_pd, quota, name.string(), priority, location, utcb),
|
||||
_trace_control_slot(trace_control_area),
|
||||
_trace_sources(trace_sources),
|
||||
_managed_thread_cap(_ep, *this),
|
||||
@ -181,7 +185,9 @@ 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; };
|
||||
bool valid() { return _platform_thread.valid(); }
|
||||
|
||||
void destroy(); /* solely called by ~Pd_session_component */
|
||||
|
||||
|
||||
/********************************************
|
||||
|
@ -38,7 +38,10 @@
|
||||
#include <platform_generic.h>
|
||||
#include <account.h>
|
||||
|
||||
namespace Core { class Pd_session_component; }
|
||||
namespace Core {
|
||||
class Pd_session_component;
|
||||
class Cpu_thread_component;
|
||||
}
|
||||
|
||||
|
||||
class Core::Pd_session_component : public Session_object<Pd_session>
|
||||
@ -47,6 +50,8 @@ class Core::Pd_session_component : public Session_object<Pd_session>
|
||||
|
||||
enum class Managing_system { DENIED, PERMITTED };
|
||||
|
||||
using Threads = Registry<Cpu_thread_component>;
|
||||
|
||||
private:
|
||||
|
||||
Constructible<Account<Cap_quota> > _cap_account { };
|
||||
@ -71,6 +76,8 @@ class Core::Pd_session_component : public Session_object<Pd_session>
|
||||
|
||||
Managing_system _managing_system;
|
||||
|
||||
Threads _threads { };
|
||||
|
||||
friend class Native_pd_component;
|
||||
|
||||
|
||||
@ -159,6 +166,8 @@ class Core::Pd_session_component : public Session_object<Pd_session>
|
||||
}
|
||||
}
|
||||
|
||||
~Pd_session_component();
|
||||
|
||||
/**
|
||||
* Initialize cap and RAM accounts without providing a reference account
|
||||
*
|
||||
@ -171,20 +180,16 @@ class Core::Pd_session_component : public Session_object<Pd_session>
|
||||
_ram_account.construct(_ram_quota_guard(), _label);
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate thread with PD
|
||||
*
|
||||
* \return true on success
|
||||
*
|
||||
* This function may fail for platform-specific reasons such as a
|
||||
* limit on the number of threads per protection domain or a limited
|
||||
* thread ID namespace.
|
||||
*/
|
||||
bool bind_thread(Platform_thread &thread)
|
||||
void with_platform_pd(auto const &fn)
|
||||
{
|
||||
return _pd->bind_thread(thread);
|
||||
if (_pd.constructed())
|
||||
fn(*_pd);
|
||||
else
|
||||
error("unexpected call for 'with_platform_pd'");
|
||||
}
|
||||
|
||||
void with_threads(auto const &fn) { fn(_threads); }
|
||||
|
||||
Region_map_component &address_space_region_map()
|
||||
{
|
||||
return _address_space;
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
/* core includes */
|
||||
#include <pd_session_component.h>
|
||||
#include <cpu_session_component.h>
|
||||
|
||||
using namespace Core;
|
||||
|
||||
@ -207,3 +208,15 @@ Pd_session_component::attach_dma(Dataspace_capability ds_cap, addr_t at)
|
||||
|
||||
return _address_space.attach_dma(ds_cap, at);
|
||||
}
|
||||
|
||||
|
||||
Pd_session_component::~Pd_session_component()
|
||||
{
|
||||
/*
|
||||
* As `Platform_thread` objects point to their corresponding `Platform_pd`
|
||||
* objects, we need to destroy the threads when the `Platform_pd` ceases to
|
||||
* exist.
|
||||
*/
|
||||
_threads.for_each([&] (Cpu_thread_component &thread) {
|
||||
thread.destroy(); });
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user