00001 /* Copyright (c) 2006, Google Inc. 00002 * All rights reserved. 00003 * 00004 * Redistribution and use in source and binary forms, with or without 00005 * modification, are permitted provided that the following conditions are 00006 * met: 00007 * 00008 * * Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * * Redistributions in binary form must reproduce the above 00011 * copyright notice, this list of conditions and the following disclaimer 00012 * in the documentation and/or other materials provided with the 00013 * distribution. 00014 * * Neither the name of Google Inc. nor the names of its 00015 * contributors may be used to endorse or promote products derived from 00016 * this software without specific prior written permission. 00017 * 00018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00019 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00020 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 00021 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 00022 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00023 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00024 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00025 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00026 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 00028 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00029 * 00030 * --- 00031 * Author: Sanjay Ghemawat 00032 */ 00033 00034 // 00035 // Fast spinlocks (at least on x86, a lock/unlock pair is approximately 00036 // half the cost of a Mutex because the unlock just does a store instead 00037 // of a compare-and-swap which is expensive). 00038 00039 // Spinlock is async signal safe. 00040 // If used within a signal handler, all lock holders 00041 // should block the signal even outside the signal handler. 00042 00043 #ifndef BASE_SPINLOCK_H__ 00044 #define BASE_SPINLOCK_H__ 00045 00046 #include "config.h" 00047 #include "base/basictypes.h" 00048 #include "base/atomicops.h" 00049 00050 class SpinLock { 00051 public: 00052 SpinLock() : lockword_(0) { } 00053 00054 // Special constructor for use with static SpinLock objects. E.g., 00055 // 00056 // static SpinLock lock(SpinLock::LINKER_INITIALIZED); 00057 // 00058 // When intialized using this constructor, we depend on the fact 00059 // that the linker has already initialized the memory appropriately. 00060 // A SpinLock constructed like this can be freely used from global 00061 // initializers without worrying about the order in which global 00062 // initializers run. 00063 enum StaticInitializer { LINKER_INITIALIZED }; 00064 explicit SpinLock(StaticInitializer x) { 00065 // Does nothing; lockword_ is already initialized 00066 } 00067 00068 inline void Lock() { 00069 if (Acquire_CompareAndSwap(&lockword_, 0, 1) != 0) { 00070 SlowLock(); 00071 } 00072 } 00073 00074 inline void Unlock() { 00075 Release_Store(&lockword_, 0); 00076 } 00077 00078 // Report if we think the lock can be held by this thread. 00079 // When the lock is truly held by the invoking thread 00080 // we will always return true. 00081 // Indended to be used as CHECK(lock.IsHeld()); 00082 inline bool IsHeld() const { 00083 return lockword_ != 0; 00084 } 00085 00086 private: 00087 // Lock-state: 0 means unlocked, 1 means locked 00088 volatile AtomicWord lockword_; 00089 00090 void SlowLock(); 00091 00092 DISALLOW_EVIL_CONSTRUCTORS(SpinLock); 00093 }; 00094 00095 // Corresponding locker object that arranges to acquire a spinlock for 00096 // the duration of a C++ scope. 00097 class SpinLockHolder { 00098 private: 00099 SpinLock* lock_; 00100 public: 00101 inline explicit SpinLockHolder(SpinLock* l) : lock_(l) { l->Lock(); } 00102 inline ~SpinLockHolder() { lock_->Unlock(); } 00103 }; 00104 // Catch bug where variable name is omitted, e.g. SpinLockHolder (&lock); 00105 #define SpinLockHolder(x) COMPILE_ASSERT(0, spin_lock_decl_missing_var_name) 00106 00107 00108 #endif // BASE_SPINLOCK_H__