1 //===-- Linux implementation of the callonce function ---------------------===// 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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "src/__support/threads/callonce.h" 10 #include "src/__support/macros/config.h" 11 #include "src/__support/threads/linux/callonce.h" 12 #include "src/__support/threads/linux/futex_utils.h" 13 14 namespace LIBC_NAMESPACE_DECL { 15 namespace callonce_impl { callonce_slowpath(CallOnceFlag * flag,CallOnceCallback * func)16int callonce_slowpath(CallOnceFlag *flag, CallOnceCallback *func) { 17 auto *futex_word = reinterpret_cast<Futex *>(flag); 18 19 FutexWordType not_called = NOT_CALLED; 20 21 // The call_once call can return only after the called function |func| 22 // returns. So, we use futexes to synchronize calls with the same flag value. 23 if (futex_word->compare_exchange_strong(not_called, START)) { 24 func(); 25 auto status = futex_word->exchange(FINISH); 26 if (status == WAITING) 27 futex_word->notify_all(); 28 return 0; 29 } 30 31 FutexWordType status = START; 32 if (futex_word->compare_exchange_strong(status, WAITING) || 33 status == WAITING) { 34 futex_word->wait(WAITING); 35 } 36 37 return 0; 38 } 39 } // namespace callonce_impl 40 } // namespace LIBC_NAMESPACE_DECL 41