Line data Source code
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 : // emulates google3/base/once.h
6 : //
7 : // This header is intended to be included only by v8's internal code. Users
8 : // should not use this directly.
9 : //
10 : // This is basically a portable version of pthread_once().
11 : //
12 : // This header declares:
13 : // * A type called OnceType.
14 : // * A macro V8_DECLARE_ONCE() which declares a (global) variable of type
15 : // OnceType.
16 : // * A function CallOnce(OnceType* once, void (*init_func)()).
17 : // This function, when invoked multiple times given the same OnceType object,
18 : // will invoke init_func on the first call only, and will make sure none of
19 : // the calls return before that first call to init_func has finished.
20 : //
21 : // Additionally, the following features are supported:
22 : // * A macro V8_ONCE_INIT which is expanded into the expression used to
23 : // initialize a OnceType. This is only useful when clients embed a OnceType
24 : // into a structure of their own and want to initialize it statically.
25 : // * The user can provide a parameter which CallOnce() forwards to the
26 : // user-provided function when it is called. Usage example:
27 : // CallOnce(&my_once, &MyFunctionExpectingIntArgument, 10);
28 : // * This implementation guarantees that OnceType is a POD (i.e. no static
29 : // initializer generated).
30 : //
31 : // This implements a way to perform lazy initialization. It's more efficient
32 : // than using mutexes as no lock is needed if initialization has already
33 : // happened.
34 : //
35 : // Example usage:
36 : // void Init();
37 : // V8_DECLARE_ONCE(once_init);
38 : //
39 : // // Calls Init() exactly once.
40 : // void InitOnce() {
41 : // CallOnce(&once_init, &Init);
42 : // }
43 : //
44 : // Note that if CallOnce() is called before main() has begun, it must
45 : // only be called by the thread that will eventually call main() -- that is,
46 : // the thread that performs dynamic initialization. In general this is a safe
47 : // assumption since people don't usually construct threads before main() starts,
48 : // but it is technically not guaranteed. Unfortunately, Win32 provides no way
49 : // whatsoever to statically-initialize its synchronization primitives, so our
50 : // only choice is to assume that dynamic initialization is single-threaded.
51 :
52 : #ifndef V8_BASE_ONCE_H_
53 : #define V8_BASE_ONCE_H_
54 :
55 : #include <stddef.h>
56 : #include <functional>
57 :
58 : #include "src/base/atomicops.h"
59 : #include "src/base/base-export.h"
60 :
61 : namespace v8 {
62 : namespace base {
63 :
64 : typedef AtomicWord OnceType;
65 :
66 : #define V8_ONCE_INIT 0
67 :
68 : #define V8_DECLARE_ONCE(NAME) ::v8::base::OnceType NAME
69 :
70 : enum {
71 : ONCE_STATE_UNINITIALIZED = 0,
72 : ONCE_STATE_EXECUTING_FUNCTION = 1,
73 : ONCE_STATE_DONE = 2
74 : };
75 :
76 : typedef void (*NoArgFunction)();
77 : typedef void (*PointerArgFunction)(void* arg);
78 :
79 : template <typename T>
80 : struct OneArgFunction {
81 : typedef void (*type)(T);
82 : };
83 :
84 : V8_BASE_EXPORT void CallOnceImpl(OnceType* once,
85 : std::function<void()> init_func);
86 :
87 116260 : inline void CallOnce(OnceType* once, NoArgFunction init_func) {
88 116260 : if (Acquire_Load(once) != ONCE_STATE_DONE) {
89 146325 : CallOnceImpl(once, init_func);
90 : }
91 116323 : }
92 :
93 :
94 : template <typename Arg>
95 41602487 : inline void CallOnce(OnceType* once,
96 : typename OneArgFunction<Arg*>::type init_func, Arg* arg) {
97 41602487 : if (Acquire_Load(once) != ONCE_STATE_DONE) {
98 1378299 : CallOnceImpl(once, [=]() { init_func(arg); });
99 : }
100 41602487 : }
101 :
102 : } // namespace base
103 : } // namespace v8
104 :
105 : #endif // V8_BASE_ONCE_H_
|