mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-23 17:17:38 +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:
@ -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();
|
||||
|
Reference in New Issue
Block a user