58 lines · c
1//===-- Linux callonce fastpath -------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8#ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_CALLONCE_H9#define LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_CALLONCE_H10 11#include "src/__support/macros/config.h"12#include "src/__support/threads/linux/futex_utils.h"13 14namespace LIBC_NAMESPACE_DECL {15using CallOnceFlag = Futex;16 17namespace callonce_impl {18static constexpr FutexWordType NOT_CALLED = 0x0;19static constexpr FutexWordType START = 0x11;20static constexpr FutexWordType WAITING = 0x22;21static constexpr FutexWordType FINISH = 0x33;22 23// Avoid cmpxchg operation if the function has already been called.24// The destination operand of cmpxchg may receive a write cycle without25// regard to the result of the comparison.26LIBC_INLINE bool callonce_fastpath(CallOnceFlag *flag) {27 return flag->load(cpp::MemoryOrder::RELAXED) == FINISH;28}29 30template <class CallOnceCallback>31[[gnu::noinline, gnu::cold]] int callonce_slowpath(CallOnceFlag *flag,32 CallOnceCallback callback) {33 34 auto *futex_word = reinterpret_cast<Futex *>(flag);35 36 FutexWordType not_called = NOT_CALLED;37 38 // The call_once call can return only after the called function |func|39 // returns. So, we use futexes to synchronize calls with the same flag value.40 if (futex_word->compare_exchange_strong(not_called, START)) {41 callback();42 auto status = futex_word->exchange(FINISH);43 if (status == WAITING)44 futex_word->notify_all();45 return 0;46 }47 48 FutexWordType status = START;49 if (futex_word->compare_exchange_strong(status, WAITING) || status == WAITING)50 futex_word->wait(WAITING);51 52 return 0;53}54} // namespace callonce_impl55 56} // namespace LIBC_NAMESPACE_DECL57#endif // LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_CALLONCE_H58