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 :
57 : #include "src/base/atomicops.h"
58 : #include "src/base/base-export.h"
59 :
60 : namespace v8 {
61 : namespace base {
62 :
63 : typedef AtomicWord OnceType;
64 :
65 : #define V8_ONCE_INIT 0
66 :
67 : #define V8_DECLARE_ONCE(NAME) ::v8::base::OnceType NAME
68 :
69 : enum {
70 : ONCE_STATE_UNINITIALIZED = 0,
71 : ONCE_STATE_EXECUTING_FUNCTION = 1,
72 : ONCE_STATE_DONE = 2
73 : };
74 :
75 : typedef void (*NoArgFunction)();
76 : typedef void (*PointerArgFunction)(void* arg);
77 :
78 : template <typename T>
79 : struct OneArgFunction {
80 : typedef void (*type)(T);
81 : };
82 :
83 : V8_BASE_EXPORT void CallOnceImpl(OnceType* once, PointerArgFunction init_func,
84 : void* arg);
85 :
86 2351885 : inline void CallOnce(OnceType* once, NoArgFunction init_func) {
87 2351885 : if (Acquire_Load(once) != ONCE_STATE_DONE) {
88 134845 : CallOnceImpl(once, reinterpret_cast<PointerArgFunction>(init_func), NULL);
89 : }
90 2351885 : }
91 :
92 :
93 : template <typename Arg>
94 127374435 : inline void CallOnce(OnceType* once,
95 : typename OneArgFunction<Arg*>::type init_func, Arg* arg) {
96 127374435 : if (Acquire_Load(once) != ONCE_STATE_DONE) {
97 647994 : CallOnceImpl(once, reinterpret_cast<PointerArgFunction>(init_func),
98 : static_cast<void*>(arg));
99 : }
100 127374458 : }
101 :
102 : } // namespace base
103 : } // namespace v8
104 :
105 : #endif // V8_BASE_ONCE_H_
|