diff --git a/repos/base-fiasco/src/lib/base/lock.cc b/repos/base-fiasco/src/lib/base/lock.cc index 7feb76c7c4..7deedd31f8 100644 --- a/repos/base-fiasco/src/lib/base/lock.cc +++ b/repos/base-fiasco/src/lib/base/lock.cc @@ -13,6 +13,7 @@ /* Genode includes */ #include +#include #include #include @@ -33,6 +34,13 @@ Cancelable_lock::Cancelable_lock(Cancelable_lock::State initial) void Cancelable_lock::lock() +{ + Applicant myself(Thread::myself()); + lock(myself); +} + + +void Cancelable_lock::lock(Applicant &myself) { /* * XXX: How to notice cancel-blocking signals issued when being outside the @@ -41,11 +49,14 @@ void Cancelable_lock::lock() while (!Genode::cmpxchg(&_state, UNLOCKED, LOCKED)) if (Fiasco::l4_ipc_sleep(Fiasco::l4_ipc_timeout(0, 0, 500, 0)) != L4_IPC_RETIMEOUT) throw Genode::Blocking_canceled(); + + _owner = myself; } void Cancelable_lock::unlock() { + _owner = Applicant(nullptr); Genode::memory_barrier(); _state = UNLOCKED; } diff --git a/repos/base-foc/src/include/base/internal/lock_helper.h b/repos/base-foc/src/include/base/internal/lock_helper.h index 95698358fc..395cbab0ad 100644 --- a/repos/base-foc/src/include/base/internal/lock_helper.h +++ b/repos/base-foc/src/include/base/internal/lock_helper.h @@ -78,7 +78,7 @@ static inline void thread_switch_to(Genode::Thread *thread_base) __attribute__((optimize("-fno-omit-frame-pointer"))) __attribute__((noinline)) __attribute__((used)) -static void thread_stop_myself() +static void thread_stop_myself(Genode::Thread *) { using namespace Fiasco; diff --git a/repos/base-hw/src/bootstrap/lock.cc b/repos/base-hw/src/bootstrap/lock.cc index c8f6661902..41b5167757 100644 --- a/repos/base-hw/src/bootstrap/lock.cc +++ b/repos/base-hw/src/bootstrap/lock.cc @@ -12,6 +12,7 @@ */ #include +#include #include Genode::Cancelable_lock::Cancelable_lock(Genode::Cancelable_lock::State state) @@ -30,3 +31,13 @@ void Genode::Cancelable_lock::lock() assert(_state == UNLOCKED); _state = LOCKED; } + +void Genode::Mutex::acquire() +{ + _lock.lock(); +} + +void Genode::Mutex::release() +{ + _lock.unlock(); +} diff --git a/repos/base-hw/src/include/base/internal/lock_helper.h b/repos/base-hw/src/include/base/internal/lock_helper.h index 5eafe68780..6e6e4e9bb8 100644 --- a/repos/base-hw/src/include/base/internal/lock_helper.h +++ b/repos/base-hw/src/include/base/internal/lock_helper.h @@ -62,7 +62,7 @@ thread_check_stopped_and_restart(Genode::Thread * const t) /** * Pause execution of current thread */ -static inline void thread_stop_myself() { Kernel::stop_thread(); } +static inline void thread_stop_myself(Genode::Thread *) { Kernel::stop_thread(); } #endif /* _INCLUDE__BASE__INTERNAL__LOCK_HELPER_H_ */ diff --git a/repos/base-linux/src/include/base/internal/lock_helper.h b/repos/base-linux/src/include/base/internal/lock_helper.h index 701090ce2d..37321ae45c 100644 --- a/repos/base-linux/src/include/base/internal/lock_helper.h +++ b/repos/base-linux/src/include/base/internal/lock_helper.h @@ -49,14 +49,13 @@ static inline bool thread_check_stopped_and_restart(Genode::Thread *thread_base) static inline void thread_switch_to(Genode::Thread *) { thread_yield(); } -static inline void thread_stop_myself() +static inline void thread_stop_myself(Genode::Thread *myself) { /* * 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 *myself = Genode::Thread::myself(); const int *futex_counter_ptr = myself ? &myself->native_thread().futex_counter : &main_thread_futex_counter; diff --git a/repos/base-nova/src/include/base/internal/lock_helper.h b/repos/base-nova/src/include/base/internal/lock_helper.h index 53901e308d..4281d17000 100644 --- a/repos/base-nova/src/include/base/internal/lock_helper.h +++ b/repos/base-nova/src/include/base/internal/lock_helper.h @@ -47,13 +47,12 @@ static inline bool thread_check_stopped_and_restart(Genode::Thread *thread_base) static inline void thread_switch_to(Genode::Thread *) { } -static inline void thread_stop_myself() +static inline void thread_stop_myself(Genode::Thread *myself) { using namespace Genode; using namespace Nova; addr_t sem; - Thread *myself = Thread::myself(); if (myself) sem = myself->native_thread().exc_pt_sel + SM_SEL_EC; else diff --git a/repos/base-okl4/src/include/base/internal/lock_helper.h b/repos/base-okl4/src/include/base/internal/lock_helper.h index bc3907fc3b..00bdd5462a 100644 --- a/repos/base-okl4/src/include/base/internal/lock_helper.h +++ b/repos/base-okl4/src/include/base/internal/lock_helper.h @@ -77,9 +77,8 @@ static inline void thread_switch_to(Genode::Thread *thread_base) /** * Unconditionally block the calling thread */ -static inline void thread_stop_myself() +static inline void thread_stop_myself(Genode::Thread *myself) { - Genode::Thread *myself = Genode::Thread::myself(); Okl4::L4_ThreadId_t tid = myself ? myself->native_thread().l4id : main_thread_tid; diff --git a/repos/base-pistachio/src/include/base/internal/lock_helper.h b/repos/base-pistachio/src/include/base/internal/lock_helper.h index e7d0b6fe81..220a018e3a 100644 --- a/repos/base-pistachio/src/include/base/internal/lock_helper.h +++ b/repos/base-pistachio/src/include/base/internal/lock_helper.h @@ -81,9 +81,8 @@ static inline void thread_switch_to(Genode::Thread *thread_base) /** * Unconditionally block the calling thread */ -static inline void thread_stop_myself() +static inline void thread_stop_myself(Genode::Thread *myself) { - Genode::Thread *myself = Genode::Thread::myself(); Pistachio::L4_ThreadId_t tid = myself ? myself->native_thread().l4id : main_thread_tid; diff --git a/repos/base-sel4/src/include/base/internal/lock_helper.h b/repos/base-sel4/src/include/base/internal/lock_helper.h index d450833351..ebbbc4295e 100644 --- a/repos/base-sel4/src/include/base/internal/lock_helper.h +++ b/repos/base-sel4/src/include/base/internal/lock_helper.h @@ -44,14 +44,12 @@ static inline bool thread_check_stopped_and_restart(Genode::Thread *thread) } -static inline void thread_stop_myself() +static inline void thread_stop_myself(Genode::Thread *myself) { - Genode::Thread *myself = Genode::Thread::myself(); - unsigned lock_sel = Genode::INITIAL_SEL_LOCK; /* main thread */ if (myself) - lock_sel = Genode::Thread::myself()->native_thread().lock_sel; + lock_sel = myself->native_thread().lock_sel; seL4_Word sender = ~0U; seL4_Wait(lock_sel, &sender); diff --git a/repos/base/include/base/cancelable_lock.h b/repos/base/include/base/cancelable_lock.h index 3bcff6ef37..8bb30ab180 100644 --- a/repos/base/include/base/cancelable_lock.h +++ b/repos/base/include/base/cancelable_lock.h @@ -21,11 +21,14 @@ namespace Genode { class Thread; class Cancelable_lock; + class Mutex; } class Genode::Cancelable_lock { + friend class Mutex; + private: class Applicant @@ -68,6 +71,9 @@ class Genode::Cancelable_lock Applicant _owner; + bool lock_owner(Applicant &myself) { return _owner == myself; } + void lock(Applicant &); + public: enum State { LOCKED, UNLOCKED }; diff --git a/repos/base/include/base/mutex.h b/repos/base/include/base/mutex.h new file mode 100644 index 0000000000..40cc87d45c --- /dev/null +++ b/repos/base/include/base/mutex.h @@ -0,0 +1,46 @@ +/* + * \brief Mutex primitives + * \author Alexander Boettcher + * \date 2020-01-24 + */ + +/* + * Copyright (C) 2020 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__BASE__MUTEX_H_ +#define _INCLUDE__BASE__MUTEX_H_ + +#include +#include + +namespace Genode { class Mutex; } + + +class Genode::Mutex : Noncopyable +{ + private: + Lock _lock { }; + + public: + explicit Mutex() { } + + void acquire(); + void release(); + + class Guard + { + private: + Mutex &_mutex; + + public: + explicit Guard(Mutex &mutex) : _mutex(mutex) { _mutex.acquire(); } + + ~Guard() { _mutex.release(); } + }; +}; + +#endif /* _INCLUDE__BASE__MUTEX_H_ */ diff --git a/repos/base/lib/mk/base-common.inc b/repos/base/lib/mk/base-common.inc index 475f0e461f..d00d26461d 100644 --- a/repos/base/lib/mk/base-common.inc +++ b/repos/base/lib/mk/base-common.inc @@ -17,6 +17,7 @@ SRC_CC += session_state.cc SRC_CC += elf_binary.cc SRC_CC += ipc.cc SRC_CC += lock.cc +SRC_CC += mutex.cc SRC_CC += log.cc SRC_CC += raw_output.cc SRC_CC += rpc_entrypoint.cc diff --git a/repos/base/lib/symbols/ld b/repos/base/lib/symbols/ld index 2e76e157d7..91c3688bb5 100644 --- a/repos/base/lib/symbols/ld +++ b/repos/base/lib/symbols/ld @@ -32,7 +32,7 @@ # # -# Copyright (C) 2016-2019 Genode Labs GmbH +# Copyright (C) 2016-2020 Genode Labs GmbH # # This file is part of the Genode OS framework, which is distributed # under the terms of the GNU Affero General Public License version 3. @@ -270,6 +270,8 @@ _ZN6Genode5ChildC2ERNS_10Region_mapERNS_14Rpc_entrypointERNS_12Child_policyE T _ZN6Genode5ChildD0Ev T _ZN6Genode5ChildD1Ev T _ZN6Genode5ChildD2Ev T +_ZN6Genode5Mutex7acquireEv T +_ZN6Genode5Mutex7releaseEv T _ZN6Genode5Stack4sizeEm T _ZN6Genode5Trace6Logger17_evaluate_controlEv T _ZN6Genode5Trace6Logger3logEPKcm T diff --git a/repos/base/src/lib/base/lock.cc b/repos/base/src/lib/base/lock.cc index 76536664b8..268b1edd1a 100644 --- a/repos/base/src/lib/base/lock.cc +++ b/repos/base/src/lib/base/lock.cc @@ -63,7 +63,11 @@ void Cancelable_lock::Applicant::wake_up() void Cancelable_lock::lock() { Applicant myself(Thread::myself()); + lock(myself); +} +void Cancelable_lock::lock(Applicant &myself) +{ spinlock_lock(&_spinlock_state); if (cmpxchg(&_state, UNLOCKED, LOCKED)) { @@ -121,7 +125,7 @@ void Cancelable_lock::lock() * ! for (int i = 0; i < 10; i++) * ! thread_yield(); */ - thread_stop_myself(); + thread_stop_myself(myself.thread_base()); /* * We expect to be the lock owner when woken up. If this is not diff --git a/repos/base/src/lib/base/mutex.cc b/repos/base/src/lib/base/mutex.cc new file mode 100644 index 0000000000..f7a8c2315e --- /dev/null +++ b/repos/base/src/lib/base/mutex.cc @@ -0,0 +1,42 @@ +/* + * \brief Mutex primitives + * \author Alexander Boettcher + * \date 2020-01-24 + */ + +/* + * Copyright (C) 2020 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#include +#include +#include + +void Genode::Mutex::acquire() +{ + Lock::Applicant myself(Thread::myself()); + if (_lock.lock_owner(myself)) + Genode::error("deadlock ahead, mutex=", this, ", return ip=", + __builtin_return_address(0)); + + while (1) + try { + _lock.Cancelable_lock::lock(myself); + return; + } catch (Blocking_canceled) { } +} + +void Genode::Mutex::release() +{ + Lock::Applicant myself(Thread::myself()); + if (!_lock.lock_owner(myself)) { + Genode::error("denied non mutex owner the release, mutex=", + this, ", return ip=", + __builtin_return_address(0)); + return; + } + _lock.unlock(); +}