15f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 25f757f3fSDimitry Andric // 35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65f757f3fSDimitry Andric // 75f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 85f757f3fSDimitry Andric 95f757f3fSDimitry Andric #include <__mutex/once_flag.h> 105f757f3fSDimitry Andric #include <__utility/exception_guard.h> 115f757f3fSDimitry Andric 125f757f3fSDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS 13*0fca6ea1SDimitry Andric # include <__thread/support.h> 145f757f3fSDimitry Andric #endif 155f757f3fSDimitry Andric 165f757f3fSDimitry Andric #include "include/atomic_support.h" 175f757f3fSDimitry Andric 185f757f3fSDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 195f757f3fSDimitry Andric 205f757f3fSDimitry Andric // If dispatch_once_f ever handles C++ exceptions, and if one can get to it 215f757f3fSDimitry Andric // without illegal macros (unexpected macros not beginning with _UpperCase or 225f757f3fSDimitry Andric // __lowercase), and if it stops spinning waiting threads, then call_once should 235f757f3fSDimitry Andric // call into dispatch_once_f instead of here. Relevant radar this code needs to 245f757f3fSDimitry Andric // keep in sync with: 7741191. 255f757f3fSDimitry Andric 265f757f3fSDimitry Andric #ifndef _LIBCPP_HAS_NO_THREADS 275f757f3fSDimitry Andric static constinit __libcpp_mutex_t mut = _LIBCPP_MUTEX_INITIALIZER; 285f757f3fSDimitry Andric static constinit __libcpp_condvar_t cv = _LIBCPP_CONDVAR_INITIALIZER; 295f757f3fSDimitry Andric #endif 305f757f3fSDimitry Andric 31cb14a3feSDimitry Andric void __call_once(volatile once_flag::_State_type& flag, void* arg, void (*func)(void*)) { 325f757f3fSDimitry Andric #if defined(_LIBCPP_HAS_NO_THREADS) 335f757f3fSDimitry Andric 345f757f3fSDimitry Andric if (flag == once_flag::_Unset) { 355f757f3fSDimitry Andric auto guard = std::__make_exception_guard([&flag] { flag = once_flag::_Unset; }); 365f757f3fSDimitry Andric flag = once_flag::_Pending; 375f757f3fSDimitry Andric func(arg); 385f757f3fSDimitry Andric flag = once_flag::_Complete; 395f757f3fSDimitry Andric guard.__complete(); 405f757f3fSDimitry Andric } 415f757f3fSDimitry Andric 425f757f3fSDimitry Andric #else // !_LIBCPP_HAS_NO_THREADS 435f757f3fSDimitry Andric 445f757f3fSDimitry Andric __libcpp_mutex_lock(&mut); 455f757f3fSDimitry Andric while (flag == once_flag::_Pending) 465f757f3fSDimitry Andric __libcpp_condvar_wait(&cv, &mut); 475f757f3fSDimitry Andric if (flag == once_flag::_Unset) { 485f757f3fSDimitry Andric auto guard = std::__make_exception_guard([&flag] { 495f757f3fSDimitry Andric __libcpp_mutex_lock(&mut); 505f757f3fSDimitry Andric __libcpp_relaxed_store(&flag, once_flag::_Unset); 515f757f3fSDimitry Andric __libcpp_mutex_unlock(&mut); 525f757f3fSDimitry Andric __libcpp_condvar_broadcast(&cv); 535f757f3fSDimitry Andric }); 545f757f3fSDimitry Andric 555f757f3fSDimitry Andric __libcpp_relaxed_store(&flag, once_flag::_Pending); 565f757f3fSDimitry Andric __libcpp_mutex_unlock(&mut); 575f757f3fSDimitry Andric func(arg); 585f757f3fSDimitry Andric __libcpp_mutex_lock(&mut); 595f757f3fSDimitry Andric __libcpp_atomic_store(&flag, once_flag::_Complete, _AO_Release); 605f757f3fSDimitry Andric __libcpp_mutex_unlock(&mut); 615f757f3fSDimitry Andric __libcpp_condvar_broadcast(&cv); 625f757f3fSDimitry Andric guard.__complete(); 635f757f3fSDimitry Andric } else { 645f757f3fSDimitry Andric __libcpp_mutex_unlock(&mut); 655f757f3fSDimitry Andric } 665f757f3fSDimitry Andric 675f757f3fSDimitry Andric #endif // !_LIBCPP_HAS_NO_THREADS 685f757f3fSDimitry Andric } 695f757f3fSDimitry Andric 705f757f3fSDimitry Andric _LIBCPP_END_NAMESPACE_STD 71