Index: llvm/include/llvm/Support/Threading.h =================================================================== --- llvm/include/llvm/Support/Threading.h +++ llvm/include/llvm/Support/Threading.h @@ -44,7 +44,7 @@ #if LLVM_THREADING_USE_STD_CALL_ONCE #include #else -#include "llvm/Support/Atomic.h" +#include #endif namespace llvm { @@ -98,7 +98,7 @@ /// This structure must be used as an opaque object. It is a struct to force /// autoinitialization and behave like std::once_flag. struct once_flag { - volatile sys::cas_flag status = Uninitialized; + std::atomic status(Uninitialized); }; #endif @@ -121,24 +121,21 @@ std::call_once(flag, std::forward(F), std::forward(ArgList)...); #else - // For other platforms we use a generic (if brittle) version based on our - // atomics. - sys::cas_flag old_val = sys::CompareAndSwap(&flag.status, Wait, Uninitialized); - if (old_val == Uninitialized) { + switch (flag.status.compare_exchange_strong(Uninitialized, Wait)) { + case Uninitialized: + // This is the first time the function is invoked. std::forward(F)(std::forward(ArgList)...); - sys::MemoryFence(); - TsanIgnoreWritesBegin(); - TsanHappensBefore(&flag.status); - flag.status = Done; - TsanIgnoreWritesEnd(); - } else { - // Wait until any thread doing the call has finished. - sys::cas_flag tmp = flag.status; - sys::MemoryFence(); - while (tmp != Done) { - tmp = flag.status; - sys::MemoryFence(); + flag.status.store(Done); + break; + + case Wait: + while (flag.status.load() != Done) { + // Wait for function to finish. } + break; + + case Done: + break; } TsanHappensAfter(&flag.status); #endif