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)
42class TSLock {
43 public:
44  void Lock() {};
45  void Unlock() {};
46  void AssertHeld() {};
47};
48#else
49class 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
62class 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.
76ALWAYS_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
82ALWAYS_INLINE void ReleaseStore(uintptr_t *ptr, uintptr_t value) {
83  *ptr = value;
84}
85
86ALWAYS_INLINE int32_t NoBarrier_AtomicIncrement(int32_t* ptr) {
87  return *ptr += 1;
88}
89
90ALWAYS_INLINE int32_t NoBarrier_AtomicDecrement(int32_t* ptr) {
91  return *ptr -= 1;
92}
93
94#elif defined(__GNUC__)
95
96ALWAYS_INLINE uintptr_t AtomicExchange(uintptr_t *ptr, uintptr_t new_value) {
97  return __sync_lock_test_and_set(ptr, new_value);
98}
99
100ALWAYS_INLINE void ReleaseStore(uintptr_t *ptr, uintptr_t value) {
101  __asm__ __volatile__("" : : : "memory");
102  *(volatile uintptr_t*)ptr = value;
103}
104
105ALWAYS_INLINE int32_t NoBarrier_AtomicIncrement(int32_t* ptr) {
106  return __sync_add_and_fetch(ptr, 1);
107}
108
109ALWAYS_INLINE int32_t NoBarrier_AtomicDecrement(int32_t* ptr) {
110  return __sync_sub_and_fetch(ptr, 1);
111}
112
113#elif defined(_MSC_VER)
114uintptr_t AtomicExchange(uintptr_t *ptr, uintptr_t new_value);
115void ReleaseStore(uintptr_t *ptr, uintptr_t value);
116int32_t NoBarrier_AtomicIncrement(int32_t* ptr);
117int32_t NoBarrier_AtomicDecrement(int32_t* ptr);
118
119#else
120# error "unsupported configuration"
121#endif
122
123
124ALWAYS_INLINE int32_t AtomicIncrementRefcount(int32_t *refcount) {
125  return NoBarrier_AtomicIncrement(refcount);
126}
127
128ALWAYS_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