mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-18 02:40:08 +00:00
base: add mutex as derivate of lock
The mutex class is more restrictive in usage compared to Genode::Lock. - At initialiation time it is ever unlocked. - No thread is permitted to lock twice. Warn about it in case it happens. - Only the lock onwer is permitted to unlock the mutex. Warn about it and don't unlock the mutex in case it happens. Issue #3612
This commit is contained in:
parent
d1609e771a
commit
00f69bc70d
@ -13,6 +13,7 @@
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/cancelable_lock.h>
|
||||
#include <base/thread.h>
|
||||
#include <cpu/atomic.h>
|
||||
#include <cpu/memory_barrier.h>
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
#include <base/lock.h>
|
||||
#include <base/mutex.h>
|
||||
#include <hw/assert.h>
|
||||
|
||||
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();
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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 };
|
||||
|
46
repos/base/include/base/mutex.h
Normal file
46
repos/base/include/base/mutex.h
Normal file
@ -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 <base/lock.h>
|
||||
#include <util/noncopyable.h>
|
||||
|
||||
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_ */
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
42
repos/base/src/lib/base/mutex.cc
Normal file
42
repos/base/src/lib/base/mutex.cc
Normal file
@ -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 <base/mutex.h>
|
||||
#include <base/log.h>
|
||||
#include <base/thread.h>
|
||||
|
||||
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();
|
||||
}
|
Loading…
Reference in New Issue
Block a user