Rework the internal lock interface

With this patch, the 'futex' syscall gets used for blocking and unblocking
of threads in the Linux-specific lock implementation.

The 'Native_thread_id' type, which was previously used in the
lock-internal 'Applicant' class to identify a thread to be woken up,
was not suitable anymore for implementing this change. With this patch,
the 'Thread_base*' type gets used instead, which also has the positive
effect of making the public 'cancelable_lock.h' header file
platform-independent.

Fixes #646.
This commit is contained in:
Christian Prochaska 2013-02-25 21:18:26 +01:00 committed by Norman Feske
parent 7fef0ba931
commit a99193ad90
36 changed files with 496 additions and 330 deletions

View File

@ -147,7 +147,7 @@ namespace Genode {
/**
* Return badge for faulting thread
*/
unsigned long badge() const { return _last.tid; }
unsigned long badge() const { return _last; }
/**
* Return true if page fault was a write fault

View File

@ -37,31 +37,7 @@ namespace Genode {
static void copy(void* dst, Native_capability_tpl<Cap_dst_policy>* src);
};
struct Native_thread_id
{
typedef Cap_dst_policy::Dst Dst;
Dst tid;
/**
* Pointer to thread's running lock
*
* Once initialized (see 'lock_helper.h'), it will point to the
* '_running_lock' field of the thread's 'Native_thread' structure,
* which is part of the thread context. This member variable is
* used by the lock implementation only.
*/
struct Codezero::l4_mutex *running_lock;
Native_thread_id() { }
/**
* Constructor (used as implicit constructor)
*/
Native_thread_id(Dst l4id) : tid(l4id), running_lock(0) { }
Native_thread_id(Dst l4id, Codezero::l4_mutex *rl) : tid(l4id), running_lock(rl) { }
};
typedef Cap_dst_policy::Dst Native_thread_id;
struct Native_thread
{
@ -111,9 +87,6 @@ namespace Genode {
return (Codezero::l4_mutex *)&_running_lock; }
};
inline bool operator == (Native_thread_id t1, Native_thread_id t2) { return t1.tid == t2.tid; }
inline bool operator != (Native_thread_id t1, Native_thread_id t2) { return t1.tid != t2.tid; }
typedef Native_capability_tpl<Cap_dst_policy> Native_capability;
typedef int Native_connection_state;

View File

@ -20,7 +20,7 @@ SRC_CC += elf/elf_binary.cc
SRC_CC += lock/lock.cc
SRC_CC += signal/signal.cc signal/common.cc
SRC_CC += server/server.cc server/common.cc
SRC_CC += thread/thread.cc thread/thread_bootstrap_empty.cc
SRC_CC += thread/thread.cc thread/thread_bootstrap.cc
SRC_CC += env/utcb.cc
SRC_CC += lock/cmpxchg.cc
@ -28,5 +28,5 @@ INC_DIR += $(REP_DIR)/src/base/lock
INC_DIR += $(REP_DIR)/include/codezero/dummies
vpath cap_copy.cc $(BASE_DIR)/src/platform
vpath %.cc $(REP_DIR)/src/base
vpath %.cc $(BASE_DIR)/src/base
vpath %.cc $(REP_DIR)/src/base

View File

@ -150,11 +150,11 @@ void Ipc_pager::reply_and_wait_for_fault()
int ret = l4_map((void *)_reply_mapping.from_phys(),
(void *)_reply_mapping.to_virt(),
_reply_mapping.num_pages(), flags, _last.tid);
_reply_mapping.num_pages(), flags, _last);
/* wake up faulter if mapping succeeded */
if (ret < 0)
PERR("l4_map returned %d, putting thread %d to sleep", ret, _last.tid);
PERR("l4_map returned %d, putting thread %d to sleep", ret, _last);
else
acknowledge_wakeup();
@ -166,7 +166,7 @@ void Ipc_pager::reply_and_wait_for_fault()
void Ipc_pager::acknowledge_wakeup()
{
enum { SUCCESS = 0 };
l4_set_sender(_last.tid);
l4_set_sender(_last);
l4_ipc_return(SUCCESS);
}

View File

@ -22,7 +22,8 @@
#include <codezero/syscalls.h>
static Codezero::l4_mutex main_running_lock = { -1 };
extern Genode::Native_thread_id main_thread_tid;
extern Codezero::l4_mutex main_thread_running_lock;
static inline void thread_yield()
@ -31,58 +32,30 @@ static inline void thread_yield()
}
static inline bool thread_id_valid(Genode::Native_thread_id tid)
static inline bool thread_check_stopped_and_restart(Genode::Thread_base *thread_base)
{
return tid.tid != Codezero::NILTHREAD;
}
static inline bool thread_check_stopped_and_restart(Genode::Native_thread_id tid)
{
if (!thread_id_valid(tid))
return false;
Codezero::l4_mutex_unlock(tid.running_lock);
Codezero::l4_mutex *running_lock = thread_base ?
thread_base->utcb()->running_lock() :
&main_thread_running_lock;
Codezero::l4_mutex_unlock(running_lock);
return true;
}
static inline Genode::Native_thread_id thread_get_my_native_id()
static inline void thread_switch_to(Genode::Thread_base *thread_base)
{
using namespace Genode;
Codezero::l4_mutex *running_lock = 0;
/* obtain pointer to running lock of calling thread */
if (Thread_base::myself())
running_lock = Thread_base::myself()->utcb()->running_lock();
else {
running_lock = &main_running_lock;
if (running_lock->lock == -1) {
Codezero::l4_mutex_init(running_lock);
Codezero::l4_mutex_lock(running_lock); /* block on first mutex lock */
}
}
return Genode::Native_thread_id(Codezero::thread_myself(), running_lock);
}
static inline Genode::Native_thread_id thread_invalid_id()
{
return Genode::Native_thread_id(Codezero::NILTHREAD, 0);
}
static inline void thread_switch_to(Genode::Native_thread_id tid)
{
if (thread_id_valid(tid))
Codezero::l4_thread_switch(tid.tid);
Genode::Native_thread_id tid = thread_base ?
thread_base->tid().l4id :
main_thread_tid;
Codezero::l4_thread_switch(tid);
}
static inline void thread_stop_myself()
{
Genode::Native_thread_id myself = thread_get_my_native_id();
Codezero::l4_mutex_lock(myself.running_lock);
Genode::Thread_base *myself = Genode::Thread_base::myself();
Codezero::l4_mutex *running_lock = myself ?
myself->utcb()->running_lock() :
&main_thread_running_lock;
Codezero::l4_mutex_lock(running_lock);
}

