1 /* Copyright (c) 2008-2010, Google Inc. 2 * All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Neither the name of Google Inc. nor the names of its 11 * contributors may be used to endorse or promote products derived from 12 * this software without specific prior written permission. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 18 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 // This file is part of ThreadSanitizer, a dynamic data race detector. 28 // Author: Konstantin Serebryany. 29 30 #ifndef TS_LOCK_H_ 31 #define TS_LOCK_H_ 32 33 #include "ts_util.h" 34 35 #if (DEBUG > 0) && (TS_SERIALIZED == 0) && defined (TS_LLVM) && !defined(DYNAMIC_ANNOTATIONS_ENABLED) 36 # define DYNAMIC_ANNOTATIONS_ENABLED 1 37 #endif 38 #include "dynamic_annotations.h" 39 40 //--------- Simple Lock ------------------ {{{1 41 #if defined(TS_VALGRIND) || defined(TS_OFFLINE) 42 class TSLock { 43 public: 44 void Lock() {}; 45 void Unlock() {}; 46 void AssertHeld() {}; 47 }; 48 #else 49 class TSLock { 50 public: 51 TSLock(); 52 ~TSLock(); 53 void Lock(); 54 void Unlock(); 55 void AssertHeld(); 56 private: 57 struct Rep; 58 Rep *rep_; 59 }; 60 #endif 61 62 class ScopedLock { 63 public: 64 ScopedLock(TSLock *lock) 65 : lock_(lock) { 66 lock_->Lock(); 67 } 68 ~ScopedLock() { lock_->Unlock(); } 69 private: 70 TSLock *lock_; 71 }; 72 73 //--------- Atomic operations {{{1 74 #if TS_SERIALIZED == 1 75 // No need for atomics when all ThreadSanitizer logic is serialized. 76 ALWAYS_INLINE uintptr_t AtomicExchange(uintptr_t *ptr, uintptr_t new_value) { 77 uintptr_t old_value = *ptr; 78 *ptr = new_value; 79 return old_value; 80 } 81 82 ALWAYS_INLINE void ReleaseStore(uintptr_t *ptr, uintptr_t value) { 83 *ptr = value; 84 } 85 86 ALWAYS_INLINE int32_t NoBarrier_AtomicIncrement(int32_t* ptr) { 87 return *ptr += 1; 88 } 89 90 ALWAYS_INLINE int32_t NoBarrier_AtomicDecrement(int32_t* ptr) { 91 return *ptr -= 1; 92 } 93 94 #elif defined(__GNUC__) 95 96 ALWAYS_INLINE uintptr_t AtomicExchange(uintptr_t *ptr, uintptr_t new_value) { 97 return __sync_lock_test_and_set(ptr, new_value); 98 } 99 100 ALWAYS_INLINE void ReleaseStore(uintptr_t *ptr, uintptr_t value) { 101 __asm__ __volatile__("" : : : "memory"); 102 *(volatile uintptr_t*)ptr = value; 103 } 104 105 ALWAYS_INLINE int32_t NoBarrier_AtomicIncrement(int32_t* ptr) { 106 return __sync_add_and_fetch(ptr, 1); 107 } 108 109 ALWAYS_INLINE int32_t NoBarrier_AtomicDecrement(int32_t* ptr) { 110 return __sync_sub_and_fetch(ptr, 1); 111 } 112 113 #elif defined(_MSC_VER) 114 uintptr_t AtomicExchange(uintptr_t *ptr, uintptr_t new_value); 115 void ReleaseStore(uintptr_t *ptr, uintptr_t value); 116 int32_t NoBarrier_AtomicIncrement(int32_t* ptr); 117 int32_t NoBarrier_AtomicDecrement(int32_t* ptr); 118 119 #else 120 # error "unsupported configuration" 121 #endif 122 123 124 ALWAYS_INLINE int32_t AtomicIncrementRefcount(int32_t *refcount) { 125 return NoBarrier_AtomicIncrement(refcount); 126 } 127 128 ALWAYS_INLINE int32_t AtomicDecrementRefcount(int32_t *refcount) { 129 ANNOTATE_HAPPENS_BEFORE(refcount); 130 int32_t res = NoBarrier_AtomicDecrement(refcount); 131 if (res == 0) { 132 ANNOTATE_HAPPENS_AFTER(refcount); 133 } 134 return res; 135 } 136 137 138 139 // end. {{{1 140 #endif // TS_LOCK_H_ 141 // vim:shiftwidth=2:softtabstop=2:expandtab:tw=80 142