summaryrefslogtreecommitdiffstats
path: root/core/os
diff options
context:
space:
mode:
Diffstat (limited to 'core/os')
-rw-r--r--core/os/condition_variable.h8
-rw-r--r--core/os/mutex.h9
-rw-r--r--core/os/safe_binary_mutex.h85
3 files changed, 61 insertions, 41 deletions
diff --git a/core/os/condition_variable.h b/core/os/condition_variable.h
index fa1355e98c..c819fa6b40 100644
--- a/core/os/condition_variable.h
+++ b/core/os/condition_variable.h
@@ -32,6 +32,7 @@
#define CONDITION_VARIABLE_H
#include "core/os/mutex.h"
+#include "core/os/safe_binary_mutex.h"
#ifdef THREADS_ENABLED
@@ -56,7 +57,12 @@ class ConditionVariable {
public:
template <typename BinaryMutexT>
_ALWAYS_INLINE_ void wait(const MutexLock<BinaryMutexT> &p_lock) const {
- condition.wait(const_cast<THREADING_NAMESPACE::unique_lock<THREADING_NAMESPACE::mutex> &>(p_lock.lock));
+ condition.wait(const_cast<THREADING_NAMESPACE::unique_lock<THREADING_NAMESPACE::mutex> &>(p_lock._get_lock()));
+ }
+
+ template <int Tag>
+ _ALWAYS_INLINE_ void wait(const MutexLock<SafeBinaryMutex<Tag>> &p_lock) const {
+ condition.wait(const_cast<THREADING_NAMESPACE::unique_lock<THREADING_NAMESPACE::mutex> &>(p_lock.mutex._get_lock()));
}
_ALWAYS_INLINE_ void notify_one() const {
diff --git a/core/os/mutex.h b/core/os/mutex.h
index 3e7aa81bc1..773b31828d 100644
--- a/core/os/mutex.h
+++ b/core/os/mutex.h
@@ -72,13 +72,18 @@ public:
template <typename MutexT>
class MutexLock {
- friend class ConditionVariable;
-
THREADING_NAMESPACE::unique_lock<typename MutexT::StdMutexType> lock;
public:
explicit MutexLock(const MutexT &p_mutex) :
lock(p_mutex.mutex) {}
+
+ // Clarification: all the funny syntax is needed so this function exists only for binary mutexes.
+ template <typename T = MutexT>
+ _ALWAYS_INLINE_ THREADING_NAMESPACE::unique_lock<THREADING_NAMESPACE::mutex> &_get_lock(
+ typename std::enable_if<std::is_same<T, THREADING_NAMESPACE::mutex>::value> * = nullptr) const {
+ return const_cast<THREADING_NAMESPACE::unique_lock<THREADING_NAMESPACE::mutex> &>(lock);
+ }
};
using Mutex = MutexImpl<THREADING_NAMESPACE::recursive_mutex>; // Recursive, for general use
diff --git a/core/os/safe_binary_mutex.h b/core/os/safe_binary_mutex.h
index 1e98cc074c..1035ee76b4 100644
--- a/core/os/safe_binary_mutex.h
+++ b/core/os/safe_binary_mutex.h
@@ -37,6 +37,11 @@
#ifdef THREADS_ENABLED
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wundefined-var-template"
+#endif
+
// 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).
@@ -47,76 +52,80 @@
// Also, don't forget to declare the thread_local variable on each use.
template <int Tag>
class SafeBinaryMutex {
- friend class MutexLock<SafeBinaryMutex>;
+ friend class MutexLock<SafeBinaryMutex<Tag>>;
using StdMutexType = THREADING_NAMESPACE::mutex;
mutable THREADING_NAMESPACE::mutex mutex;
- static thread_local uint32_t count;
+
+ struct TLSData {
+ mutable THREADING_NAMESPACE::unique_lock<THREADING_NAMESPACE::mutex> lock;
+ uint32_t count = 0;
+
+ TLSData(SafeBinaryMutex<Tag> &p_mutex) :
+ lock(p_mutex.mutex, THREADING_NAMESPACE::defer_lock) {}
+ };
+ static thread_local TLSData tls_data;
public:
_ALWAYS_INLINE_ void lock() const {
- if (++count == 1) {
- mutex.lock();
+ if (++tls_data.count == 1) {
+ tls_data.lock.lock();
}
}
_ALWAYS_INLINE_ void unlock() const {
- DEV_ASSERT(count);
- if (--count == 0) {
- mutex.unlock();
+ DEV_ASSERT(tls_data.count);
+ if (--tls_data.count == 0) {
+ tls_data.lock.unlock();
}
}
- _ALWAYS_INLINE_ bool try_lock() const {
- if (count) {
- count++;
- return true;
- } else {
- if (mutex.try_lock()) {
- count++;
- return true;
- } else {
- return false;
- }
- }
+ _ALWAYS_INLINE_ THREADING_NAMESPACE::unique_lock<THREADING_NAMESPACE::mutex> &_get_lock() const {
+ return const_cast<THREADING_NAMESPACE::unique_lock<THREADING_NAMESPACE::mutex> &>(tls_data.lock);
}
- ~SafeBinaryMutex() {
- DEV_ASSERT(!count);
+ _ALWAYS_INLINE_ SafeBinaryMutex() {
+ }
+
+ _ALWAYS_INLINE_ ~SafeBinaryMutex() {
+ DEV_ASSERT(!tls_data.count);
}
};
-// This specialization is needed so manual locking and MutexLock can be used
-// at the same time on a SafeBinaryMutex.
template <int Tag>
class MutexLock<SafeBinaryMutex<Tag>> {
friend class ConditionVariable;
- THREADING_NAMESPACE::unique_lock<THREADING_NAMESPACE::mutex> lock;
+ const SafeBinaryMutex<Tag> &mutex;
public:
- _ALWAYS_INLINE_ explicit MutexLock(const SafeBinaryMutex<Tag> &p_mutex) :
- lock(p_mutex.mutex) {
- SafeBinaryMutex<Tag>::count++;
- };
- _ALWAYS_INLINE_ ~MutexLock() {
- SafeBinaryMutex<Tag>::count--;
- };
+ explicit MutexLock(const SafeBinaryMutex<Tag> &p_mutex) :
+ mutex(p_mutex) {
+ mutex.lock();
+ }
+
+ ~MutexLock() {
+ mutex.unlock();
+ }
};
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
#else // No threads.
template <int Tag>
-class SafeBinaryMutex : public MutexImpl {
- static thread_local uint32_t count;
-};
+class SafeBinaryMutex {
+ struct TLSData {
+ TLSData(SafeBinaryMutex<Tag> &p_mutex) {}
+ };
+ static thread_local TLSData tls_data;
-template <int Tag>
-class MutexLock<SafeBinaryMutex<Tag>> {
public:
- MutexLock(const SafeBinaryMutex<Tag> &p_mutex) {}
- ~MutexLock() {}
+ void lock() const {}
+ void unlock() const {}
};
#endif // THREADS_ENABLED