View File

@ -0,0 +1,25 @@
/*
* \brief Thread bootstrap code
* \author Christian Prochaska
* \date 2013-02-15
*/
/*
* Copyright (C) 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/thread.h>
/* Codezero includes */
#include <codezero/syscalls.h>
void Genode::Thread_base::_thread_bootstrap()
{
Codezero::l4_mutex_init(utcb()->running_lock());
Codezero::l4_mutex_lock(utcb()->running_lock()); /* block on first mutex lock */
}

View File

@ -39,11 +39,7 @@ void Thread_base::_thread_start()
** Thread base **
*****************/
void Thread_base::_init_platform_thread()
{
Codezero::l4_mutex_init(utcb()->running_lock());
Codezero::l4_mutex_lock(utcb()->running_lock()); /* block on first mutex lock */
}
void Thread_base::_init_platform_thread() { }
void Thread_base::_deinit_platform_thread()

View File

@ -42,7 +42,7 @@ int Platform_thread::start(void *ip, void *sp, unsigned int cpu_no)
memset(&exregs, 0, sizeof(exregs));
exregs_set_stack(&exregs, (unsigned long)sp);
exregs_set_pc (&exregs, (unsigned long)ip);
exregs_set_pager(&exregs, pager.tid);
exregs_set_pager(&exregs, pager);
exregs_set_utcb (&exregs, _utcb);
int ret = l4_exchange_registers(&exregs, _tid);

View File

@ -105,12 +105,14 @@ void Thread_base::start()
_tid.pt = new(platform()->core_mem_alloc()) Platform_thread(_context->name);
_tid.l4id = create_thread(1, &_context->stack[-4], (void *)&_thread_start);
if (_tid.l4id.tid < 0)
PERR("create_thread returned %d", _tid.l4id.tid);
if (_tid.l4id < 0)
PERR("create_thread returned %d", _tid.l4id);
if (verbose_thread_start)
printf("core started local thread \"%s\" with ID %d\n",
_context->name, _tid.l4id.tid);
_context->name, _tid.l4id);
}

View File

@ -59,9 +59,19 @@ extern "C" int printf(const char *format, ...)
** Startup-code helpers **
**************************/
Genode::Native_thread_id main_thread_tid;
Codezero::l4_mutex main_thread_running_lock;
static void main_thread_bootstrap()
{
Codezero::__l4_init();
main_thread_tid = Codezero::thread_myself();
Codezero::l4_mutex_init(&main_thread_running_lock);
Codezero::l4_mutex_lock(&main_thread_running_lock); /* block on first mutex lock */
}
#endif /* _PLATFORM___MAIN_HELPER_H_ */

View File

@ -53,43 +53,25 @@ static inline void thread_yield() { Fiasco::l4_thread_yield(); }
*
* \return true if the thread was in blocking state
*/
static inline bool thread_check_stopped_and_restart(Genode::Native_thread_id tid)
static inline bool thread_check_stopped_and_restart(Genode::Thread_base *thread_base)
{
Genode::Native_thread_id tid = thread_base ?
thread_base->tid() :
Fiasco::MAIN_THREAD_CAP;
Genode::Native_thread_id irq = tid + Fiasco::THREAD_IRQ_CAP;
Fiasco::l4_irq_trigger(irq);
return true;
}
static inline Genode::Native_thread_id thread_get_my_native_id()
{
Genode::Thread_base *myself = Genode::Thread_base::myself();
return myself ? myself->tid() : Fiasco::MAIN_THREAD_CAP;
}
static inline Genode::Native_thread_id thread_invalid_id()
{
return Genode::Native_thread();
}
/**
* Check if a native thread ID is initialized
*
* \return true if ID is initialized
*/
static inline bool thread_id_valid(Genode::Native_thread_id tid)
{
return Fiasco::Capability::valid(tid);
}
/**
* Yield CPU time to the specified thread
*/
static inline void thread_switch_to(Genode::Native_thread_id tid)
static inline void thread_switch_to(Genode::Thread_base *thread_base)
{
Genode::Native_thread_id tid = thread_base ?
thread_base->tid() :
Fiasco::MAIN_THREAD_CAP;
Fiasco::l4_thread_switch(tid);
}
@ -101,7 +83,11 @@ static inline void thread_stop_myself()
{
using namespace Fiasco;
Genode::Native_thread_id irq = thread_get_my_native_id() + THREAD_IRQ_CAP;
Genode::Thread_base *myself = Genode::Thread_base::myself();
Genode::Native_thread_id tid = myself ?
myself->tid() :
Fiasco::MAIN_THREAD_CAP;
Genode::Native_thread_id irq = tid + THREAD_IRQ_CAP;
l4_irq_receive(irq, L4_IPC_NEVER);
}

