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#include "src/base/atomicops.h"
14
15namespace v8 {
16namespace base {
17
18void CallOnceImpl(OnceType* once, PointerArgFunction init_func, void* arg) {
19  AtomicWord state = Acquire_Load(once);
20  // Fast path. The provided function was already executed.
21  if (state == ONCE_STATE_DONE) {
22    return;
23  }
24
25  // The function execution did not complete yet. The once object can be in one
26  // of the two following states:
27  //   - UNINITIALIZED: We are the first thread calling this function.
28  //   - EXECUTING_FUNCTION: Another thread is already executing the function.
29  //
30  // First, try to change the state from UNINITIALIZED to EXECUTING_FUNCTION
31  // atomically.
32  state = Acquire_CompareAndSwap(
33      once, ONCE_STATE_UNINITIALIZED, ONCE_STATE_EXECUTING_FUNCTION);
34  if (state == ONCE_STATE_UNINITIALIZED) {
35    // We are the first thread to call this function, so we have to call the
36    // function.
37    init_func(arg);
38    Release_Store(once, ONCE_STATE_DONE);
39  } else {
40    // Another thread has already started executing the function. We need to
41    // wait until it completes the initialization.
42    while (state == ONCE_STATE_EXECUTING_FUNCTION) {
43#ifdef _WIN32
44      ::Sleep(0);
45#else
46      sched_yield();
47#endif
48      state = Acquire_Load(once);
49    }
50  }
51}
52
53} }  // namespace v8::base
54