/* Copyright (c) 2008-2010, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // This file is part of ThreadSanitizer, a dynamic data race detector. // Author: Konstantin Serebryany. #ifndef TS_LOCK_H_ #define TS_LOCK_H_ #include "ts_util.h" #if (DEBUG > 0) && (TS_SERIALIZED == 0) && defined (TS_LLVM) && !defined(DYNAMIC_ANNOTATIONS_ENABLED) # define DYNAMIC_ANNOTATIONS_ENABLED 1 #endif #include "dynamic_annotations.h" //--------- Simple Lock ------------------ {{{1 #if defined(TS_VALGRIND) || defined(TS_OFFLINE) class TSLock { public: void Lock() {}; void Unlock() {}; void AssertHeld() {}; }; #else class TSLock { public: TSLock(); ~TSLock(); void Lock(); void Unlock(); void AssertHeld(); private: struct Rep; Rep *rep_; }; #endif class ScopedLock { public: ScopedLock(TSLock *lock) : lock_(lock) { lock_->Lock(); } ~ScopedLock() { lock_->Unlock(); } private: TSLock *lock_; }; //--------- Atomic operations {{{1 #if TS_SERIALIZED == 1 // No need for atomics when all ThreadSanitizer logic is serialized. ALWAYS_INLINE uintptr_t AtomicExchange(uintptr_t *ptr, uintptr_t new_value) { uintptr_t old_value = *ptr; *ptr = new_value; return old_value; } ALWAYS_INLINE void ReleaseStore(uintptr_t *ptr, uintptr_t value) { *ptr = value; } ALWAYS_INLINE int32_t NoBarrier_AtomicIncrement(int32_t* ptr) { return *ptr += 1; } ALWAYS_INLINE int32_t NoBarrier_AtomicDecrement(int32_t* ptr) { return *ptr -= 1; } #elif defined(__GNUC__) ALWAYS_INLINE uintptr_t AtomicExchange(uintptr_t *ptr, uintptr_t new_value) { return __sync_lock_test_and_set(ptr, new_value); } ALWAYS_INLINE void ReleaseStore(uintptr_t *ptr, uintptr_t value) { __asm__ __volatile__("" : : : "memory"); *(volatile uintptr_t*)ptr = value; } ALWAYS_INLINE int32_t NoBarrier_AtomicIncrement(int32_t* ptr) { return __sync_add_and_fetch(ptr, 1); } ALWAYS_INLINE int32_t NoBarrier_AtomicDecrement(int32_t* ptr) { return __sync_sub_and_fetch(ptr, 1); } #elif defined(_MSC_VER) uintptr_t AtomicExchange(uintptr_t *ptr, uintptr_t new_value); void ReleaseStore(uintptr_t *ptr, uintptr_t value); int32_t NoBarrier_AtomicIncrement(int32_t* ptr); int32_t NoBarrier_AtomicDecrement(int32_t* ptr); #else # error "unsupported configuration" #endif ALWAYS_INLINE int32_t AtomicIncrementRefcount(int32_t *refcount) { return NoBarrier_AtomicIncrement(refcount); } ALWAYS_INLINE int32_t AtomicDecrementRefcount(int32_t *refcount) { ANNOTATE_HAPPENS_BEFORE(refcount); int32_t res = NoBarrier_AtomicDecrement(refcount); if (res == 0) { ANNOTATE_HAPPENS_AFTER(refcount); } return res; } // end. {{{1 #endif // TS_LOCK_H_ // vim:shiftwidth=2:softtabstop=2:expandtab:tw=80