View File

@ -24,9 +24,15 @@ namespace Genode
class Platform_thread;
class Tlb;
typedef Platform_thread * Native_thread;
typedef unsigned Native_thread_id;
typedef int Native_connection_state;
typedef unsigned Native_thread_id;
struct Native_thread
{
Native_thread_id tid;
Platform_thread *pt;
};
typedef int Native_connection_state;
/* FIXME needs to be MMU dependent */
enum { MIN_MAPPING_SIZE_LOG2 = 12 };

View File

@ -18,7 +18,7 @@ SRC_CC += console/console.cc
SRC_CC += lock/lock.cc
SRC_CC += signal/signal.cc signal/common.cc
SRC_CC += server/server.cc server/common.cc
SRC_CC += thread/thread_bootstrap_empty.cc
SRC_CC += thread/thread_bootstrap.cc
INC_DIR += $(REP_DIR)/src/base/lock $(BASE_DIR)/src/base/lock

View File

@ -16,6 +16,10 @@
/* Genode includes */
#include <base/native_types.h>
#include <base/thread.h>
extern Genode::Native_thread_id main_thread_tid;
/**
@ -29,23 +33,26 @@ static inline void thread_yield()
* Yield CPU to a specified thread 't'
*/
static inline void
thread_switch_to(Genode::Native_thread_id const t)
{ Kernel::yield_thread(t); }
thread_switch_to(Genode::Thread_base *thread_base)
{
Genode::Native_thread_id t = thread_base ?
thread_base->tid().tid :
main_thread_tid;
Kernel::yield_thread(t);
}
/**
* Resume another thread 't' and return if it were paused or not
*/
static inline bool
thread_check_stopped_and_restart(Genode::Native_thread_id const t)
{ return Kernel::resume_thread(t) == 0; }
/**
* Validation kernel thread-identifier 'id'
*/
static inline bool thread_id_valid(Genode::Native_thread_id const id)
{ return id != Genode::thread_invalid_id(); }
thread_check_stopped_and_restart(Genode::Thread_base *thread_base)
{
Genode::Native_thread_id t = thread_base ?
thread_base->tid().tid :
main_thread_tid;
return Kernel::resume_thread(t) == 0;
}
/**

View File

@ -0,0 +1,22 @@
/*
* \brief Thread bootstrap code
* \author Christian Prochaska
* \date 2013-02-15
*/
/*
* Copyright (C) 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/thread.h>
#include <kernel/syscalls.h>
void Genode::Thread_base::_thread_bootstrap()
{
_tid.tid = Kernel::current_thread_id();
}

View File

@ -33,7 +33,7 @@ Native_utcb * Thread_base::utcb()
if (!this) { return _main_utcb; }
/* this isn't the main thread */
return _tid->phys_utcb();
return _tid.pt->phys_utcb();
}
@ -51,17 +51,18 @@ Thread_base * Thread_base::myself()
}
static void thread_entry()
void Thread_base::_thread_start()
{
/* this is never called by a main thread */
Thread_base::myself()->_thread_bootstrap();
Thread_base::myself()->entry();
}
Thread_base::Thread_base(const char *name, size_t stack_size)
: _list_element(this), _tid(0)
: _list_element(this)
{
_tid = new (platform()->core_mem_alloc())
_tid.pt = new (platform()->core_mem_alloc())
Platform_thread(name, this, stack_size, Kernel::core_id());
}
@ -75,12 +76,12 @@ Thread_base::~Thread_base()
void Thread_base::start()
{
size_t const stack_size = _tid->stack_size()/sizeof(umword_t) + 1;
size_t const stack_size = _tid.pt->stack_size()/sizeof(umword_t) + 1;
void * const stack_base = new (platform()->core_mem_alloc())
umword_t [stack_size];
void * sp = (void *)((addr_t)stack_base + _tid->stack_size());
void * ip = (void *)&thread_entry;
if (_tid->start(ip, sp)) PERR("Couldn't start thread");
void * sp = (void *)((addr_t)stack_base + _tid.pt->stack_size());
void * ip = (void *)&_thread_start;
if (_tid.pt->start(ip, sp)) PERR("Couldn't start thread");
}

View File

@ -14,7 +14,16 @@
#ifndef _SRC__PLATFORM__MAIN_HELPER_H_
#define _SRC__PLATFORM__MAIN_HELPER_H_
static void main_thread_bootstrap() { }
#include <base/native_types.h>
Genode::Native_thread_id main_thread_tid;
static void main_thread_bootstrap()
{
main_thread_tid = Kernel::current_thread_id();
}
#endif /* _SRC__PLATFORM__MAIN_HELPER_H_ */

View File

