blob: c81e87131f7222194e2309869c9e4537e2764eff [file] [log] [blame]
// Copyright 2008 Google Inc. All Rights Reserved.
//
// The first call to GoogleOnceInit() with a particular GoogleOnceType
// argument will run the specified function. Other calls with the same
// argument will not run the function, but will wait for the provided
// function to finish running (if it is still running). This provides
// a safe, simple, and fast mechanism for one-time initialization in a
// multi-threaded process.
//
// This module is a replacement for pthread_once(). It was added
// since some versions of pthread_once() call the supplied function
//
// Example usage:
// static GoogleOnceType once = GOOGLE_ONCE_INIT;
// static void Initializer() {
// ... do initialization ...
// }
// ...
// void SomeFunction() {
// GoogleOnceInit(&once, &Initializer);
// ...
// }
#ifndef BASE_ONCE_H_
#define BASE_ONCE_H_
#include "gutil/atomicops.h"
#include "gutil/integral_types.h"
#include "gutil/dynamic_annotations.h"
#include "gutil/macros.h"
#include "gutil/port.h"
#include "gutil/type_traits.h"
// The following enum values are not for use by clients
enum {
GOOGLE_ONCE_INTERNAL_INIT = 0,
GOOGLE_ONCE_INTERNAL_RUNNING = 0x65C2937B, // an improbable 32-bit value
GOOGLE_ONCE_INTERNAL_WAITER = 0x05A308D2, // a different improbable value
GOOGLE_ONCE_INTERNAL_DONE = 0x3F2D8AB0, // yet another improbable value
};
struct GoogleOnceType {
Atomic32 state;
};
#define GOOGLE_ONCE_INIT { GOOGLE_ONCE_INTERNAL_INIT }
// For internal use only.
extern void GoogleOnceInternalInit(Atomic32* state, void (*func)(),
void (*func_with_arg)(void*), void* arg);
inline void GoogleOnceInit(GoogleOnceType* state, void (*func)()) {
Atomic32 s = Acquire_Load(&state->state);
if (PREDICT_FALSE(s != GOOGLE_ONCE_INTERNAL_DONE)) {
GoogleOnceInternalInit(&state->state, func, 0, 0);
}
ANNOTATE_HAPPENS_AFTER(&state->state);
}
// A version of GoogleOnceInit where the function argument takes a pointer
// of arbitrary type.
template<typename T>
inline void GoogleOnceInitArg(GoogleOnceType* state,
void (*func_with_arg)(T*), T* arg) {
Atomic32 s = Acquire_Load(&state->state);
if (PREDICT_FALSE(s != GOOGLE_ONCE_INTERNAL_DONE)) {
// Deal with const T as well as non-const T.
typedef typename base::remove_const<T>::type mutable_T;
GoogleOnceInternalInit(&state->state, 0,
reinterpret_cast<void(*)(void*)>(func_with_arg),
const_cast<mutable_T*>(arg));
}
ANNOTATE_HAPPENS_AFTER(&state->state);
}
// GoogleOnceDynamic is like GoogleOnceType, but is dynamically
// initialized instead of statically initialized. This should be used only
// when the variable is not of static storage class.
// It might be used to delay expensive initialization of part of a
// dynamically-allocated data structure until it is known to be needed. For
// example:
// class MyType {
// GoogleOnceDynamic once_;
// ComplexStuff* complex_stuff_;
// static void InitComplexStuff(MyType* me) {
// me->complex_stuff_ = ...;
// }
// public:
// ComplexStuff* complex_stuff() {
// this->once_.Init(&InitComplexStuff, this);
// return this->complex_stuff_;
// }
// }
class GoogleOnceDynamic {
public:
GoogleOnceDynamic() : state_(GOOGLE_ONCE_INTERNAL_INIT) { }
// If this->Init() has not been called before by any thread,
// execute (*func_with_arg)(arg) then return.
// Otherwise, wait until that prior invocation has finished
// executing its function, then return.
template<typename T>
void Init(void (*func_with_arg)(T*), T* arg) {
Atomic32 s = Acquire_Load(&this->state_);
if (PREDICT_FALSE(s != GOOGLE_ONCE_INTERNAL_DONE)) {
// Deal with const T as well as non-const T.
typedef typename base::remove_const<T>::type mutable_T;
GoogleOnceInternalInit(&this->state_, 0,
reinterpret_cast<void (*)(void*)>(func_with_arg),
const_cast<mutable_T*>(arg));
}
ANNOTATE_HAPPENS_AFTER(&this->state_);
}
private:
Atomic32 state_;
DISALLOW_COPY_AND_ASSIGN(GoogleOnceDynamic);
};
#endif // BASE_ONCE_H_