1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/base/once.h" 6 7 #ifdef _WIN32 8 #include <windows.h> 9 #else 10 #include <sched.h> 11 #endif 12 13 namespace v8 { 14 namespace base { 15 CallOnceImpl(OnceType * once,std::function<void ()> init_func)16void CallOnceImpl(OnceType* once, std::function<void()> init_func) { 17 // Fast path. The provided function was already executed. 18 if (once->load(std::memory_order_acquire) == ONCE_STATE_DONE) { 19 return; 20 } 21 22 // The function execution did not complete yet. The once object can be in one 23 // of the two following states: 24 // - UNINITIALIZED: We are the first thread calling this function. 25 // - EXECUTING_FUNCTION: Another thread is already executing the function. 26 // 27 // First, try to change the state from UNINITIALIZED to EXECUTING_FUNCTION 28 // atomically. 29 uint8_t expected = ONCE_STATE_UNINITIALIZED; 30 if (once->compare_exchange_strong(expected, ONCE_STATE_EXECUTING_FUNCTION, 31 std::memory_order_acq_rel)) { 32 // We are the first thread to call this function, so we have to call the 33 // function. 34 init_func(); 35 once->store(ONCE_STATE_DONE, std::memory_order_release); 36 } else { 37 // Another thread has already started executing the function. We need to 38 // wait until it completes the initialization. 39 while (once->load(std::memory_order_acquire) == 40 ONCE_STATE_EXECUTING_FUNCTION) { 41 #ifdef _WIN32 42 ::Sleep(0); 43 #else 44 sched_yield(); 45 #endif 46 } 47 } 48 } 49 50 } // namespace base 51 } // namespace v8 52