Galois
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
PtrLock.h
Go to the documentation of this file.
1 /*
2  * This file belongs to the Galois project, a C++ library for exploiting
3  * parallelism. The code is being released under the terms of the 3-Clause BSD
4  * License (a copy is located in LICENSE.txt at the top-level directory).
5  *
6  * Copyright (C) 2018, The University of Texas at Austin. All rights reserved.
7  * UNIVERSITY EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES CONCERNING THIS
8  * SOFTWARE AND DOCUMENTATION, INCLUDING ANY WARRANTIES OF MERCHANTABILITY,
9  * FITNESS FOR ANY PARTICULAR PURPOSE, NON-INFRINGEMENT AND WARRANTIES OF
10  * PERFORMANCE, AND ANY WARRANTY THAT MIGHT OTHERWISE ARISE FROM COURSE OF
11  * DEALING OR USAGE OF TRADE. NO WARRANTY IS EITHER EXPRESS OR IMPLIED WITH
12  * RESPECT TO THE USE OF THE SOFTWARE OR DOCUMENTATION. Under no circumstances
13  * shall University be liable for incidental, special, indirect, direct or
14  * consequential damages or loss of profits, interruption of business, or
15  * related expenses which may arise from use of Software or Documentation,
16  * including but not limited to those resulting from defects in Software and/or
17  * Documentation, or loss or inaccuracy of data of any kind.
18  */
19 
20 #ifndef GALOIS_SUBSTRATE_PTRLOCK_H
21 #define GALOIS_SUBSTRATE_PTRLOCK_H
22 
23 #include <cstdint>
24 #include <cassert>
25 #include <atomic>
26 
27 #include "galois/config.h"
29 
30 namespace galois {
31 namespace substrate {
32 
33 namespace internal {
34 void ptr_slow_lock(std::atomic<uintptr_t>& l);
35 }
36 
40 
41 template <typename T>
42 class PtrLock {
43  std::atomic<uintptr_t> _lock;
44 
45  // static_assert(alignof(T) > 1, "Bad data type alignment for PtrLock");
46 
47 public:
48  constexpr PtrLock() : _lock(0) {}
49  // relaxed order for copy
50  PtrLock(const PtrLock& p) : _lock(p._lock.load(std::memory_order_relaxed)) {}
51 
52  PtrLock& operator=(const PtrLock& p) {
53  if (&p == this)
54  return *this;
55  // relaxed order for initialization
56  _lock.store(p._lock.load(std::memory_order_relaxed),
57  std::memory_order_relaxed);
58  return *this;
59  }
60 
61  inline void lock() {
62  uintptr_t oldval = _lock.load(std::memory_order_relaxed);
63  if (oldval & 1)
64  goto slow_path;
65  if (!_lock.compare_exchange_weak(oldval, oldval | 1,
66  std::memory_order_acq_rel,
67  std::memory_order_relaxed))
68  goto slow_path;
69  assert(is_locked());
70  return;
71 
72  slow_path:
73  internal::ptr_slow_lock(_lock);
74  }
75 
76  inline void unlock() {
77  assert(is_locked());
78  _lock.store(_lock.load(std::memory_order_relaxed) & ~(uintptr_t)1,
79  std::memory_order_release);
80  }
81 
82  inline void unlock_and_clear() {
83  assert(is_locked());
84  _lock.store(0, std::memory_order_release);
85  }
86 
87  inline void unlock_and_set(T* val) {
88  assert(is_locked());
89  assert(!((uintptr_t)val & 1));
90  _lock.store((uintptr_t)val, std::memory_order_release);
91  }
92 
93  inline T* getValue() const {
94  return (T*)(_lock.load(std::memory_order_relaxed) & ~(uintptr_t)1);
95  }
96 
97  inline void setValue(T* val) {
98  uintptr_t nval = (uintptr_t)val;
99  nval |= (_lock & 1);
100  // relaxed OK since this doesn't clear lock
101  _lock.store(nval, std::memory_order_relaxed);
102  }
103 
104  inline bool try_lock() {
105  uintptr_t oldval = _lock.load(std::memory_order_relaxed);
106  if ((oldval & 1) != 0)
107  return false;
108  oldval = _lock.fetch_or(1, std::memory_order_acq_rel);
109  return !(oldval & 1);
110  }
111 
112  inline bool is_locked() const {
113  return _lock.load(std::memory_order_acquire) & 1;
114  }
115 
118  inline bool CAS(T* oldval, T* newval) {
119  assert(!((uintptr_t)oldval & 1) && !((uintptr_t)newval & 1));
120  uintptr_t old = (uintptr_t)oldval;
121  return _lock.compare_exchange_strong(old, (uintptr_t)newval);
122  }
123 
126  inline bool stealing_CAS(T* oldval, T* newval) {
127  uintptr_t old = 1 | (uintptr_t)oldval;
128  return _lock.compare_exchange_strong(old, 1 | (uintptr_t)newval);
129  }
130 };
131 
132 template <typename T>
134  T* _lock;
135 
136 public:
137  DummyPtrLock() : _lock() {}
138 
139  inline void lock() {}
140  inline void unlock() {}
141  inline void unlock_and_clear() { _lock = 0; }
142  inline void unlock_and_set(T* val) { _lock = val; }
143  inline T* getValue() const { return _lock; }
144  inline void setValue(T* val) { _lock = val; }
145  inline bool try_lock() const { return true; }
146  inline bool is_locked() const { return false; }
147  inline bool CAS(T* oldval, T* newval) {
148  if (_lock == oldval) {
149  _lock = newval;
150  return true;
151  }
152  return false;
153  }
154  inline bool stealing_CAS(T* oldval, T* newval) { return CAS(oldval, newval); }
155 };
156 
157 } // end namespace substrate
158 } // end namespace galois
159 
160 #endif
PtrLock & operator=(const PtrLock &p)
Definition: PtrLock.h:52
bool CAS(T *oldval, T *newval)
Definition: PtrLock.h:147
PtrLock is a spinlock and a pointer.
Definition: PtrLock.h:42
T * getValue() const
Definition: PtrLock.h:93
void setValue(T *val)
Definition: PtrLock.h:144
void unlock_and_clear()
Definition: PtrLock.h:141
constexpr PtrLock()
Definition: PtrLock.h:48
void unlock_and_set(T *val)
Definition: PtrLock.h:87
bool CAS(T *oldval, T *newval)
CAS only works on unlocked values the lock bit will prevent a successful cas.
Definition: PtrLock.h:118
void setValue(T *val)
Definition: PtrLock.h:97
DummyPtrLock()
Definition: PtrLock.h:137
bool stealing_CAS(T *oldval, T *newval)
CAS that works on locked values; this can be very dangerous when used incorrectly.
Definition: PtrLock.h:126
void lock()
Definition: PtrLock.h:139
T * getValue() const
Definition: PtrLock.h:143
void unlock_and_clear()
Definition: PtrLock.h:82
bool is_locked() const
Definition: PtrLock.h:112
void lock()
Definition: PtrLock.h:61
void unlock()
Definition: PtrLock.h:76
bool is_locked() const
Definition: PtrLock.h:146
Definition: PtrLock.h:133
void unlock_and_set(T *val)
Definition: PtrLock.h:142
PtrLock(const PtrLock &p)
Definition: PtrLock.h:50
bool try_lock()
Definition: PtrLock.h:104
void unlock()
Definition: PtrLock.h:140
bool stealing_CAS(T *oldval, T *newval)
Definition: PtrLock.h:154
bool try_lock() const
Definition: PtrLock.h:145