summaryrefslogtreecommitdiff
path: root/deps/icu-small/source/common/umutex.h
diff options
context:
space:
mode:
Diffstat (limited to 'deps/icu-small/source/common/umutex.h')
-rwxr-xr-xdeps/icu-small/source/common/umutex.h119
1 files changed, 64 insertions, 55 deletions
diff --git a/deps/icu-small/source/common/umutex.h b/deps/icu-small/source/common/umutex.h
index 1674d00bb2..7588bcc5d9 100755
--- a/deps/icu-small/source/common/umutex.h
+++ b/deps/icu-small/source/common/umutex.h
@@ -23,6 +23,7 @@
#include <atomic>
#include <condition_variable>
#include <mutex>
+#include <type_traits>
#include "unicode/utypes.h"
#include "unicode/uclean.h"
@@ -36,10 +37,11 @@
#error U_USER_ATOMICS and U_USER_MUTEX_H are not supported
#endif
-
// Export an explicit template instantiation of std::atomic<int32_t>.
// When building DLLs for Windows this is required as it is used as a data member of the exported SharedObject class.
// See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples.
+//
+// Similar story for std::atomic<std::mutex *>, and the exported UMutex class.
#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN && !defined(U_IN_DOXYGEN)
#if defined(__clang__) || defined(_MSC_VER)
#if defined(__clang__)
@@ -48,12 +50,14 @@
#pragma clang diagnostic ignored "-Winstantiation-after-specialization"
#endif
template struct U_COMMON_API std::atomic<int32_t>;
+template struct U_COMMON_API std::atomic<std::mutex *>;
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
#elif defined(__GNUC__)
// For GCC this class is already exported/visible, so no need for U_COMMON_API.
template struct std::atomic<int32_t>;
+template struct std::atomic<std::mutex *>;
#endif
#endif
@@ -180,49 +184,78 @@ template<class T> void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(T, UE
}
}
+// UMutex should be constexpr-constructible, so that no initialization code
+// is run during startup.
+// This works on all C++ libraries except MS VS before VS2019.
+#if (defined(_CPPLIB_VER) && !defined(_MSVC_STL_VERSION)) || \
+ (defined(_MSVC_STL_VERSION) && _MSVC_STL_VERSION < 142)
+ // (VS std lib older than VS2017) || (VS std lib version < VS2019)
+# define UMUTEX_CONSTEXPR
+#else
+# define UMUTEX_CONSTEXPR constexpr
+#endif
-/*************************************************************************************************
+/**
+ * UMutex - ICU Mutex class.
*
- * ICU Mutex wrappers. Originally wrapped operating system mutexes, giving the rest of ICU a
- * platform independent set of mutex operations. Now vestigial, wrapping std::mutex only.
- * For internal ICU use only.
+ * This is the preferred Mutex class for use within ICU implementation code.
+ * It is a thin wrapper over C++ std::mutex, with these additions:
+ * - Static instances are safe, not triggering static construction or destruction,
+ * and the associated order of construction or destruction issues.
+ * - Plumbed into u_cleanup() for destructing the underlying std::mutex,
+ * which frees any OS level resources they may be holding.
*
- *************************************************************************************************/
+ * Limitations:
+ * - Static or global instances only. Cannot be heap allocated. Cannot appear as a
+ * member of another class.
+ * - No condition variables or other advanced features. If needed, you will need to use
+ * std::mutex and std::condition_variable directly. For an example, see unifiedcache.cpp
+ *
+ * Typical Usage:
+ * static UMutex myMutex;
+ *
+ * {
+ * Mutex lock(myMutex);
+ * ... // Do stuff that is protected by myMutex;
+ * } // myMutex is released when lock goes out of scope.
+ */
-struct UMutex : public icu::UMemory {
- UMutex() = default;
+class U_COMMON_API UMutex {
+public:
+ UMUTEX_CONSTEXPR UMutex() {}
~UMutex() = default;
+
UMutex(const UMutex &other) = delete;
UMutex &operator =(const UMutex &other) = delete;
+ void *operator new(size_t) = delete;
- std::mutex fMutex = {}; // Note: struct - pubic members - because most access is from
- // // plain C style functions (umtx_lock(), etc.)
-};
+ // requirements for C++ BasicLockable, allows UMutex to work with std::lock_guard
+ void lock() {
+ std::mutex *m = fMutex.load(std::memory_order_acquire);
+ if (m == nullptr) { m = getMutex(); }
+ m->lock();
+ }
+ void unlock() { fMutex.load(std::memory_order_relaxed)->unlock(); }
+ static void cleanup();
-struct UConditionVar : public icu::UMemory {
- U_COMMON_API UConditionVar();
- U_COMMON_API ~UConditionVar();
- UConditionVar(const UConditionVar &other) = delete;
- UConditionVar &operator =(const UConditionVar &other) = delete;
+private:
+ alignas(std::mutex) char fStorage[sizeof(std::mutex)] {};
+ std::atomic<std::mutex *> fMutex { nullptr };
- std::condition_variable_any fCV;
-};
+ /** All initialized UMutexes are kept in a linked list, so that they can be found,
+ * and the underlying std::mutex destructed, by u_cleanup().
+ */
+ UMutex *fListLink { nullptr };
+ static UMutex *gListHead;
-#define U_MUTEX_INITIALIZER {}
-#define U_CONDITION_INITIALIZER {}
+ /** Out-of-line function to lazily initialize a UMutex on first use.
+ * Initial fast check is inline, in lock(). The returned value may never
+ * be nullptr.
+ */
+ std::mutex *getMutex();
+};
-// Implementation notes for UConditionVar:
-//
-// Use an out-of-line constructor to reduce problems with the ICU dependency checker.
-// On Linux, the default constructor of std::condition_variable_any
-// produces an in-line reference to global operator new(), which the
-// dependency checker flags for any file that declares a UConditionVar. With
-// an out-of-line constructor, the dependency is constrained to umutex.o
-//
-// Do not export (U_COMMON_API) the entire class, but only the constructor
-// and destructor, to avoid Windows build problems with attempting to export the
-// std::condition_variable_any.
/* Lock a mutex.
* @param mutex The given mutex to be locked. Pass NULL to specify
@@ -237,30 +270,6 @@ U_INTERNAL void U_EXPORT2 umtx_lock(UMutex* mutex);
*/
U_INTERNAL void U_EXPORT2 umtx_unlock (UMutex* mutex);
-/*
- * Wait on a condition variable.
- * The calling thread will unlock the mutex and wait on the condition variable.
- * The mutex must be locked by the calling thread when invoking this function.
- *
- * @param cond the condition variable to wait on.
- * @param mutex the associated mutex.
- */
-
-U_INTERNAL void U_EXPORT2 umtx_condWait(UConditionVar *cond, UMutex *mutex);
-
-
-/*
- * Broadcast wakeup of all threads waiting on a Condition.
- *
- * @param cond the condition variable.
- */
-U_INTERNAL void U_EXPORT2 umtx_condBroadcast(UConditionVar *cond);
-
-/*
- * Signal a condition variable, waking up one waiting thread.
- */
-U_INTERNAL void U_EXPORT2 umtx_condSignal(UConditionVar *cond);
-
U_NAMESPACE_END