brintos

brintos / llvm-project-archived public Read only

0
0
Text · 2.0 KiB · 70872b6 Raw
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