Line data Source code
1 : // Protocol Buffers - Google's data interchange format
2 : // Copyright 2008 Google Inc. All rights reserved.
3 : // https://developers.google.com/protocol-buffers/
4 : //
5 : // Redistribution and use in source and binary forms, with or without
6 : // modification, are permitted provided that the following conditions are
7 : // met:
8 : //
9 : // * Redistributions of source code must retain the above copyright
10 : // notice, this list of conditions and the following disclaimer.
11 : // * Redistributions in binary form must reproduce the above
12 : // copyright notice, this list of conditions and the following disclaimer
13 : // in the documentation and/or other materials provided with the
14 : // distribution.
15 : // * Neither the name of Google Inc. nor the names of its
16 : // contributors may be used to endorse or promote products derived from
17 : // this software without specific prior written permission.
18 : //
19 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 : // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 : // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 : // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 : // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 : // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 : // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 : // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 : // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 : // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 :
31 : // Author: kenton@google.com (Kenton Varda)
32 : //
33 : // emulates google3/base/once.h
34 : //
35 : // This header is intended to be included only by internal .cc files and
36 : // generated .pb.cc files. Users should not use this directly.
37 : //
38 : // This is basically a portable version of pthread_once().
39 : //
40 : // This header declares:
41 : // * A type called ProtobufOnceType.
42 : // * A macro GOOGLE_PROTOBUF_DECLARE_ONCE() which declares a variable of type
43 : // ProtobufOnceType. This is the only legal way to declare such a variable.
44 : // The macro may only be used at the global scope (you cannot create local or
45 : // class member variables of this type).
46 : // * A function GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()).
47 : // This function, when invoked multiple times given the same ProtobufOnceType
48 : // object, will invoke init_func on the first call only, and will make sure
49 : // none of the calls return before that first call to init_func has finished.
50 : // * The user can provide a parameter which GoogleOnceInit() forwards to the
51 : // user-provided function when it is called. Usage example:
52 : // int a = 10;
53 : // GoogleOnceInit(&my_once, &MyFunctionExpectingIntArgument, &a);
54 : // * This implementation guarantees that ProtobufOnceType is a POD (i.e. no
55 : // static initializer generated).
56 : //
57 : // This implements a way to perform lazy initialization. It's more efficient
58 : // than using mutexes as no lock is needed if initialization has already
59 : // happened.
60 : //
61 : // Example usage:
62 : // void Init();
63 : // GOOGLE_PROTOBUF_DECLARE_ONCE(once_init);
64 : //
65 : // // Calls Init() exactly once.
66 : // void InitOnce() {
67 : // GoogleOnceInit(&once_init, &Init);
68 : // }
69 : //
70 : // Note that if GoogleOnceInit() is called before main() has begun, it must
71 : // only be called by the thread that will eventually call main() -- that is,
72 : // the thread that performs dynamic initialization. In general this is a safe
73 : // assumption since people don't usually construct threads before main() starts,
74 : // but it is technically not guaranteed. Unfortunately, Win32 provides no way
75 : // whatsoever to statically-initialize its synchronization primitives, so our
76 : // only choice is to assume that dynamic initialization is single-threaded.
77 :
78 : #ifndef GOOGLE_PROTOBUF_STUBS_ONCE_H__
79 : #define GOOGLE_PROTOBUF_STUBS_ONCE_H__
80 :
81 : #include <google/protobuf/stubs/atomicops.h>
82 : #include <google/protobuf/stubs/common.h>
83 :
84 : namespace google {
85 : namespace protobuf {
86 :
87 : #ifdef GOOGLE_PROTOBUF_NO_THREAD_SAFETY
88 :
89 : typedef bool ProtobufOnceType;
90 :
91 : #define GOOGLE_PROTOBUF_ONCE_INIT false
92 :
93 : inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()) {
94 : if (!*once) {
95 : *once = true;
96 : init_func();
97 : }
98 : }
99 :
100 : template <typename Arg>
101 : inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)(Arg),
102 : Arg arg) {
103 : if (!*once) {
104 : *once = true;
105 : init_func(arg);
106 : }
107 : }
108 :
109 : #else
110 :
111 : enum {
112 : ONCE_STATE_UNINITIALIZED = 0,
113 : ONCE_STATE_EXECUTING_CLOSURE = 1,
114 : ONCE_STATE_DONE = 2
115 : };
116 :
117 : typedef internal::AtomicWord ProtobufOnceType;
118 :
119 : #define GOOGLE_PROTOBUF_ONCE_INIT ::google::protobuf::ONCE_STATE_UNINITIALIZED
120 :
121 : LIBPROTOBUF_EXPORT
122 : void GoogleOnceInitImpl(ProtobufOnceType* once, Closure* closure);
123 :
124 684 : inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()) {
125 684 : if (internal::Acquire_Load(once) != ONCE_STATE_DONE) {
126 24 : internal::FunctionClosure0 func(init_func, false);
127 12 : GoogleOnceInitImpl(once, &func);
128 : }
129 684 : }
130 :
131 : template <typename Arg>
132 0 : inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)(Arg*),
133 : Arg* arg) {
134 0 : if (internal::Acquire_Load(once) != ONCE_STATE_DONE) {
135 0 : internal::FunctionClosure1<Arg*> func(init_func, false, arg);
136 0 : GoogleOnceInitImpl(once, &func);
137 : }
138 0 : }
139 :
140 : #endif // GOOGLE_PROTOBUF_NO_THREAD_SAFETY
141 :
142 : class GoogleOnceDynamic {
143 : public:
144 3 : GoogleOnceDynamic() : state_(GOOGLE_PROTOBUF_ONCE_INIT) { }
145 :
146 : // If this->Init() has not been called before by any thread,
147 : // execute (*func_with_arg)(arg) then return.
148 : // Otherwise, wait until that prior invocation has finished
149 : // executing its function, then return.
150 : template<typename T>
151 0 : void Init(void (*func_with_arg)(T*), T* arg) {
152 0 : GoogleOnceInit<T>(&this->state_,
153 : func_with_arg,
154 : arg);
155 0 : }
156 : private:
157 : ProtobufOnceType state_;
158 : };
159 :
160 : #define GOOGLE_PROTOBUF_DECLARE_ONCE(NAME) \
161 : ::google::protobuf::ProtobufOnceType NAME = GOOGLE_PROTOBUF_ONCE_INIT
162 :
163 : } // namespace protobuf
164 : } // namespace google
165 :
166 : #endif // GOOGLE_PROTOBUF_STUBS_ONCE_H__
|