YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/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_