Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[libc] avoid cmpxchg on the fastpath of callonce #91748

Merged
merged 1 commit into from
May 10, 2024

Conversation

SchrodingerZhu
Copy link
Contributor

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

@llvmbot
Copy link

llvmbot commented May 10, 2024

@llvm/pr-subscribers-libc

Author: Schrodinger ZHU Yifan (SchrodingerZhu)

Changes

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


Full diff: https://github.com/llvm/llvm-project/pull/91748.diff

1 Files Affected:

  • (modified) libc/src/__support/threads/linux/callonce.cpp (+7)
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)) {

@SchrodingerZhu SchrodingerZhu merged commit b8f4f39 into llvm:main May 10, 2024
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants