base: add cpu_session parameter to thread creation

Fixes #1114
This commit is contained in:
Alexander Boettcher 2014-04-03 14:18:52 +02:00 committed by Christian Helmuth
parent 5169de72c4
commit 03ce614c23
15 changed files with 156 additions and 60 deletions

View File

@ -41,32 +41,36 @@ void Thread_base::_thread_start()
void Thread_base::_deinit_platform_thread()
{
env()->cpu_session()->kill_thread(_thread_cap);
_cpu_session->kill_thread(_thread_cap);
env()->rm_session()->remove_client(_pager_cap);
}
void Thread_base::start()
{
/* if no cpu session is given, use it from the environment */
if (!_cpu_session)
_cpu_session = env()->cpu_session();
/* create thread at core */
char buf[48];
name(buf, sizeof(buf));
_thread_cap = env()->cpu_session()->create_thread(buf);
_thread_cap = _cpu_session->create_thread(buf);
/* assign thread to protection domain */
env()->pd_session()->bind_thread(_thread_cap);
/* create new pager object and assign it to the new thread */
_pager_cap = env()->rm_session()->add_client(_thread_cap);
env()->cpu_session()->set_pager(_thread_cap, _pager_cap);
_cpu_session->set_pager(_thread_cap, _pager_cap);
/* register initial IP and SP at core */
env()->cpu_session()->start(_thread_cap, (addr_t)_thread_start, _context->stack_top());
_cpu_session->start(_thread_cap, (addr_t)_thread_start, _context->stack_top());
}
void Thread_base::cancel_blocking()
{
Codezero::l4_mutex_unlock(utcb()->running_lock());
env()->cpu_session()->cancel_blocking(_thread_cap);
_cpu_session->cancel_blocking(_thread_cap);
}

View File

