Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions libc/src/__support/threads/callonce.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,32 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_CALLONCE_H
#define LLVM_LIBC_SRC___SUPPORT_THREADS_CALLONCE_H

#include "src/__support/macros/optimization.h" // LIBC_LIKELY

// Plaform specific routines, provides:
// - OnceFlag definition
// - callonce_impl::callonce_fastpath for fast path check
// - callonce_impl::callonce_slowpath for slow path execution
#ifdef __linux__
#include "src/__support/threads/linux/callonce.h"
#else
#error "callonce is not supported on this platform"
#endif

namespace LIBC_NAMESPACE {

struct CallOnceFlag;
// Common definitions
using CallOnceCallback = void(void);
namespace callonce_impl {
int callonce_slowpath(CallOnceFlag *flag, CallOnceCallback *callback);
} // namespace callonce_impl

int callonce(CallOnceFlag *flag, CallOnceCallback *callback);
LIBC_INLINE int callonce(CallOnceFlag *flag, CallOnceCallback *callback) {
if (LIBC_LIKELY(callonce_impl::callonce_fastpath(flag)))
return 0;

return callonce_impl::callonce_slowpath(flag, callback);
}
} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC___SUPPORT_THREADS_CALLONCE_H
2 changes: 2 additions & 0 deletions libc/src/__support/threads/linux/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,10 @@ add_object_library(
callonce.cpp
HDRS
../callonce.h
callonce.h
DEPENDS
.futex_utils
libc.src.__support.macros.optimization
)

add_object_library(
Expand Down
19 changes: 4 additions & 15 deletions libc/src/__support/threads/linux/callonce.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,16 @@
//===----------------------------------------------------------------------===//

#include "src/__support/threads/callonce.h"
#include "src/__support/macros/optimization.h"
#include "src/__support/threads/linux/callonce.h"
#include "src/__support/threads/linux/futex_utils.h"

namespace LIBC_NAMESPACE {

static constexpr FutexWordType NOT_CALLED = 0x0;
static constexpr FutexWordType START = 0x11;
static constexpr FutexWordType WAITING = 0x22;
static constexpr FutexWordType FINISH = 0x33;

int callonce(CallOnceFlag *flag, CallOnceCallback *func) {
namespace callonce_impl {
int callonce_slowpath(CallOnceFlag *flag, CallOnceCallback *func) {
auto *futex_word = reinterpret_cast<Futex *>(flag);

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)) {
Expand All @@ -46,5 +35,5 @@ int callonce(CallOnceFlag *flag, CallOnceCallback *func) {

return 0;
}

} // namespace callonce_impl
} // namespace LIBC_NAMESPACE
31 changes: 31 additions & 0 deletions libc/src/__support/threads/linux/callonce.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//===-- Linux callonce fastpath -------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_CALLONCE_H
#define LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_CALLONCE_H

#include "src/__support/threads/linux/futex_utils.h"

namespace LIBC_NAMESPACE {
using CallOnceFlag = Futex;

namespace callonce_impl {
static constexpr FutexWordType NOT_CALLED = 0x0;
static constexpr FutexWordType START = 0x11;
static constexpr FutexWordType WAITING = 0x22;
static constexpr FutexWordType FINISH = 0x33;

// 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.
LIBC_INLINE bool callonce_fastpath(CallOnceFlag *flag) {
return flag->load(cpp::MemoryOrder::RELAXED) == FINISH;
}
} // namespace callonce_impl

} // namespace LIBC_NAMESPACE
#endif // LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_CALLONCE_H