@ -29,10 +29,9 @@
namespace Genode {
/**
* Thread ID used in lock implementation
* Thread ID
*
* Unfortunately, both - PID and TID - are needed for lx_tgkill() in
* thread_check_stopped_and_restart().
* Unfortunately, both - PID and TID - are needed for lx_tgkill()
*/
struct Native_thread_id
{
@ -62,6 +61,11 @@ namespace Genode {
{
bool is_ipc_server;
/**
* Natively aligned memory location used in the lock implementation
*/
int futex_counter __attribute__((aligned(sizeof(Genode::addr_t))));
/**
* Opaque pointer to additional thread-specific meta data
*
@ -71,7 +75,7 @@ namespace Genode {
*/
Thread_meta_data *meta_data;
Native_thread() : is_ipc_server(false), meta_data(0) { }
Native_thread() : is_ipc_server(false), futex_counter(0), meta_data(0) { }
};
inline bool operator == (Native_thread_id t1, Native_thread_id t2) {

View File

@ -25,6 +25,9 @@
#include <linux_syscalls.h>
extern int main_thread_futex_counter;
/**
* Resolve 'Thread_base::myself' when not linking the thread library
*
@ -42,32 +45,16 @@ static inline void thread_yield()
}
static inline bool thread_check_stopped_and_restart(Genode::Native_thread_id tid)
static inline bool thread_check_stopped_and_restart(Genode::Thread_base *thread_base)
{
lx_tgkill(tid.pid, tid.tid, LX_SIGUSR1);
return true;
const int *futex_counter_ptr = thread_base ?
&thread_base->tid().futex_counter :
&main_thread_futex_counter;
return lx_futex(futex_counter_ptr, LX_FUTEX_WAKE, 1);
}
static inline Genode::Native_thread_id thread_get_my_native_id()
{
return Genode::Native_thread_id(lx_gettid(), lx_getpid());
}
static inline Genode::Native_thread_id thread_invalid_id()
{
return Genode::Native_thread_id();
}
static inline bool thread_id_valid(Genode::Native_thread_id tid)
{
return (tid.pid != 0);
}
static inline void thread_switch_to(Genode::Native_thread_id tid)
static inline void thread_switch_to(Genode::Thread_base *thread_base)
{
thread_yield();
}
@ -75,6 +62,14 @@ static inline void thread_switch_to(Genode::Native_thread_id tid)
static inline void thread_stop_myself()
{
struct timespec ts = { 1000, 0 };
while (lx_nanosleep(&ts, 0) == 0);
/*
* Just go to sleep without modifying the counter value. The
* 'thread_check_stopped_and_restart()' function will get called
* repeatedly until this thread has actually executed the syscall.
*/
Genode::Thread_base *myself = Genode::Thread_base::myself();
const int *futex_counter_ptr = myself ?
&myself->tid().futex_counter :
&main_thread_futex_counter;
lx_futex(futex_counter_ptr, LX_FUTEX_WAIT, 0);
}

View File

@ -203,4 +203,20 @@ inline int lx_connect(int sockfd, const struct sockaddr *serv_addr,
#endif /* SYS_socketcall */
/******************************
** Linux signal dispatching **
******************************/
inline int lx_pipe(int pipefd[2])
{
return lx_syscall(SYS_pipe, pipefd);
}
inline int lx_read(int fd, void *buf, Genode::size_t count)
{
return lx_syscall(SYS_read, fd, buf, count);
}
#endif /* _CORE__INCLUDE__CORE_LINUX_SYSCALLS_H_ */

View File

@ -33,20 +33,53 @@ using namespace Genode;
static char _core_mem[80*1024*1024];
static Lock _wait_for_exit_lock(Lock::LOCKED); /* wakeup of '_wait_for_exit' */
static bool _do_exit = false; /* exit condition */
/*
* Basic semaphore implementation based on the 'pipe' syscall.
*
* This alternative implementation is needed to be able to wake up the
* blocked main thread from a signal handler executed by the same thread.
*/
class Pipe_semaphore
{
private:
int _pipefd[2];
public:
Pipe_semaphore()
{
lx_pipe(_pipefd);
}
void down()
{
char dummy;
while(lx_read(_pipefd[0], &dummy, 1) != 1);
}
void up()
{
char dummy;
while (lx_write(_pipefd[1], &dummy, 1) != 1);
}
};
static Pipe_semaphore _wait_for_exit_sem; /* wakeup of '_wait_for_exit' */
static bool _do_exit = false; /* exit condition */
static void sigint_handler(int signum)
{
_wait_for_exit_lock.unlock();
_do_exit = true;
_wait_for_exit_sem.up();
}
static void sigchld_handler(int signnum)
{
_wait_for_exit_lock.unlock();
_wait_for_exit_sem.up();
}
@ -82,11 +115,10 @@ void Platform::wait_for_exit()
/*
* Block until a signal occurs.
*/
try { _wait_for_exit_lock.lock(); }
catch (Blocking_canceled) { };
_wait_for_exit_sem.down();
/*
* Each time, the '_wait_for_exit_lock' gets unlocked, we could have
* Each time, the '_wait_for_exit_sem' gets unlocked, we could have
* received either a SIGINT or SIGCHLD. If a SIGINT was received, the
* '_exit' condition will be set.
*/

View File

@ -25,6 +25,13 @@
__attribute__((weak)) char **lx_environ = (char **)0;
/**
* Natively aligned memory location used in the lock implementation
*/
int main_thread_futex_counter __attribute__((aligned(sizeof(Genode::addr_t))));
static inline void main_thread_bootstrap()
{
using namespace Genode;

View File

@ -33,6 +33,7 @@
#endif
/* Linux includes */
#include <linux/futex.h>
#include <unistd.h>
#include <signal.h>
#include <sched.h>
@ -338,6 +339,16 @@ inline int lx_nanosleep(const struct timespec *req, struct timespec *rem)
return lx_syscall(SYS_nanosleep, req, rem);
}
enum {
LX_FUTEX_WAIT = FUTEX_WAIT,
LX_FUTEX_WAKE = FUTEX_WAKE,
};
inline int lx_futex(const int *uaddr, int op, int val)
{
return lx_syscall(SYS_futex, uaddr, op, val, 0, 0, 0);
}
/**
* Signal set corrsponding to glibc's 'sigset_t'

View File

@ -130,27 +130,6 @@ namespace Genode {
struct Thread_meta_data
{
/**
* Lock with the initial state set to LOCKED
*/
struct Barrier : Lock { Barrier() : Lock(Lock::LOCKED) { } };
/**
* Used to block the constructor until the new thread has initialized
* 'id'
*/
Barrier construct_lock;
/**
* Used to block the new thread until 'start' is called
*/
Barrier start_lock;
/**
* Used to block the 'join()' function until the 'entry()' is done
*/
Barrier join_lock;
/**
* Filled out by 'thread_start' function in the context of the new
* thread
@ -168,6 +147,128 @@ namespace Genode {
* \param thread associated 'Thread_base' object
*/
Thread_meta_data(Thread_base *thread) : thread_base(thread) { }
/**
* Used to block the constructor until the new thread has initialized
* 'id'
*/
virtual void wait_for_construction() = 0;
virtual void constructed() = 0;
/**
* Used to block the new thread until 'start' is called
*/
virtual void wait_for_start() = 0;
virtual void started() = 0;
/**
* Used to block the 'join()' function until the 'entry()' is done
*/
virtual void wait_for_join() = 0;
virtual void joined() = 0;
};
/*
* Thread meta data for a thread created by Genode
*/
class Thread_meta_data_created : public Thread_meta_data
{
private:
/**
* Lock with the initial state set to LOCKED
*/
struct Barrier : Lock { Barrier() : Lock(Lock::LOCKED) { } };
/**
* Used to block the constructor until the new thread has initialized
* 'id'
*/
Barrier _construct_lock;
/**
* Used to block the new thread until 'start' is called
*/
Barrier _start_lock;
/**
* Used to block the 'join()' function until the 'entry()' is done
*/
Barrier _join_lock;
public:
Thread_meta_data_created(Thread_base *thread) : Thread_meta_data(thread) { }
void wait_for_construction()
{
_construct_lock.lock();
}
void constructed()
{
_construct_lock.unlock();
}
void wait_for_start()
{
_start_lock.lock();
}
void started()
{
_start_lock.unlock();
}
void wait_for_join()
{
_join_lock.lock();
}
void joined()
{
_join_lock.unlock();
}
};
/*
* Thread meta data for an adopted thread
*/
class Thread_meta_data_adopted : public Thread_meta_data
{
public:
Thread_meta_data_adopted(Thread_base *thread) : Thread_meta_data(thread) { }
void wait_for_construction()
{
PERR("wait_for_construction() called for an adopted thread");
}
void constructed()
{
PERR("constructed() called for an adopted thread");
}
void wait_for_start()
{
PERR("wait_for_start() called for an adopted thread");
}
void started()
{
PERR("started() called for an adopted thread");
}
void wait_for_join()
{
PERR("wait_for_join() called for an adopted thread");
}
void joined()
{
PERR("joined() called for an adopted thread");
}
};
}
@ -224,14 +325,14 @@ static void *thread_start(void *arg)
adopt_thread(meta_data);
/* unblock 'Thread_base' constructor */
meta_data->construct_lock.unlock();
meta_data->constructed();
/* block until the 'Thread_base::start' gets called */
meta_data->start_lock.lock();
meta_data->wait_for_start();
Thread_base::myself()->entry();
meta_data->join_lock.unlock();
meta_data->joined();
return 0;
}
@ -271,7 +372,7 @@ Thread_base *Thread_base::myself()
*/
Thread_base *thread = (Thread_base *)malloc(sizeof(Thread_base));
memset(thread, 0, sizeof(*thread));
Thread_meta_data *meta_data = new Thread_meta_data(thread);
Thread_meta_data *meta_data = new Thread_meta_data_adopted(thread);
/*
* Initialize 'Thread_base::_tid' using the default constructor of
@ -290,13 +391,13 @@ void Thread_base::start()
/*
* Unblock thread that is supposed to slumber in 'thread_start'.
*/
_tid.meta_data->start_lock.unlock();
_tid.meta_data->started();
}
void Thread_base::join()
{
_tid.meta_data->join_lock.lock();
_tid.meta_data->wait_for_join();
}
@ -304,7 +405,7 @@ Thread_base::Thread_base(const char *name, size_t stack_size)
:
_list_element(this)
{
_tid.meta_data = new (env()->heap()) Thread_meta_data(this);
_tid.meta_data = new (env()->heap()) Thread_meta_data_created(this);
int const ret = pthread_create(&_tid.meta_data->pt, 0, thread_start,
_tid.meta_data);
@ -315,7 +416,7 @@ Thread_base::Thread_base(const char *name, size_t stack_size)
throw Context_alloc_failed();
}
_tid.meta_data->construct_lock.lock();
_tid.meta_data->wait_for_construction();
Linux_cpu_session *cpu = dynamic_cast<Linux_cpu_session *>(env()->cpu_session());

