/Users/deen/code/yugabyte-db/src/yb/gutil/once.h
Line | Count | Source |
1 | | // Copyright 2008 Google Inc. All Rights Reserved. |
2 | | // |
3 | | // The following only applies to changes made to this file as part of YugaByte development. |
4 | | // |
5 | | // Portions Copyright (c) YugaByte, Inc. |
6 | | // |
7 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
8 | | // in compliance with the License. You may obtain a copy of the License at |
9 | | // |
10 | | // http://www.apache.org/licenses/LICENSE-2.0 |
11 | | // |
12 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
13 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
14 | | // or implied. See the License for the specific language governing permissions and limitations |
15 | | // under the License. |
16 | | // |
17 | | // The first call to GoogleOnceInit() with a particular GoogleOnceType |
18 | | // argument will run the specified function. Other calls with the same |
19 | | // argument will not run the function, but will wait for the provided |
20 | | // function to finish running (if it is still running). This provides |
21 | | // a safe, simple, and fast mechanism for one-time initialization in a |
22 | | // multi-threaded process. |
23 | | // |
24 | | // This module is a replacement for pthread_once(). It was added |
25 | | // since some versions of pthread_once() call the supplied function |
26 | | // |
27 | | // Example usage: |
28 | | // static GoogleOnceType once = GOOGLE_ONCE_INIT; |
29 | | // static void Initializer() { |
30 | | // ... do initialization ... |
31 | | // } |
32 | | // ... |
33 | | // void SomeFunction() { |
34 | | // GoogleOnceInit(&once, &Initializer); |
35 | | // ... |
36 | | // } |
37 | | |
38 | | #ifndef BASE_ONCE_H_ |
39 | | #define BASE_ONCE_H_ |
40 | | |
41 | | #include "yb/gutil/atomicops.h" |
42 | | #include "yb/gutil/integral_types.h" |
43 | | #include "yb/gutil/dynamic_annotations.h" |
44 | | #include "yb/gutil/macros.h" |
45 | | #include "yb/gutil/port.h" |
46 | | #include "yb/gutil/type_traits.h" |
47 | | |
48 | | // The following enum values are not for use by clients |
49 | | enum { |
50 | | GOOGLE_ONCE_INTERNAL_INIT = 0, |
51 | | GOOGLE_ONCE_INTERNAL_RUNNING = 0x65C2937B, // an improbable 32-bit value |
52 | | GOOGLE_ONCE_INTERNAL_WAITER = 0x05A308D2, // a different improbable value |
53 | | GOOGLE_ONCE_INTERNAL_DONE = 0x3F2D8AB0, // yet another improbable value |
54 | | }; |
55 | | |
56 | | struct GoogleOnceType { |
57 | | Atomic32 state; |
58 | | }; |
59 | | |
60 | 42.1k | #define GOOGLE_ONCE_INIT { GOOGLE_ONCE_INTERNAL_INIT } |
61 | | |
62 | | // For internal use only. |
63 | | extern void GoogleOnceInternalInit(Atomic32* state, void (*func)(), |
64 | | void (*func_with_arg)(void*), void* arg); |
65 | | |
66 | 214M | inline void GoogleOnceInit(GoogleOnceType* state, void (*func)()) { |
67 | 214M | Atomic32 s = Acquire_Load(&state->state); |
68 | 214M | if (PREDICT_FALSE(s != GOOGLE_ONCE_INTERNAL_DONE)) { |
69 | 131k | GoogleOnceInternalInit(&state->state, func, 0, 0); |
70 | 131k | } |
71 | 214M | ANNOTATE_HAPPENS_AFTER(&state->state); |
72 | 214M | } |
73 | | |
74 | | // A version of GoogleOnceInit where the function argument takes a pointer |
75 | | // of arbitrary type. |
76 | | template<typename T> |
77 | | inline void GoogleOnceInitArg(GoogleOnceType* state, |
78 | | void (*func_with_arg)(T*), T* arg) { |
79 | | Atomic32 s = Acquire_Load(&state->state); |
80 | | if (PREDICT_FALSE(s != GOOGLE_ONCE_INTERNAL_DONE)) { |
81 | | // Deal with const T as well as non-const T. |
82 | | typedef typename base::remove_const<T>::type mutable_T; |
83 | | GoogleOnceInternalInit(&state->state, 0, |
84 | | reinterpret_cast<void(*)(void*)>(func_with_arg), |
85 | | const_cast<mutable_T*>(arg)); |
86 | | } |
87 | | ANNOTATE_HAPPENS_AFTER(&state->state); |
88 | | } |
89 | | |
90 | | // GoogleOnceDynamic is like GoogleOnceType, but is dynamically |
91 | | // initialized instead of statically initialized. This should be used only |
92 | | // when the variable is not of static storage class. |
93 | | // It might be used to delay expensive initialization of part of a |
94 | | // dynamically-allocated data structure until it is known to be needed. For |
95 | | // example: |
96 | | // class MyType { |
97 | | // GoogleOnceDynamic once_; |
98 | | // ComplexStuff* complex_stuff_; |
99 | | // static void InitComplexStuff(MyType* me) { |
100 | | // me->complex_stuff_ = ...; |
101 | | // } |
102 | | // public: |
103 | | // ComplexStuff* complex_stuff() { |
104 | | // this->once_.Init(&InitComplexStuff, this); |
105 | | // return this->complex_stuff_; |
106 | | // } |
107 | | // } |
108 | | class GoogleOnceDynamic { |
109 | | public: |
110 | 3 | GoogleOnceDynamic() : state_(GOOGLE_ONCE_INTERNAL_INIT) { } |
111 | | |
112 | | // If this->Init() has not been called before by any thread, |
113 | | // execute (*func_with_arg)(arg) then return. |
114 | | // Otherwise, wait until that prior invocation has finished |
115 | | // executing its function, then return. |
116 | | template<typename T> |
117 | 9 | void Init(void (*func_with_arg)(T*), T* arg) { |
118 | 9 | Atomic32 s = Acquire_Load(&this->state_); |
119 | 9 | if (PREDICT_FALSE(s != GOOGLE_ONCE_INTERNAL_DONE)) { |
120 | | // Deal with const T as well as non-const T. |
121 | 3 | typedef typename base::remove_const<T>::type mutable_T; |
122 | 3 | GoogleOnceInternalInit(&this->state_, 0, |
123 | 3 | reinterpret_cast<void (*)(void*)>(func_with_arg), |
124 | 3 | const_cast<mutable_T*>(arg)); |
125 | 3 | } |
126 | 9 | ANNOTATE_HAPPENS_AFTER(&this->state_); |
127 | 9 | } |
128 | | private: |
129 | | Atomic32 state_; |
130 | | DISALLOW_COPY_AND_ASSIGN(GoogleOnceDynamic); |
131 | | }; |
132 | | |
133 | | #endif // BASE_ONCE_H_ |