@ -186,8 +186,10 @@ void Thread_base::free_secondary_stack(void* stack_addr)
}
Thread_base::Thread_base(const char *name, size_t stack_size, Type const type)
Thread_base::Thread_base(const char *name, size_t stack_size, Type const type,
Cpu_session *cpu_session)
:
_cpu_session(cpu_session),
_context(type == REINITIALIZED_MAIN ?
_context : _alloc_context(stack_size, type == MAIN)),
_join_lock(Lock::LOCKED)
@ -197,6 +199,10 @@ Thread_base::Thread_base(const char *name, size_t stack_size, Type const type)
}
Thread_base::Thread_base(const char *name, size_t stack_size, Type type)
: Thread_base(name, stack_size, type, nullptr) { }
Thread_base::~Thread_base()
{
_deinit_platform_thread();

View File

@ -33,7 +33,7 @@ void Thread_base::_deinit_platform_thread()
if (_context->utcb && _thread_cap.valid()) {
Cap_index *i = (Cap_index*)l4_utcb_tcr_u(_context->utcb)->user[UTCB_TCR_BADGE];
cap_map()->remove(i);
env()->cpu_session()->kill_thread(_thread_cap);
_cpu_session->kill_thread(_thread_cap);
env()->rm_session()->remove_client(_pager_cap);
}
}
@ -41,12 +41,16 @@ void Thread_base::_deinit_platform_thread()
void Thread_base::_init_platform_thread(Type type)
{
/* if no cpu session is given, use it from the environment */
if (!_cpu_session)
_cpu_session = env()->cpu_session();
if (type == NORMAL)
{
/* create thread at core */
char buf[48];
name(buf, sizeof(buf));
_thread_cap = env()->cpu_session()->create_thread(buf);
_thread_cap = _cpu_session->create_thread(buf);
/* assign thread to protection domain */
env()->pd_session()->bind_thread(_thread_cap);
@ -68,11 +72,11 @@ void Thread_base::start()
/* create new pager object and assign it to the new thread */
_pager_cap = env()->rm_session()->add_client(_thread_cap);
env()->cpu_session()->set_pager(_thread_cap, _pager_cap);
_cpu_session->set_pager(_thread_cap, _pager_cap);
/* get gate-capability and badge of new thread */
Thread_state state;
try { state = env()->cpu_session()->state(_thread_cap); }
try { state = _cpu_session->state(_thread_cap); }
catch (...) { throw Cpu_session::Thread_creation_failed(); }
_tid = state.kcap;
_context->utcb = state.utcb;
@ -82,11 +86,11 @@ void Thread_base::start()
l4_utcb_tcr_u(state.utcb)->user[UTCB_TCR_THREAD_OBJ] = (addr_t)this;
/* register initial IP and SP at core */
env()->cpu_session()->start(_thread_cap, (addr_t)_thread_start, _context->stack_top());
_cpu_session->start(_thread_cap, (addr_t)_thread_start, _context->stack_top());
}
void Thread_base::cancel_blocking()
{
env()->cpu_session()->cancel_blocking(_thread_cap);
_cpu_session->cancel_blocking(_thread_cap);
}

View File

@ -73,14 +73,17 @@ void Thread_base::_thread_bootstrap()
void Thread_base::_init_platform_thread(Type type)
{
/* if no cpu session is given, use it from the environment */
if (!_cpu_session)
_cpu_session = env()->cpu_session();
/* nothing platform specific to do if this is not a special thread */
if (type == NORMAL)
{
/* create server object */
char buf[48];
name(buf, sizeof(buf));
Cpu_session * cpu = env()->cpu_session();
_thread_cap = cpu->create_thread(buf, (addr_t)&_context->utcb);
_thread_cap = _cpu_session->create_thread(buf, (addr_t)&_context->utcb);
return;
}

View File

@ -52,7 +52,7 @@ void Thread_base::_deinit_platform_thread()
env_context_area_rm_session()->detach(utcb);
/* destroy server object */
env()->cpu_session()->kill_thread(_thread_cap);
_cpu_session->kill_thread(_thread_cap);
if (_pager_cap.valid()) {
env()->rm_session()->remove_client(_pager_cap);
}
@ -66,11 +66,11 @@ void Thread_base::start()
/* create pager object and assign it to the thread */
_pager_cap = env()->rm_session()->add_client(_thread_cap);
env()->cpu_session()->set_pager(_thread_cap, _pager_cap);
_cpu_session->set_pager(_thread_cap, _pager_cap);
/* attach userland thread-context */
try {
Ram_dataspace_capability ds = env()->cpu_session()->utcb(_thread_cap);
Ram_dataspace_capability ds = _cpu_session->utcb(_thread_cap);
size_t const size = sizeof(_context->utcb);
addr_t dst = Context_allocator::addr_to_base(_context) +
Native_config::context_virtual_size() - size -
@ -81,11 +81,11 @@ void Thread_base::start()
sleep_forever();
}
/* start thread with its initial IP and aligned SP */
env()->cpu_session()->start(_thread_cap, (addr_t)_thread_start, _context->stack_top());
_cpu_session->start(_thread_cap, (addr_t)_thread_start, _context->stack_top());
}
void Thread_base::cancel_blocking()
{
env()->cpu_session()->cancel_blocking(_thread_cap);
_cpu_session->cancel_blocking(_thread_cap);
}

View File

@ -53,7 +53,7 @@ void Thread_base::_thread_start()
Thread_base * const thread = Thread_base::myself();
/* inform core about the new thread and process ID of the new thread */
Linux_cpu_session *cpu = dynamic_cast<Linux_cpu_session *>(env()->cpu_session());
Linux_cpu_session *cpu = dynamic_cast<Linux_cpu_session *>(thread->_cpu_session);
if (cpu)
cpu->thread_id(thread->cap(), thread->tid().pid, thread->tid().tid);
@ -71,9 +71,13 @@ void Thread_base::_thread_start()
void Thread_base::_init_platform_thread(Type type)
{
/* if no cpu session is given, use it from the environment */
if (!_cpu_session)
_cpu_session = env()->cpu_session();
/* for normal threads create an object at the CPU session */
if (type == NORMAL) {
_thread_cap = env()->cpu_session()->create_thread(_context->name);
_thread_cap = _cpu_session->create_thread(_context->name);
return;
}
/* adjust initial object state for main threads */
@ -109,7 +113,7 @@ void Thread_base::_deinit_platform_thread()
}
/* inform core about the killed thread */
env()->cpu_session()->kill_thread(_thread_cap);
_cpu_session->kill_thread(_thread_cap);
}
@ -141,5 +145,5 @@ void Thread_base::start()
void Thread_base::cancel_blocking()
{
env()->cpu_session()->cancel_blocking(_thread_cap);
_cpu_session->cancel_blocking(_thread_cap);
}