View File

@ -44,49 +44,18 @@ Genode::Thread_base * __attribute__((weak)) Genode::Thread_base::myself()
static inline void thread_yield() { }
static inline bool thread_check_stopped_and_restart(Genode::Native_thread_id tid)
static inline bool thread_check_stopped_and_restart(Genode::Thread_base *thread_base)
{
Genode::addr_t sem = (tid.ec_sel == 0 && tid.exc_pt_sel == 0) ?
main_thread_running_semaphore() :
tid.exc_pt_sel + Nova::SM_SEL_EC;
Genode::addr_t sem = thread_base ?
thread_base->tid().exc_pt_sel + Nova::SM_SEL_EC :
main_thread_running_semaphore();
Nova::sm_ctrl(sem, Nova::SEMAPHORE_UP);
return true;
}
static inline Genode::Native_thread_id thread_get_my_native_id()
{
/*
* We encode the main thread as tid { 0, 0 } because we cannot
* call 'main_thread_running_semaphore()' here.
*/
Genode::Thread_base *myself = Genode::Thread_base::myself();
if (myself == 0) {
Genode::Native_thread_id main_tid;
main_tid.ec_sel = 0;
main_tid.exc_pt_sel = 0;
return main_tid;
} else
return myself->tid();
}
static inline Genode::Native_thread_id thread_invalid_id()
{
Genode::Native_thread_id tid;
return tid;
}
static inline bool thread_id_valid(Genode::Native_thread_id tid)
{
return !(tid.ec_sel == ~0UL && tid.exc_pt_sel == ~0UL);
}
static inline void thread_switch_to(Genode::Native_thread_id tid) { }
static inline void thread_switch_to(Genode::Thread_base *thread_base) { }
static inline void thread_stop_myself()

