From be58af8225a3b6bcb126f81bf292771318d10d01 Mon Sep 17 00:00:00 2001 From: avogar Date: Tue, 9 Aug 2022 10:08:45 +0000 Subject: [PATCH] Fix deadlock with msan --- cpp/src/arrow/util/mutex.cc | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/cpp/src/arrow/util/mutex.cc b/cpp/src/arrow/util/mutex.cc index f0b51a73e965..ca8aa0412d65 100644 --- a/cpp/src/arrow/util/mutex.cc +++ b/cpp/src/arrow/util/mutex.cc @@ -62,18 +62,41 @@ struct AfterForkState { // The leak (only in child processes) is a small price to pay for robustness. Mutex* mutex = nullptr; + enum State { + INITIALIZED, + IN_PROCESS, + NOT_INITIALIZED, + }; + + std::atomic_int state = INITIALIZED; + private: AfterForkState() { pthread_atfork(/*prepare=*/nullptr, /*parent=*/nullptr, /*child=*/&AfterFork); } - static void AfterFork() { instance.mutex = new Mutex; } + static void AfterFork() { instance.state.store(NOT_INITIALIZED); } + }; AfterForkState AfterForkState::instance; } // namespace -Mutex* GlobalForkSafeMutex() { return AfterForkState::instance.mutex; } +Mutex* GlobalForkSafeMutex() { + if (AfterForkState::instance.state.load() == AfterForkState::State::INITIALIZED) { + return AfterForkState::instance.mutex; + } + + int expected = AfterForkState::State::NOT_INITIALIZED; + if (AfterForkState::instance.state.compare_exchange_strong(expected, AfterForkState::State::IN_PROCESS)) { + AfterForkState::instance.mutex = new Mutex; + AfterForkState::instance.state.store(AfterForkState::State::INITIALIZED); + } else { + while (AfterForkState::instance.state.load() != AfterForkState::State::INITIALIZED); + } + + return AfterForkState::instance.mutex; +} #endif // _WIN32 } // namespace util