xref: /llvm-project/libc/src/__support/threads/linux/callonce.cpp (revision 5ff3ff33ff930e4ec49da7910612d8a41eb068cb)
133675390SSiva Chandra Reddy //===-- Linux implementation of the callonce function ---------------------===//
233675390SSiva Chandra Reddy //
333675390SSiva Chandra Reddy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
433675390SSiva Chandra Reddy // See https://llvm.org/LICENSE.txt for license information.
533675390SSiva Chandra Reddy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
633675390SSiva Chandra Reddy //
733675390SSiva Chandra Reddy //===----------------------------------------------------------------------===//
833675390SSiva Chandra Reddy 
933675390SSiva Chandra Reddy #include "src/__support/threads/callonce.h"
10*5ff3ff33SPetr Hosek #include "src/__support/macros/config.h"
116d61d837SSchrodinger ZHU Yifan #include "src/__support/threads/linux/callonce.h"
12ab3a9e72SSchrodinger ZHU Yifan #include "src/__support/threads/linux/futex_utils.h"
1333675390SSiva Chandra Reddy 
14*5ff3ff33SPetr Hosek namespace LIBC_NAMESPACE_DECL {
156d61d837SSchrodinger ZHU Yifan namespace callonce_impl {
166d61d837SSchrodinger ZHU Yifan int callonce_slowpath(CallOnceFlag *flag, CallOnceCallback *func) {
17ab3a9e72SSchrodinger ZHU Yifan   auto *futex_word = reinterpret_cast<Futex *>(flag);
1833675390SSiva Chandra Reddy 
1933675390SSiva Chandra Reddy   FutexWordType not_called = NOT_CALLED;
2033675390SSiva Chandra Reddy 
2133675390SSiva Chandra Reddy   // The call_once call can return only after the called function |func|
2233675390SSiva Chandra Reddy   // returns. So, we use futexes to synchronize calls with the same flag value.
2333675390SSiva Chandra Reddy   if (futex_word->compare_exchange_strong(not_called, START)) {
2433675390SSiva Chandra Reddy     func();
2533675390SSiva Chandra Reddy     auto status = futex_word->exchange(FINISH);
26ab3a9e72SSchrodinger ZHU Yifan     if (status == WAITING)
27ab3a9e72SSchrodinger ZHU Yifan       futex_word->notify_all();
2833675390SSiva Chandra Reddy     return 0;
2933675390SSiva Chandra Reddy   }
3033675390SSiva Chandra Reddy 
3133675390SSiva Chandra Reddy   FutexWordType status = START;
3233675390SSiva Chandra Reddy   if (futex_word->compare_exchange_strong(status, WAITING) ||
3333675390SSiva Chandra Reddy       status == WAITING) {
34ab3a9e72SSchrodinger ZHU Yifan     futex_word->wait(WAITING);
3533675390SSiva Chandra Reddy   }
3633675390SSiva Chandra Reddy 
3733675390SSiva Chandra Reddy   return 0;
3833675390SSiva Chandra Reddy }
396d61d837SSchrodinger ZHU Yifan } // namespace callonce_impl
40*5ff3ff33SPetr Hosek } // namespace LIBC_NAMESPACE_DECL
41