1919
2020#include < mutex>
2121
22- #ifndef _WIN32
22+ #if !defined( _WIN32) && !defined(__ppc64__)
2323# include < pthread.h>
2424# include < atomic>
2525#endif
@@ -59,7 +59,7 @@ Mutex::Guard Mutex::Lock() {
5959
6060Mutex::Mutex () : impl_(new Impl, [](Impl* impl) { delete impl; }) {}
6161
62- #ifndef _WIN32
62+ #if !defined( _WIN32) && !defined(__ppc64__)
6363namespace {
6464
6565struct AfterForkState {
@@ -71,19 +71,42 @@ struct AfterForkState {
7171 // The leak (only in child processes) is a small price to pay for robustness.
7272 Mutex* mutex = nullptr ;
7373
74+ enum State {
75+ INITIALIZED,
76+ IN_PROCESS,
77+ NOT_INITIALIZED,
78+ };
79+
80+ std::atomic_int state = INITIALIZED;
81+
7482 private:
7583 AfterForkState () {
7684 pthread_atfork (/* prepare=*/ nullptr , /* parent=*/ nullptr , /* child=*/ &AfterFork);
7785 }
7886
79- static void AfterFork () { instance.mutex = new Mutex; }
87+ static void AfterFork () { instance.state .store (NOT_INITIALIZED); }
88+
8089};
8190
8291AfterForkState AfterForkState::instance;
8392} // namespace
8493
85- Mutex* GlobalForkSafeMutex () { return AfterForkState::instance.mutex ; }
86- #endif // _WIN32
94+ Mutex* GlobalForkSafeMutex () {
95+ if (AfterForkState::instance.state .load () == AfterForkState::State::INITIALIZED) {
96+ return AfterForkState::instance.mutex ;
97+ }
98+
99+ int expected = AfterForkState::State::NOT_INITIALIZED;
100+ if (AfterForkState::instance.state .compare_exchange_strong (expected, AfterForkState::State::IN_PROCESS)) {
101+ AfterForkState::instance.mutex = new Mutex;
102+ AfterForkState::instance.state .store (AfterForkState::State::INITIALIZED);
103+ } else {
104+ while (AfterForkState::instance.state .load () != AfterForkState::State::INITIALIZED);
105+ }
106+
107+ return AfterForkState::instance.mutex ;
108+ }
109+ #endif // _WIN32 and __ppc64__
87110
88111} // namespace util
89112} // namespace arrow
0 commit comments