From a99193ad90344459cb0c6b1d56b8d730c2377019 Mon Sep 17 00:00:00 2001 From: Christian Prochaska Date: Mon, 25 Feb 2013 21:18:26 +0100 Subject: [PATCH] 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. --- base-codezero/include/base/ipc_pager.h | 2 +- base-codezero/include/base/native_types.h | 29 +--- base-codezero/lib/mk/base-common.mk | 4 +- base-codezero/src/base/ipc/pager.cc | 6 +- base-codezero/src/base/lock/lock_helper.h | 61 ++----- .../src/base/thread/thread_bootstrap.cc | 25 +++ base-codezero/src/base/thread/thread_start.cc | 6 +- base-codezero/src/core/platform_thread.cc | 2 +- base-codezero/src/core/thread_start.cc | 8 +- base-codezero/src/platform/_main_helper.h | 10 ++ base-foc/src/base/lock/lock_helper.h | 40 ++--- base-hw/include/base/native_types.h | 12 +- base-hw/lib/mk/base-common.mk | 2 +- base-hw/src/base/lock/lock_helper.h | 29 ++-- base-hw/src/base/thread/thread_bootstrap.cc | 22 +++ base-hw/src/core/thread.cc | 17 +- base-hw/src/platform/_main_helper.h | 11 +- base-linux/include/base/native_types.h | 12 +- base-linux/src/base/lock/lock_helper.h | 43 +++-- .../src/core/include/core_linux_syscalls.h | 16 ++ base-linux/src/core/platform.cc | 46 ++++- base-linux/src/platform/_main_helper.h | 7 + base-linux/src/platform/linux_syscalls.h | 11 ++ base-linux/src/platform/lx_hybrid.cc | 159 ++++++++++++++---- base-nova/src/base/lock/lock_helper.h | 41 +---- base-okl4/lib/mk/base-common.mk | 3 +- base-okl4/lib/mk/base.mk | 2 +- base-okl4/src/base/lock/lock_helper.h | 50 ++---- base-okl4/src/core/target.inc | 5 - base-okl4/src/platform/_main_helper.h | 13 +- base-pistachio/lib/mk/base-common.mk | 2 +- base-pistachio/src/base/lock/lock_helper.h | 45 ++--- .../src/base/thread/thread_bootstrap.cc | 25 +++ base-pistachio/src/platform/_main_helper.h | 17 +- base/include/base/cancelable_lock.h | 17 +- base/src/base/lock/lock.cc | 26 ++- 36 files changed, 496 insertions(+), 330 deletions(-) create mode 100644 base-codezero/src/base/thread/thread_bootstrap.cc create mode 100644 base-hw/src/base/thread/thread_bootstrap.cc create mode 100644 base-pistachio/src/base/thread/thread_bootstrap.cc diff --git a/base-codezero/include/base/ipc_pager.h b/base-codezero/include/base/ipc_pager.h index b19590adab..9c2d5ca3f8 100644 --- a/base-codezero/include/base/ipc_pager.h +++ b/base-codezero/include/base/ipc_pager.h @@ -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 diff --git a/base-codezero/include/base/native_types.h b/base-codezero/include/base/native_types.h index 021a1d3b2f..5bb4346c70 100644 --- a/base-codezero/include/base/native_types.h +++ b/base-codezero/include/base/native_types.h @@ -37,31 +37,7 @@ namespace Genode { static void copy(void* dst, Native_capability_tpl* 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 Native_capability; typedef int Native_connection_state; diff --git a/base-codezero/lib/mk/base-common.mk b/base-codezero/lib/mk/base-common.mk index 027a8089fe..b3ab3b7c8a 100644 --- a/base-codezero/lib/mk/base-common.mk +++ b/base-codezero/lib/mk/base-common.mk @@ -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 diff --git a/base-codezero/src/base/ipc/pager.cc b/base-codezero/src/base/ipc/pager.cc index 705ab14c50..b9a3265dca 100644 --- a/base-codezero/src/base/ipc/pager.cc +++ b/base-codezero/src/base/ipc/pager.cc @@ -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); } diff --git a/base-codezero/src/base/lock/lock_helper.h b/base-codezero/src/base/lock/lock_helper.h index f3a1c21f7d..2ac7abd2c6 100644 --- a/base-codezero/src/base/lock/lock_helper.h +++ b/base-codezero/src/base/lock/lock_helper.h @@ -22,7 +22,8 @@ #include -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); } diff --git a/base-codezero/src/base/thread/thread_bootstrap.cc b/base-codezero/src/base/thread/thread_bootstrap.cc new file mode 100644 index 0000000000..19be3612af --- /dev/null +++ b/base-codezero/src/base/thread/thread_bootstrap.cc @@ -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 + +/* Codezero includes */ +#include + + +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 */ +} diff --git a/base-codezero/src/base/thread/thread_start.cc b/base-codezero/src/base/thread/thread_start.cc index 03168a03d4..9802132908 100644 --- a/base-codezero/src/base/thread/thread_start.cc +++ b/base-codezero/src/base/thread/thread_start.cc @@ -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() diff --git a/base-codezero/src/core/platform_thread.cc b/base-codezero/src/core/platform_thread.cc index a3f16a5f2d..3c40092143 100644 --- a/base-codezero/src/core/platform_thread.cc +++ b/base-codezero/src/core/platform_thread.cc @@ -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); diff --git a/base-codezero/src/core/thread_start.cc b/base-codezero/src/core/thread_start.cc index 58e4b9f46c..caf06a596f 100644 --- a/base-codezero/src/core/thread_start.cc +++ b/base-codezero/src/core/thread_start.cc @@ -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); + } diff --git a/base-codezero/src/platform/_main_helper.h b/base-codezero/src/platform/_main_helper.h index 2a9ab1fda0..a14c70212c 100644 --- a/base-codezero/src/platform/_main_helper.h +++ b/base-codezero/src/platform/_main_helper.h @@ -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_ */ diff --git a/base-foc/src/base/lock/lock_helper.h b/base-foc/src/base/lock/lock_helper.h index 5d80e231a7..68221f0987 100644 --- a/base-foc/src/base/lock/lock_helper.h +++ b/base-foc/src/base/lock/lock_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); } diff --git a/base-hw/include/base/native_types.h b/base-hw/include/base/native_types.h index 4f253f1bb3..45011ad492 100644 --- a/base-hw/include/base/native_types.h +++ b/base-hw/include/base/native_types.h @@ -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 }; diff --git a/base-hw/lib/mk/base-common.mk b/base-hw/lib/mk/base-common.mk index 8bd793f72e..bee58c6627 100644 --- a/base-hw/lib/mk/base-common.mk +++ b/base-hw/lib/mk/base-common.mk @@ -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 diff --git a/base-hw/src/base/lock/lock_helper.h b/base-hw/src/base/lock/lock_helper.h index 91430f1e58..7fcd246a01 100644 --- a/base-hw/src/base/lock/lock_helper.h +++ b/base-hw/src/base/lock/lock_helper.h @@ -16,6 +16,10 @@ /* Genode includes */ #include +#include + + +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; +} /** diff --git a/base-hw/src/base/thread/thread_bootstrap.cc b/base-hw/src/base/thread/thread_bootstrap.cc new file mode 100644 index 0000000000..6865c44be0 --- /dev/null +++ b/base-hw/src/base/thread/thread_bootstrap.cc @@ -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 +#include + + +void Genode::Thread_base::_thread_bootstrap() +{ + _tid.tid = Kernel::current_thread_id(); +} diff --git a/base-hw/src/core/thread.cc b/base-hw/src/core/thread.cc index f83fd5ebc0..7b15660801 100644 --- a/base-hw/src/core/thread.cc +++ b/base-hw/src/core/thread.cc @@ -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"); } diff --git a/base-hw/src/platform/_main_helper.h b/base-hw/src/platform/_main_helper.h index 4a2cc34673..e161f008e4 100644 --- a/base-hw/src/platform/_main_helper.h +++ b/base-hw/src/platform/_main_helper.h @@ -14,7 +14,16 @@ #ifndef _SRC__PLATFORM__MAIN_HELPER_H_ #define _SRC__PLATFORM__MAIN_HELPER_H_ -static void main_thread_bootstrap() { } +#include + + +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_ */ diff --git a/base-linux/include/base/native_types.h b/base-linux/include/base/native_types.h index 75b9a1e2c5..6d4333b14e 100644 --- a/base-linux/include/base/native_types.h +++ b/base-linux/include/base/native_types.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) { diff --git a/base-linux/src/base/lock/lock_helper.h b/base-linux/src/base/lock/lock_helper.h index c0f428ffa3..f7d34cdc5b 100644 --- a/base-linux/src/base/lock/lock_helper.h +++ b/base-linux/src/base/lock/lock_helper.h @@ -25,6 +25,9 @@ #include +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); } diff --git a/base-linux/src/core/include/core_linux_syscalls.h b/base-linux/src/core/include/core_linux_syscalls.h index 44ac7785a5..6557979efe 100644 --- a/base-linux/src/core/include/core_linux_syscalls.h +++ b/base-linux/src/core/include/core_linux_syscalls.h @@ -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_ */ diff --git a/base-linux/src/core/platform.cc b/base-linux/src/core/platform.cc index fc5e019819..35482bd29e 100644 --- a/base-linux/src/core/platform.cc +++ b/base-linux/src/core/platform.cc @@ -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. */ diff --git a/base-linux/src/platform/_main_helper.h b/base-linux/src/platform/_main_helper.h index 22b17a5144..98a419431b 100644 --- a/base-linux/src/platform/_main_helper.h +++ b/base-linux/src/platform/_main_helper.h @@ -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; diff --git a/base-linux/src/platform/linux_syscalls.h b/base-linux/src/platform/linux_syscalls.h index 8f994f8e1c..e75ddbd756 100644 --- a/base-linux/src/platform/linux_syscalls.h +++ b/base-linux/src/platform/linux_syscalls.h @@ -33,6 +33,7 @@ #endif /* Linux includes */ +#include #include #include #include @@ -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' diff --git a/base-linux/src/platform/lx_hybrid.cc b/base-linux/src/platform/lx_hybrid.cc index c2992fedc8..ec1cb95f75 100644 --- a/base-linux/src/platform/lx_hybrid.cc +++ b/base-linux/src/platform/lx_hybrid.cc @@ -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(env()->cpu_session()); diff --git a/base-nova/src/base/lock/lock_helper.h b/base-nova/src/base/lock/lock_helper.h index 5cc3c45d27..8af4a1c0a9 100644 --- a/base-nova/src/base/lock/lock_helper.h +++ b/base-nova/src/base/lock/lock_helper.h @@ -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() diff --git a/base-okl4/lib/mk/base-common.mk b/base-okl4/lib/mk/base-common.mk index f9840f19b1..cad7a55a92 100644 --- a/base-okl4/lib/mk/base-common.mk +++ b/base-okl4/lib/mk/base-common.mk @@ -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 diff --git a/base-okl4/lib/mk/base.mk b/base-okl4/lib/mk/base.mk index 8cd239238c..71972c81b8 100644 --- a/base-okl4/lib/mk/base.mk +++ b/base-okl4/lib/mk/base.mk @@ -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 diff --git a/base-okl4/src/base/lock/lock_helper.h b/base-okl4/src/base/lock/lock_helper.h index 8022204311..e70ac3a2bc 100644 --- a/base-okl4/src/base/lock/lock_helper.h +++ b/base-okl4/src/base/lock/lock_helper.h @@ -16,6 +16,7 @@ /* Genode includes */ #include +#include /* 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); } diff --git a/base-okl4/src/core/target.inc b/base-okl4/src/core/target.inc index b6d4699fc7..c0891cf388 100644 --- a/base-okl4/src/core/target.inc +++ b/base-okl4/src/core/target.inc @@ -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 diff --git a/base-okl4/src/platform/_main_helper.h b/base-okl4/src/platform/_main_helper.h index e41131b6df..b74f42baa8 100644 --- a/base-okl4/src/platform/_main_helper.h +++ b/base-okl4/src/platform/_main_helper.h @@ -21,8 +21,6 @@ namespace Okl4 { extern "C" { #include } } -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_ */ diff --git a/base-pistachio/lib/mk/base-common.mk b/base-pistachio/lib/mk/base-common.mk index a0857e969a..cad7a55a92 100644 --- a/base-pistachio/lib/mk/base-common.mk +++ b/base-pistachio/lib/mk/base-common.mk @@ -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 diff --git a/base-pistachio/src/base/lock/lock_helper.h b/base-pistachio/src/base/lock/lock_helper.h index c4f29a161f..9b4d544897 100644 --- a/base-pistachio/src/base/lock/lock_helper.h +++ b/base-pistachio/src/base/lock/lock_helper.h @@ -16,6 +16,7 @@ /* Genode includes */ #include +#include /* 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); } diff --git a/base-pistachio/src/base/thread/thread_bootstrap.cc b/base-pistachio/src/base/thread/thread_bootstrap.cc new file mode 100644 index 0000000000..2bc0cbd57e --- /dev/null +++ b/base-pistachio/src/base/thread/thread_bootstrap.cc @@ -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 + +/* Pistachio includes */ +namespace Pistachio { +#include +} + +void Genode::Thread_base::_thread_bootstrap() +{ + _tid.l4id = Pistachio::L4_Myself(); +} diff --git a/base-pistachio/src/platform/_main_helper.h b/base-pistachio/src/platform/_main_helper.h index 068498533b..1f73d8aef2 100644 --- a/base-pistachio/src/platform/_main_helper.h +++ b/base-pistachio/src/platform/_main_helper.h @@ -14,13 +14,22 @@ #ifndef _PLATFORM___MAIN_HELPER_H_ #define _PLATFORM___MAIN_HELPER_H_ +/* Pistachio includes */ +namespace Pistachio { +#include +} -/* Pistachio-specific definitions */ -enum { L4_PAGEMASK = ~0xFFF }; -enum { L4_PAGESIZE = 0x1000 }; +/* Genode includes */ +#include -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_ */ diff --git a/base/include/base/cancelable_lock.h b/base/include/base/cancelable_lock.h index 1d3736c3a7..725e356ad7 100644 --- a/base/include/base/cancelable_lock.h +++ b/base/include/base/cancelable_lock.h @@ -15,11 +15,12 @@ #define _INCLUDE__BASE__CANCELABLE_LOCK_H_ #include -#include #include 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(); } }; /* diff --git a/base/src/base/lock/lock.cc b/base/src/base/lock/lock.cc index 021fe29b8b..c82ccafc89 100644 --- a/base/src/base/lock/lock.cc +++ b/base/src/base/lock/lock.cc @@ -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();