ruby-32: re-add architecure independent manifest support, remove unnecassary GNU_CPU...
[oi-userland.git] / components / library / icu-74 / patches / 154-icu-source-common-umutex.cpp.patch
blob3826d94c09138ad3048def95a918b149c6e877af
1 Note that programs that link ICU library may crash
2 because std::call_once cannot handle C++ exceptions.
3 The reason is that GCC's implementation calls pthread_once
4 that is not C++ exception aware at least in Solaris libc.
6 To workaround this issue, a simple implementation based
7 on C++11 atomic operations and variadic templates is provided.
8 This way we avoid that C++ exception is thrown in libc library.
10 Note that the implementation is far from optimal with respect
11 to the performance, for example, the following could be improved:
12 1) use a condition variable instead of yield if thread contention is high
13 2) utilize C++11 memory model to reduce synchronization overhead
15 However, the workaround is temporary as an untested patch is available on GCC's bugzilla:
16 https://gcc.gnu.org/pipermail/gcc-patches/2020-November/557928.html
18 The patch is not suitable for upstream.
19 It only fixes the problem in ICU library.
21 --- icu/source/common/umutex.cpp.orig
22 +++ icu/source/common/umutex.cpp
23 @@ -26,6 +26,7 @@
24 #include "uassert.h"
25 #include "ucln_cmn.h"
26 #include "cmemory.h"
27 +#include <thread>
29 U_NAMESPACE_BEGIN
31 @@ -51,21 +52,54 @@
32 // Used when ICU implementation code passes nullptr for the mutex pointer.
33 UMutex globalMutex;
35 +#if defined(sun) || defined(__sun) || defined(__sun__)
36 +enum class CallOnceState : int {
37 + INIT, RUNNING, FINISH
38 +};
40 +std::atomic<CallOnceState> initState;
41 +#else
42 std::once_flag initFlag;
43 std::once_flag *pInitFlag = &initFlag;
45 +#endif
46 } // Anonymous namespace
48 +#if defined(sun) || defined(__sun) || defined(__sun__)
49 +template <class Callable, class... Args>
50 +void solaris_call_once(std::atomic<CallOnceState>& state, Callable&& fce, Args&&... args) {
51 + if (state != CallOnceState::FINISH) {
52 + do {
53 + CallOnceState expected = CallOnceState::INIT, desired = CallOnceState::RUNNING;
54 + if (state.compare_exchange_strong(expected, desired)) {
55 + try {
56 + fce(std::forward<Args>(args)...);
57 + state = CallOnceState::FINISH;
58 + } catch (...) {
59 + state = CallOnceState::INIT;
60 + throw;
61 + }
62 + } else {
63 + std::this_thread::yield();
64 + }
65 + } while (state != CallOnceState::FINISH);
66 + }
68 +#endif
70 U_CDECL_BEGIN
71 static UBool U_CALLCONV umtx_cleanup() {
72 initMutex->~mutex();
73 initCondition->~condition_variable();
74 UMutex::cleanup();
76 + #if defined(sun) || defined(__sun) || defined(__sun__)
77 + initState = CallOnceState::INIT;
78 + #else
79 // Reset the once_flag, by destructing it and creating a fresh one in its place.
80 // Do not use this trick anywhere else in ICU; use umtx_initOnce, not std::call_once().
81 pInitFlag->~once_flag();
82 pInitFlag = new(&initFlag) std::once_flag();
83 + #endif
84 return true;
87 @@ -80,7 +114,11 @@
88 std::mutex *UMutex::getMutex() {
89 std::mutex *retPtr = fMutex.load(std::memory_order_acquire);
90 if (retPtr == nullptr) {
91 + #if defined(sun) || defined(__sun) || defined(__sun__)
92 + solaris_call_once(initState, umtx_init);
93 + #else
94 std::call_once(*pInitFlag, umtx_init);
95 + #endif
96 std::lock_guard<std::mutex> guard(*initMutex);
97 retPtr = fMutex.load(std::memory_order_acquire);
98 if (retPtr == nullptr) {
99 @@ -143,7 +181,11 @@
101 U_COMMON_API UBool U_EXPORT2
102 umtx_initImplPreInit(UInitOnce &uio) {
103 + #if defined(sun) || defined(__sun) || defined(__sun__)
104 + solaris_call_once(initState, umtx_init);
105 + #else
106 std::call_once(*pInitFlag, umtx_init);
107 + #endif
108 std::unique_lock<std::mutex> lock(*initMutex);
109 if (umtx_loadAcquire(uio.fState) == 0) {
110 umtx_storeRelease(uio.fState, 1);