umutex.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. // © 2016 and later: Unicode, Inc. and others.
  2. // License & terms of use: http://www.unicode.org/copyright.html
  3. /*
  4. ******************************************************************************
  5. *
  6. * Copyright (C) 1997-2016, International Business Machines
  7. * Corporation and others. All Rights Reserved.
  8. *
  9. ******************************************************************************
  10. *
  11. * File umutex.cpp
  12. *
  13. * Modification History:
  14. *
  15. * Date Name Description
  16. * 04/02/97 aliu Creation.
  17. * 04/07/99 srl updated
  18. * 05/13/99 stephen Changed to umutex (from cmutex).
  19. * 11/22/99 aliu Make non-global mutex autoinitialize [j151]
  20. ******************************************************************************
  21. */
  22. #include "umutex.h"
  23. #include "unicode/utypes.h"
  24. #include "uassert.h"
  25. #include "ucln_cmn.h"
  26. #include "cmemory.h"
  27. U_NAMESPACE_BEGIN
  28. #if defined(U_USER_MUTEX_CPP)
  29. // Support for including an alternate implementation of mutexes has been withdrawn.
  30. // See issue ICU-20185.
  31. #error U_USER_MUTEX_CPP not supported
  32. #endif
  33. /*************************************************************************************************
  34. *
  35. * ICU Mutex wrappers.
  36. *
  37. *************************************************************************************************/
  38. namespace {
  39. std::mutex *initMutex;
  40. std::condition_variable *initCondition;
  41. // The ICU global mutex.
  42. // Used when ICU implementation code passes nullptr for the mutex pointer.
  43. UMutex globalMutex;
  44. std::once_flag initFlag;
  45. std::once_flag *pInitFlag = &initFlag;
  46. } // Anonymous namespace
  47. U_CDECL_BEGIN
  48. static UBool U_CALLCONV umtx_cleanup() {
  49. initMutex->~mutex();
  50. initCondition->~condition_variable();
  51. UMutex::cleanup();
  52. // Reset the once_flag, by destructing it and creating a fresh one in its place.
  53. // Do not use this trick anywhere else in ICU; use umtx_initOnce, not std::call_once().
  54. pInitFlag->~once_flag();
  55. pInitFlag = new(&initFlag) std::once_flag();
  56. return true;
  57. }
  58. static void U_CALLCONV umtx_init() {
  59. initMutex = STATIC_NEW(std::mutex);
  60. initCondition = STATIC_NEW(std::condition_variable);
  61. ucln_common_registerCleanup(UCLN_COMMON_MUTEX, umtx_cleanup);
  62. }
  63. U_CDECL_END
  64. std::mutex *UMutex::getMutex() {
  65. std::mutex *retPtr = fMutex.load(std::memory_order_acquire);
  66. if (retPtr == nullptr) {
  67. std::call_once(*pInitFlag, umtx_init);
  68. std::lock_guard<std::mutex> guard(*initMutex);
  69. retPtr = fMutex.load(std::memory_order_acquire);
  70. if (retPtr == nullptr) {
  71. fMutex = new(fStorage) std::mutex();
  72. retPtr = fMutex;
  73. fListLink = gListHead;
  74. gListHead = this;
  75. }
  76. }
  77. U_ASSERT(retPtr != nullptr);
  78. return retPtr;
  79. }
  80. UMutex *UMutex::gListHead = nullptr;
  81. void UMutex::cleanup() {
  82. UMutex *next = nullptr;
  83. for (UMutex *m = gListHead; m != nullptr; m = next) {
  84. (*m->fMutex).~mutex();
  85. m->fMutex = nullptr;
  86. next = m->fListLink;
  87. m->fListLink = nullptr;
  88. }
  89. gListHead = nullptr;
  90. }
  91. U_CAPI void U_EXPORT2
  92. umtx_lock(UMutex *mutex) {
  93. if (mutex == nullptr) {
  94. mutex = &globalMutex;
  95. }
  96. mutex->lock();
  97. }
  98. U_CAPI void U_EXPORT2
  99. umtx_unlock(UMutex* mutex)
  100. {
  101. if (mutex == nullptr) {
  102. mutex = &globalMutex;
  103. }
  104. mutex->unlock();
  105. }
  106. /*************************************************************************************************
  107. *
  108. * UInitOnce Implementation
  109. *
  110. *************************************************************************************************/
  111. // This function is called when a test of a UInitOnce::fState reveals that
  112. // initialization has not completed, that we either need to call the init
  113. // function on this thread, or wait for some other thread to complete.
  114. //
  115. // The actual call to the init function is made inline by template code
  116. // that knows the C++ types involved. This function returns true if
  117. // the caller needs to call the Init function.
  118. //
  119. U_COMMON_API UBool U_EXPORT2
  120. umtx_initImplPreInit(UInitOnce &uio) {
  121. std::call_once(*pInitFlag, umtx_init);
  122. std::unique_lock<std::mutex> lock(*initMutex);
  123. if (umtx_loadAcquire(uio.fState) == 0) {
  124. umtx_storeRelease(uio.fState, 1);
  125. return true; // Caller will next call the init function.
  126. } else {
  127. while (umtx_loadAcquire(uio.fState) == 1) {
  128. // Another thread is currently running the initialization.
  129. // Wait until it completes.
  130. initCondition->wait(lock);
  131. }
  132. U_ASSERT(uio.fState == 2);
  133. return false;
  134. }
  135. }
  136. // This function is called by the thread that ran an initialization function,
  137. // just after completing the function.
  138. // Some threads may be waiting on the condition, requiring the broadcast wakeup.
  139. // Some threads may be racing to test the fState variable outside of the mutex,
  140. // requiring the use of store/release when changing its value.
  141. U_COMMON_API void U_EXPORT2
  142. umtx_initImplPostInit(UInitOnce &uio) {
  143. {
  144. std::unique_lock<std::mutex> lock(*initMutex);
  145. umtx_storeRelease(uio.fState, 2);
  146. }
  147. initCondition->notify_all();
  148. }
  149. U_NAMESPACE_END
  150. /*************************************************************************************************
  151. *
  152. * Deprecated functions for setting user mutexes.
  153. *
  154. *************************************************************************************************/
  155. U_DEPRECATED void U_EXPORT2
  156. u_setMutexFunctions(const void * /*context */, UMtxInitFn *, UMtxFn *,
  157. UMtxFn *, UMtxFn *, UErrorCode *status) {
  158. if (U_SUCCESS(*status)) {
  159. *status = U_UNSUPPORTED_ERROR;
  160. }
  161. }
  162. U_DEPRECATED void U_EXPORT2
  163. u_setAtomicIncDecFunctions(const void * /*context */, UMtxAtomicFn *, UMtxAtomicFn *,
  164. UErrorCode *status) {
  165. if (U_SUCCESS(*status)) {
  166. *status = U_UNSUPPORTED_ERROR;
  167. }
  168. }