diff --git a/libc/src/__support/threads/linux/callonce.cpp b/libc/src/__support/threads/linux/callonce.cpp index 1c29db5f5c1a1..b48a514a44875 100644 --- a/libc/src/__support/threads/linux/callonce.cpp +++ b/libc/src/__support/threads/linux/callonce.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "src/__support/threads/callonce.h" +#include "src/__support/macros/optimization.h" #include "src/__support/threads/linux/futex_utils.h" namespace LIBC_NAMESPACE { @@ -21,6 +22,12 @@ int callonce(CallOnceFlag *flag, CallOnceCallback *func) { FutexWordType not_called = NOT_CALLED; + // Avoid cmpxchg operation if the function has already been called. + // The destination operand of cmpxchg may receive a write cycle without + // regard to the result of the comparison + if (LIBC_LIKELY(futex_word->load(cpp::MemoryOrder::RELAXED) == FINISH)) + return 0; + // The call_once call can return only after the called function |func| // returns. So, we use futexes to synchronize calls with the same flag value. if (futex_word->compare_exchange_strong(not_called, START)) {