genode/ports-okl4/src/lib/oklx/genode/genode_threads.cc

180 lines
3.5 KiB
C++

/*
* \brief Genode C API thread functions needed by OKLinux
* \author Stefan Kalkowski
* \date 2009-05-19
*/
/*
* Copyright (C) 2009-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/printf.h>
/* OKLinux support library */
#include <oklx_threads.h>
namespace Okl4 {
extern "C" {
#include <iguana/thread.h>
#include <genode/sleep.h>
}
}
using namespace Genode;
using namespace Okl4;
static Thread_capability oklx_pager_cap; /* cap to the Linux main thread */
/**
* Get the thread capability of the active kernel thread
*/
static Thread_capability my_cap()
{
Okl4::L4_Word_t tid = thread_myself();
Oklx_kernel_thread * thread = Genode::Oklx_thread_list::thread_list()->first();
while (thread) {
if (thread->tid().raw == tid)
return thread->cap();
thread = thread->next();
}
/* invalid cap */
return Thread_capability();
}
void Oklx_kernel_thread::entry()
{
L4_ThreadId_t tid;
/* Save our thread id to the first entry in the UTCB */
__L4_TCR_Set_ThreadWord(0, L4_UserDefinedHandle());
/* Synchronize with the thread, that created us and sleep afterwards */
L4_Wait(&tid);
sleep_forever();
}
L4_ThreadId_t Oklx_thread_list::add()
{
try
{
/* Create the thread an start it immediately */
Thread_capability cap = _cpu.create_thread("Lx_kernel_thread");
Oklx_kernel_thread *thd = new (env()->heap()) Oklx_kernel_thread(cap);
_threads.insert(thd);
env()->pd_session()->bind_thread(cap);
Pager_capability pager = env()->rm_session()->add_client(cap);
_cpu.set_pager(cap, pager);
_cpu.start(cap, (addr_t)&Oklx_kernel_thread::entry,
(addr_t)thd->stack_addr());
/* Get the OKL4 thread id of the new thread */
Thread_state state = _cpu.state(cap);
thd->set_tid(state.tid);
/* Acknowledge startup and return */
L4_Send(state.tid);
return state.tid;
}
catch(...)
{
PWRN("Creation of new thread failed!");
return L4_nilthread;
}
}
Oklx_thread_list* Oklx_thread_list::thread_list()
{
static Oklx_thread_list _list;
return &_list;
}
Oklx_process::~Oklx_process()
{
/* When the process dies, kill all of its threads */
while(_threads.first())
{
Oklx_user_thread *th = _threads.first();
_threads.remove(th);
destroy(env()->heap(), th);
}
}
L4_ThreadId_t
Oklx_process::add_thread()
{
Oklx_user_thread *th = 0;
try {
Thread_state dst_state;
th = new (env()->heap()) Oklx_user_thread();
_pd.bind_thread(th->cap());
/*
* Initialize eip and esp with max. value to signal
* core, that it doesn't really need to start this thread,
* but will create the OKL4 thread inactive
*/
_cpu.start(th->cap(), 0xffffffff, 0xffffffff);
dst_state = _cpu.state(th->cap());
th->_tid = dst_state.tid;
_threads.insert(th);
return th->_tid;
}
catch(...)
{
PWRN("Couldn't create a new Thread for space %lx", _pd.space_id().raw);
if(th)
destroy(env()->heap(), th);
return L4_nilthread;
}
}
bool
Oklx_process::kill_thread(Okl4::L4_ThreadId_t tid)
{
Oklx_user_thread *th = _threads.first();
while (th)
{
if(th->tid().raw == tid.raw)
{
_threads.remove(th);
destroy(env()->heap(), th);
return true;
}
th = th->next();
}
return false;
}
List<Oklx_process>*
Oklx_process::processes()
{
static List<Oklx_process> _list;
return &_list;
}
void Oklx_process::set_pager()
{
oklx_pager_cap = my_cap();
}
Thread_capability Oklx_process::pager_cap()
{
return oklx_pager_cap;
}