mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-01 00:45:29 +00:00
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:
parent
7fef0ba931
commit
a99193ad90
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
25
base-codezero/src/base/thread/thread_bootstrap.cc
Normal file
25
base-codezero/src/base/thread/thread_bootstrap.cc
Normal 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 */
|
||||
}
|
@ -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()
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -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_ */
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 };
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
22
base-hw/src/base/thread/thread_bootstrap.cc
Normal file
22
base-hw/src/base/thread/thread_bootstrap.cc
Normal 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();
|
||||
}
|
@ -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");
|
||||
}
|
||||
|
||||
|
||||
|
@ -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_ */
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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;
|
||||
|
@ -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'
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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_ */
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
25
base-pistachio/src/base/thread/thread_bootstrap.cc
Normal file
25
base-pistachio/src/base/thread/thread_bootstrap.cc
Normal 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();
|
||||
}
|
@ -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_ */
|
||||
|
@ -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(); }
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user