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();
+}