Home | History | Annotate | Download | only in tsan
      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