View File

@ -20,9 +20,10 @@ SRC_CC += elf/elf_binary.cc
SRC_CC += lock/lock.cc
SRC_CC += signal/signal.cc signal/common.cc
SRC_CC += server/server.cc server/common.cc
SRC_CC += thread/thread.cc thread/thread_bootstrap.cc
INC_DIR += $(REP_DIR)/src/base/lock
vpath cap_copy.cc $(BASE_DIR)/src/platform
vpath %.cc $(BASE_DIR)/src/base
vpath %.cc $(REP_DIR)/src/base
vpath %.cc $(BASE_DIR)/src/base

View File

@ -1,6 +1,6 @@
SRC_CC += console/log_console.cc
SRC_CC += env/env.cc env/context_area.cc env/reload_parent_cap.cc
SRC_CC += thread/thread.cc thread/thread_start.cc thread/thread_bootstrap.cc
SRC_CC += thread/thread_start.cc
vpath %.cc $(REP_DIR)/src/base
vpath %.cc $(BASE_DIR)/src/base

View File

@ -16,6 +16,7 @@
/* Genode includes */
#include <base/native_types.h>
#include <base/thread.h>
/* OKL4 includes */
namespace Okl4 { extern "C" {
@ -30,6 +31,9 @@ namespace Okl4 { extern "C" {
static inline void thread_yield() { Okl4::L4_Yield(); }
extern Genode::Native_thread_id main_thread_tid;
/**
* Custom ExchangeRegisters wrapper for waking up a thread
*
@ -39,7 +43,7 @@ static inline void thread_yield() { Okl4::L4_Yield(); }
*
* \return true if the thread was in blocking state
*/
static inline bool thread_check_stopped_and_restart(Genode::Native_thread_id tid)
static inline bool thread_check_stopped_and_restart(Genode::Thread_base *thread_base)
{
using namespace Okl4;
@ -47,6 +51,10 @@ static inline bool thread_check_stopped_and_restart(Genode::Native_thread_id tid
L4_ThreadId_t dummy_id;
L4_ThreadState_t state;
Genode::Native_thread_id tid = thread_base ?
thread_base->tid().l4id :
main_thread_tid;
L4_ExchangeRegisters(tid, L4_ExReg_Resume + L4_ExReg_AbortIPC, 0, 0, 0,
0, L4_nilthread, &state.raw, &dummy, &dummy, &dummy,
&dummy, &dummy_id);
@ -55,40 +63,14 @@ static inline bool thread_check_stopped_and_restart(Genode::Native_thread_id tid
}
/*
* XXX Avoid duplicating this function, see 'ipc.cc', 'pager.cc', and
* 'irq_session_component.cc'
*/
static inline Genode::Native_thread_id thread_get_my_native_id()
{
Okl4::L4_ThreadId_t myself;
myself.raw = Okl4::__L4_TCR_ThreadWord(Genode::UTCB_TCR_THREAD_WORD_MYSELF);
return myself;
}
static inline Genode::Native_thread_id thread_invalid_id()
{
return Okl4::L4_nilthread;
}
/**
* Check if a native thread ID is initialized
*
* \return true if ID is initialized
*/
static inline bool thread_id_valid(Genode::Native_thread_id tid)
{
return (tid.raw != 0);
}
/**
* Yield CPU time to the specified thread
*/
static inline void thread_switch_to(Genode::Native_thread_id tid)
static inline void thread_switch_to(Genode::Thread_base *thread_base)
{
Genode::Native_thread_id tid = thread_base ?
thread_base->tid().l4id :
main_thread_tid;
Okl4::L4_ThreadSwitch(tid);
}
@ -98,5 +80,9 @@ static inline void thread_switch_to(Genode::Native_thread_id tid)
*/
static inline void thread_stop_myself()
{
Okl4::L4_Stop(thread_get_my_native_id());
Genode::Thread_base *myself = Genode::Thread_base::myself();
Genode::Native_thread_id tid = myself ?
myself->tid().l4id :
main_thread_tid;
Okl4::L4_Stop(tid);
}

View File

@ -14,9 +14,7 @@ SRC_CC += main.cc \
okl4_pd_session_component.cc \
io_mem_session_component.cc \
io_mem_session_support.cc \
thread.cc \
thread_start.cc \
thread_bootstrap.cc \
platform_thread.cc \
platform_pd.cc \
platform.cc \
@ -54,8 +52,5 @@ vpath core_mem_alloc.cc $(GEN_CORE_DIR)
vpath dump_alloc.cc $(GEN_CORE_DIR)
vpath context_area.cc $(GEN_CORE_DIR)
vpath %.cc $(REP_DIR)/src/core
vpath thread_bootstrap.cc $(REP_DIR)/src/base/thread
vpath thread_start.cc $(BASE_DIR)/src/base/thread
vpath thread.cc $(BASE_DIR)/src/base/thread
vpath core_printf.cc $(BASE_DIR)/src/base/console

View File

@ -21,8 +21,6 @@ namespace Okl4 { extern "C" {
#include <l4/thread.h>
} }
enum { L4_PAGEMASK = ~0xFFF };
enum { L4_PAGESIZE = 0x1000 };
namespace Okl4 {
@ -30,21 +28,28 @@ namespace Okl4 {
* Read global thread ID from user-defined handle and store it
* into a designated UTCB entry.
*/
void copy_uregister_to_utcb()
L4_Word_t copy_uregister_to_utcb()
{
using namespace Okl4;
L4_Word_t my_global_id = L4_UserDefinedHandle();
__L4_TCR_Set_ThreadWord(Genode::UTCB_TCR_THREAD_WORD_MYSELF,
my_global_id);
return my_global_id;
}
}
Genode::Native_thread_id main_thread_tid;
static void main_thread_bootstrap()
{
/* copy thread ID to utcb */
Okl4::copy_uregister_to_utcb();
main_thread_tid.raw = Okl4::copy_uregister_to_utcb();
if (main_thread_tid.raw == 0) /* core */
main_thread_tid.raw = Okl4::L4_rootserver.raw;
}
#endif /* _PLATFORM___MAIN_HELPER_H_ */

View File

@ -20,7 +20,7 @@ SRC_CC += elf/elf_binary.cc
SRC_CC += lock/lock.cc
SRC_CC += signal/signal.cc signal/common.cc
SRC_CC += server/server.cc server/common.cc
SRC_CC += thread/thread.cc thread/thread_bootstrap_empty.cc
SRC_CC += thread/thread.cc thread/thread_bootstrap.cc
INC_DIR += $(REP_DIR)/src/base/lock

View File

@ -16,6 +16,7 @@
/* Genode includes */
#include <base/native_types.h>
#include <base/thread.h>
/* Pistachio includes */
namespace Pistachio {
@ -24,8 +25,7 @@ namespace Pistachio {
}
static inline bool operator == (Genode::Native_thread_id t1, Genode::Native_thread_id t2) { return t1.raw == t2.raw; }
static inline bool operator != (Genode::Native_thread_id t1, Genode::Native_thread_id t2) { return t1.raw != t2.raw; }
extern Genode::Native_thread_id main_thread_tid;
/**
@ -43,7 +43,7 @@ static inline void thread_yield() { Pistachio::L4_Yield(); }
*
* \return true if the thread was in blocking state
*/
static inline bool thread_check_stopped_and_restart(Genode::Native_thread_id tid)
static inline bool thread_check_stopped_and_restart(Genode::Thread_base *thread_base)
{
using namespace Pistachio;
@ -51,6 +51,10 @@ static inline bool thread_check_stopped_and_restart(Genode::Native_thread_id tid
L4_ThreadId_t dummy_id;
L4_ThreadState_t state;
Genode::Native_thread_id tid = thread_base ?
thread_base->tid().l4id :
main_thread_tid;
enum { RESUME = 1 << 8, CANCEL_IPC = 3 << 1 };
L4_ExchangeRegisters(tid, RESUME | CANCEL_IPC, 0, 0, 0,
0, L4_nilthread, &state.raw, &dummy, &dummy, &dummy,
@ -60,35 +64,14 @@ static inline bool thread_check_stopped_and_restart(Genode::Native_thread_id tid
}
static inline Genode::Native_thread_id thread_get_my_native_id()
{
return Pistachio::L4_Myself();
}
static inline Genode::Native_thread_id thread_invalid_id()
{
using namespace Pistachio;
return L4_nilthread;
}
/**
* Check if a native thread ID is initialized
*
* \return true if ID is initialized
*/
static inline bool thread_id_valid(Genode::Native_thread_id tid)
{
return (tid.raw != 0);
}
/**
* Yield CPU time to the specified thread
*/
static inline void thread_switch_to(Genode::Native_thread_id tid)
static inline void thread_switch_to(Genode::Thread_base *thread_base)
{
Genode::Native_thread_id tid = thread_base ?
thread_base->tid().l4id :
main_thread_tid;
Pistachio::L4_ThreadSwitch(tid);
}
@ -98,5 +81,9 @@ static inline void thread_switch_to(Genode::Native_thread_id tid)
*/
static inline void thread_stop_myself()
{
Pistachio::L4_Stop(thread_get_my_native_id());
Genode::Thread_base *myself = Genode::Thread_base::myself();
Genode::Native_thread_id tid = myself ?
myself->tid().l4id :
main_thread_tid;
Pistachio::L4_Stop(tid);
}

View File

@ -0,0 +1,25 @@
/*
* \brief Thread bootstrap code
* \author Christian Prochaska
* \date 2013-02-15
*/
/*
* Copyright (C) 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/thread.h>
/* Pistachio includes */
namespace Pistachio {
#include <l4/thread.h>
}
void Genode::Thread_base::_thread_bootstrap()
{
_tid.l4id = Pistachio::L4_Myself();
}

View File

@ -14,13 +14,22 @@
#ifndef _PLATFORM___MAIN_HELPER_H_
#define _PLATFORM___MAIN_HELPER_H_
/* Pistachio includes */
namespace Pistachio {
#include <l4/thread.h>
}
/* Pistachio-specific definitions */
enum { L4_PAGEMASK = ~0xFFF };
enum { L4_PAGESIZE = 0x1000 };
/* Genode includes */
#include <base/native_types.h>
static void main_thread_bootstrap() { }
Genode::Native_thread_id main_thread_tid;
static void main_thread_bootstrap()
{
main_thread_tid = Pistachio::L4_Myself();
}
#endif /* _PLATFORM___MAIN_HELPER_H_ */

View File

@ -15,11 +15,12 @@
#define _INCLUDE__BASE__CANCELABLE_LOCK_H_
#include <base/lock_guard.h>
#include <base/native_types.h>
#include <base/blocking.h>
namespace Genode {
class Thread_base;
class Cancelable_lock
{
private:
@ -28,28 +29,28 @@ namespace Genode {
{
private:
Native_thread_id _tid;
Applicant *_to_wake_up;
Thread_base *_thread_base;
Applicant *_to_wake_up;
public:
explicit Applicant(Native_thread_id tid)
: _tid(tid), _to_wake_up(0) { }
explicit Applicant(Thread_base *thread_base)
: _thread_base(thread_base), _to_wake_up(0) { }
void applicant_to_wake_up(Applicant *to_wake_up) {
_to_wake_up = to_wake_up; }
Applicant *applicant_to_wake_up() { return _to_wake_up; }
Native_thread_id tid() { return _tid; }
Thread_base *thread_base() { return _thread_base; }
/**
* Called from previous lock owner
*/
void wake_up();
bool operator == (Applicant &a) { return _tid == a.tid(); }
bool operator != (Applicant &a) { return _tid != a.tid(); }
bool operator == (Applicant &a) { return _thread_base == a.thread_base(); }
bool operator != (Applicant &a) { return _thread_base != a.thread_base(); }
};
/*

View File

@ -25,13 +25,25 @@ using namespace Genode;
int debug_lock_sleep_race_cnt;
static inline Genode::Thread_base *invalid_thread_base()
{
return (Genode::Thread_base*)~0;
}
static inline bool thread_base_valid(Genode::Thread_base *thread_base)
{
return (thread_base != invalid_thread_base());
}
/********************
** Lock applicant **
********************/
void Cancelable_lock::Applicant::wake_up()
{
if (!thread_id_valid(_tid)) return;
if (!thread_base_valid(_thread_base)) return;
/*
* Deal with the race that may occur in the 'lock' function between
@ -40,11 +52,11 @@ void Cancelable_lock::Applicant::wake_up()
for (;;) {
if (thread_check_stopped_and_restart(_tid))
if (thread_check_stopped_and_restart(_thread_base))
return;
debug_lock_sleep_race_cnt++; /* only for statistics */
thread_switch_to(_tid);
thread_switch_to(_thread_base);
}
}
@ -55,13 +67,13 @@ void Cancelable_lock::Applicant::wake_up()
void Cancelable_lock::lock()
{
Applicant myself(thread_get_my_native_id());
Applicant myself(Thread_base::myself());
spinlock_lock(&_spinlock_state);
/* reset ownership if one thread 'lock' twice */
if (_owner == myself)
_owner = Applicant(thread_invalid_id());
_owner = Applicant(invalid_thread_base());
if (cmpxchg(&_state, UNLOCKED, LOCKED)) {
@ -149,7 +161,7 @@ void Cancelable_lock::unlock()
} else {
/* there is no further applicant, leave the lock alone */
_owner = Applicant(thread_invalid_id());
_owner = Applicant(invalid_thread_base());
_last_applicant = 0;
_state = UNLOCKED;
@ -163,7 +175,7 @@ Cancelable_lock::Cancelable_lock(Cancelable_lock::State initial)
_spinlock_state(SPINLOCK_UNLOCKED),
_state(UNLOCKED),
_last_applicant(0),
_owner(thread_invalid_id())
_owner(invalid_thread_base())
{
if (initial == LOCKED)
lock();