1// Protocol Buffers - Google's data interchange format 2// Copyright 2008 Google Inc. All rights reserved. 3// http://code.google.com/p/protobuf/ 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 three things: 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 45// or class member variables of this type). 46// * A function GogoleOnceInit(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// 51// This implements a way to perform lazy initialization. It's more efficient 52// than using mutexes as no lock is needed if initialization has already 53// happened. 54// 55// Example usage: 56// void Init(); 57// GOOGLE_PROTOBUF_DECLARE_ONCE(once_init); 58// 59// // Calls Init() exactly once. 60// void InitOnce() { 61// GoogleOnceInit(&once_init, &Init); 62// } 63// 64// Note that if GoogleOnceInit() is called before main() has begun, it must 65// only be called by the thread that will eventually call main() -- that is, 66// the thread that performs dynamic initialization. In general this is a safe 67// assumption since people don't usually construct threads before main() starts, 68// but it is technically not guaranteed. Unfortunately, Win32 provides no way 69// whatsoever to statically-initialize its synchronization primitives, so our 70// only choice is to assume that dynamic initialization is single-threaded. 71 72#ifndef GOOGLE_PROTOBUF_STUBS_ONCE_H__ 73#define GOOGLE_PROTOBUF_STUBS_ONCE_H__ 74 75#include <google/protobuf/stubs/common.h> 76 77#ifndef _WIN32 78#include <pthread.h> 79#endif 80 81namespace google { 82namespace protobuf { 83 84#ifdef _WIN32 85 86struct ProtobufOnceInternal; 87 88struct LIBPROTOBUF_EXPORT ProtobufOnceType { 89 ProtobufOnceType(); 90 ~ProtobufOnceType(); 91 void Init(void (*init_func)()); 92 93 volatile bool initialized_; 94 ProtobufOnceInternal* internal_; 95}; 96 97#define GOOGLE_PROTOBUF_DECLARE_ONCE(NAME) \ 98 ::google::protobuf::ProtobufOnceType NAME 99 100inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()) { 101 // Note: Double-checked locking is safe on x86. 102 if (!once->initialized_) { 103 once->Init(init_func); 104 } 105} 106 107#else 108 109typedef pthread_once_t ProtobufOnceType; 110 111#define GOOGLE_PROTOBUF_DECLARE_ONCE(NAME) \ 112 pthread_once_t NAME = PTHREAD_ONCE_INIT 113 114inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()) { 115 pthread_once(once, init_func); 116} 117 118#endif 119 120} // namespace protobuf 121} // namespace google 122 123#endif // GOOGLE_PROTOBUF_STUBS_ONCE_H__ 124