View File

@ -276,9 +276,9 @@ namespace Genode {
/**
* Return Linux-specific extension of the Env::CPU session interface
*/
Linux_cpu_session *cpu_session()
Linux_cpu_session *cpu_session(Cpu_session * cpu_session)
{
Linux_cpu_session *cpu = dynamic_cast<Linux_cpu_session *>(env()->cpu_session());
Linux_cpu_session *cpu = dynamic_cast<Linux_cpu_session *>(cpu_session);
if (!cpu) {
PERR("could not obtain Linux extension to CPU session interface");
@ -401,7 +401,9 @@ void Thread_base::join()
}
Thread_base::Thread_base(const char *name, size_t stack_size, Type)
Thread_base::Thread_base(const char *name, size_t stack_size, Type type,
Cpu_session * cpu_sess)
: _cpu_session(cpu_sess)
{
_tid.meta_data = new (env()->heap()) Thread_meta_data_created(this);
@ -416,19 +418,16 @@ Thread_base::Thread_base(const char *name, size_t stack_size, Type)
_tid.meta_data->wait_for_construction();
Linux_cpu_session *cpu = dynamic_cast<Linux_cpu_session *>(env()->cpu_session());
Linux_cpu_session *cpu = cpu_session(_cpu_session);
if (!cpu) {
PERR("could not obtain Linux extension to CPU session interface");
struct Could_not_access_linux_cpu_session { };
throw Could_not_access_linux_cpu_session();
}
_thread_cap = cpu_session()->create_thread(name);
cpu_session()->thread_id(_thread_cap, _tid.pid, _tid.tid);
_thread_cap = cpu->create_thread(name);
cpu->thread_id(_thread_cap, _tid.pid, _tid.tid);
}
Thread_base::Thread_base(const char *name, size_t stack_size, Type type)
: Thread_base(name, stack_size, type, env()->cpu_session()) { }
void Thread_base::cancel_blocking()
{
/*
@ -457,5 +456,5 @@ Thread_base::~Thread_base()
_tid.meta_data = 0;
/* inform core about the killed thread */
cpu_session()->kill_thread(_thread_cap);
cpu_session(_cpu_session)->kill_thread(_thread_cap);
}

View File

@ -20,7 +20,6 @@
/* NOVA includes */
#include <nova/syscalls.h>
#include <nova_cpu_session/connection.h>
#include <nova/util.h>
using namespace Genode;
@ -206,7 +205,7 @@ Rpc_entrypoint::Rpc_entrypoint(Cap_session *cap_session, size_t stack_size,
/* place new thread on the specified CPU */
if (location.valid())
env()->cpu_session()->affinity(_thread_cap, location);
_cpu_session->affinity(_thread_cap, location);
/* magic value evaluated by thread_nova.cc to start a local thread */
_tid.ec_sel = Native_thread::INVALID_INDEX - 1;

View File

@ -87,11 +87,15 @@ void Thread_base::_init_platform_thread(Type type)
if (_tid.exc_pt_sel == Native_thread::INVALID_INDEX)
throw Cpu_session::Thread_creation_failed();
/* if no cpu session is given, use it from the environment */
if (!_cpu_session)
_cpu_session = env()->cpu_session();
/* create thread at core */
char buf[48];
name(buf, sizeof(buf));
_thread_cap = env()->cpu_session()->create_thread(buf);
_thread_cap = _cpu_session->create_thread(buf);
if (!_thread_cap.valid())
throw Cpu_session::Thread_creation_failed();
@ -121,7 +125,7 @@ void Thread_base::_deinit_platform_thread()
/* de-announce thread */
if (_thread_cap.valid())
env()->cpu_session()->kill_thread(_thread_cap);
_cpu_session->kill_thread(_thread_cap);
if (_pager_cap.valid())
env()->rm_session()->remove_client(_pager_cap);
@ -146,7 +150,7 @@ void Thread_base::start()
if (!_pager_cap.valid())
throw Cpu_session::Thread_creation_failed();
if (env()->cpu_session()->set_pager(_thread_cap, _pager_cap))
if (_cpu_session->set_pager(_thread_cap, _pager_cap))
throw Cpu_session::Thread_creation_failed();
/* create EC at core */
@ -157,10 +161,10 @@ void Thread_base::start()
/* local thread have no start instruction pointer - set via portal entry */
addr_t thread_ip = global ? reinterpret_cast<addr_t>(_thread_start) : 0;
try { env()->cpu_session()->state(_thread_cap, state); }
try { _cpu_session->state(_thread_cap, state); }
catch (...) { throw Cpu_session::Thread_creation_failed(); }
if (env()->cpu_session()->start(_thread_cap, thread_ip, _context->stack_top()))
if (_cpu_session->start(_thread_cap, thread_ip, _context->stack_top()))
throw Cpu_session::Thread_creation_failed();
/* request native EC thread cap */
@ -184,7 +188,7 @@ void Thread_base::start()
if (global)
/* request creation of SC to let thread run*/
env()->cpu_session()->resume(_thread_cap);
_cpu_session->resume(_thread_cap);
}

View File

@ -64,7 +64,7 @@
#include <util/bit_allocator.h>
#include <ram_session/ram_session.h> /* for 'Ram_dataspace_capability' type */
#include <cpu_session/cpu_session.h> /* for 'Thread_capability' type */
#include <cpu_session/capability.h> /* for 'Cpu_session_capability' type */
namespace Genode {
@ -284,6 +284,11 @@ namespace Genode {
*/
Genode::Pager_capability _pager_cap;
/**
* Pointer to cpu session used for this thread
*/
Genode::Cpu_session *_cpu_session;
/**
* Pointer to primary thread context
*/
@ -321,7 +326,7 @@ namespace Genode {
/**
* Hook for platform-specific constructor supplements
*
* \param main_thread wether this is the main thread
* \param main_thread whether this is the main thread
*/
void _init_platform_thread(Type type);
@ -352,6 +357,21 @@ namespace Genode {
Thread_base(const char *name, size_t stack_size,
Type type = NORMAL);
/**
* Constructor
*
* \param name thread name for debugging
* \param stack_size stack size
* \param type enables selection of special construction
* \param cpu_session capability to cpu session used for construction
*
* \throw Stack_too_large
* \throw Stack_alloc_failed
* \throw Context_alloc_failed
*/
Thread_base(const char *name, size_t stack_size, Type type,
Cpu_session *);
/**
* Destructor
*/
@ -498,6 +518,15 @@ namespace Genode {
*/
explicit Thread(const char *name, Type type = NORMAL)
: Thread_base(name, STACK_SIZE, type) { }
/**
* Constructor
*
* \param name thread name (for debugging)
* \param cpu_session thread created via specific cpu session
*/
explicit Thread(const char *name, Cpu_session * cpu_session)
: Thread_base(name, STACK_SIZE, Type::NORMAL, cpu_session) { }
};
}

View File

@ -7,6 +7,7 @@ install_config {
<parent-provides>
<service name="LOG"/>
<service name="RM"/>
<service name="CPU"/>
</parent-provides>
<default-route>
<any-service> <parent/> </any-service>
@ -21,6 +22,6 @@ build_boot_image "core init test-thread"
append qemu_args "-nographic -m 64"
run_genode_until "child exited with exit value 0.*\n" 10
run_genode_until "child exited with exit value 0.*\n" 20
puts "Test succeeded"

View File

@ -26,6 +26,7 @@ using namespace Genode;
* This function is provided by the process environment.
*/
namespace Genode {
Rm_session *env_context_area_rm_session();
Ram_session *env_context_area_ram_session();
}
@ -108,7 +109,7 @@ Thread_base::_alloc_context(size_t stack_size, bool main_thread)
ds_cap = env_context_area_ram_session()->alloc(ds_size);
addr_t attach_addr = ds_addr - Native_config::context_area_virtual_base();
if (attach_addr != (addr_t)env_context_area_rm_session()->attach_at(ds_cap, attach_addr, ds_size))
throw Stack_alloc_failed();
throw Stack_alloc_failed();
}
catch (Ram_session::Alloc_failed) { throw Stack_alloc_failed(); }
@ -172,10 +173,7 @@ Thread_base *Thread_base::myself()
}
void Thread_base::join()
{
_join_lock.lock();
}
void Thread_base::join() { _join_lock.lock(); }
void* Thread_base::alloc_secondary_stack(char const *name, size_t stack_size)
@ -193,10 +191,12 @@ void Thread_base::free_secondary_stack(void* stack_addr)
}
Thread_base::Thread_base(const char *name, size_t stack_size, Type type)
Thread_base::Thread_base(const char *name, size_t stack_size, Type type,
Cpu_session *cpu_session)
:
_cpu_session(cpu_session),
_context(type == REINITIALIZED_MAIN ?
_context : _alloc_context(stack_size, type == MAIN)),
_context : _alloc_context(stack_size, type == MAIN)),
_join_lock(Lock::LOCKED)
{
strncpy(_context->name, name, sizeof(_context->name));
@ -204,6 +204,10 @@ Thread_base::Thread_base(const char *name, size_t stack_size, Type type)
}
Thread_base::Thread_base(const char *name, size_t stack_size, Type type)
: Thread_base(name, stack_size, type, nullptr) { }
Thread_base::~Thread_base()
{
_deinit_platform_thread();

View File

@ -38,31 +38,34 @@ void Thread_base::_thread_start()
void Thread_base::_deinit_platform_thread()
{
env()->cpu_session()->kill_thread(_thread_cap);
_cpu_session->kill_thread(_thread_cap);
}
void Thread_base::start()
{
/* if no cpu session is given, use it from the environment */
if (!_cpu_session)
_cpu_session = env()->cpu_session();
/* create thread at core */
char buf[48];
name(buf, sizeof(buf));
Cpu_session * cpu = env()->cpu_session();
_thread_cap = cpu->create_thread(buf, (addr_t)&_context->utcb);
_thread_cap = _cpu_session->create_thread(buf, (addr_t)&_context->utcb);
/* assign thread to protection domain */
env()->pd_session()->bind_thread(_thread_cap);
/* create new pager object and assign it to the new thread */
Pager_capability pager_cap = env()->rm_session()->add_client(_thread_cap);
env()->cpu_session()->set_pager(_thread_cap, pager_cap);
_cpu_session->set_pager(_thread_cap, pager_cap);
/* register initial IP and SP at core */
env()->cpu_session()->start(_thread_cap, (addr_t)_thread_start, _context->stack_top());
_cpu_session->start(_thread_cap, (addr_t)_thread_start, _context->stack_top());
}
void Thread_base::cancel_blocking()
{
env()->cpu_session()->cancel_blocking(_thread_cap);
_cpu_session->cancel_blocking(_thread_cap);
}

View File

@ -15,6 +15,8 @@
/* Genode includes */
#include <base/printf.h>
#include <base/thread.h>
#include <base/env.h>
#include <cpu_session/connection.h>
using namespace Genode;
@ -149,12 +151,45 @@ static void test_main_thread()
}
/******************************************
** Using cpu-session for thread creation *
******************************************/
struct Cpu_helper : Thread<0x1000>
{
Cpu_helper(const char * name, Cpu_session * cpu)
: Thread<0x1000>(name, cpu) { }
void entry()
{
printf("%s : _cpu_session=0x%p env()->cpu_session()=0x%p\n", _context->name, _cpu_session, env()->cpu_session());
}
};
static void test_cpu_session()
{
Cpu_helper thread0("prio high ", env()->cpu_session());
thread0.start();
thread0.join();
Cpu_connection con1("prio middle", Cpu_session::PRIORITY_LIMIT / 4);
Cpu_helper thread1("prio middle", &con1);
thread1.start();
thread1.join();
Cpu_connection con2("prio low", Cpu_session::PRIORITY_LIMIT / 2);
Cpu_helper thread2("prio low ", &con2);
thread2.start();
thread2.join();
}
int main()
{
try {
test_context_alloc();
test_stack_alignment();
test_main_thread();
test_cpu_session();
} catch (int error) {
return error;
}

View File

@ -40,3 +40,4 @@ xml_generator
blk_cache
rump_ext2
virtualbox_auto_disk
thread