summaryrefslogtreecommitdiff
path: root/core/os/mutex.h
diff options
context:
space:
mode:
Diffstat (limited to 'core/os/mutex.h')
-rw-r--r--core/os/mutex.h69
1 files changed, 62 insertions, 7 deletions
diff --git a/core/os/mutex.h b/core/os/mutex.h
index ceedcb235a..90cc1632e8 100644
--- a/core/os/mutex.h
+++ b/core/os/mutex.h
@@ -31,12 +31,20 @@
#ifndef MUTEX_H
#define MUTEX_H
+#include "core/error/error_macros.h"
#include "core/typedefs.h"
#include <mutex>
+template <class MutexT>
+class MutexLock;
+
template <class StdMutexT>
class MutexImpl {
+ friend class MutexLock<MutexImpl<StdMutexT>>;
+
+ using StdMutexType = StdMutexT;
+
mutable StdMutexT mutex;
public:
@@ -53,18 +61,65 @@ public:
}
};
+// A very special kind of mutex, used in scenarios where these
+// requirements hold at the same time:
+// - Must be used with a condition variable (only binary mutexes are suitable).
+// - Must have recursive semnantics (or simulate, as this one does).
+// The implementation keeps the lock count in TS. Therefore, only
+// one object of each version of the template can exists; hence the Tag argument.
+// Tags must be unique across the Godot codebase.
+// Also, don't forget to declare the thread_local variable on each use.
+template <int Tag>
+class SafeBinaryMutex {
+ friend class MutexLock<SafeBinaryMutex>;
+
+ using StdMutexType = std::mutex;
+
+ mutable std::mutex mutex;
+ static thread_local uint32_t count;
+
+public:
+ _ALWAYS_INLINE_ void lock() const {
+ if (++count == 1) {
+ mutex.lock();
+ }
+ }
+
+ _ALWAYS_INLINE_ void unlock() const {
+ DEV_ASSERT(count);
+ if (--count == 0) {
+ mutex.unlock();
+ }
+ }
+
+ _ALWAYS_INLINE_ bool try_lock() const {
+ if (count) {
+ count++;
+ return true;
+ } else {
+ if (mutex.try_lock()) {
+ count++;
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ ~SafeBinaryMutex() {
+ DEV_ASSERT(!count);
+ }
+};
+
template <class MutexT>
class MutexLock {
- const MutexT &mutex;
+ friend class ConditionVariable;
+
+ std::unique_lock<typename MutexT::StdMutexType> lock;
public:
_ALWAYS_INLINE_ explicit MutexLock(const MutexT &p_mutex) :
- mutex(p_mutex) {
- mutex.lock();
- }
-
- _ALWAYS_INLINE_ ~MutexLock() {
- mutex.unlock();
+ lock(p_mutex.mutex) {
}
};