Changeset f4ec5e45 for libcfa/src
- Timestamp:
- Mar 26, 2021, 5:59:26 PM (3 years ago)
- Branches:
- ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- c51124b
- Parents:
- d3314ae
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/concurrency/locks.hfa
rd3314ae rf4ec5e45 20 20 21 21 #include "bits/weakso_locks.hfa" 22 #include "containers/queueLockFree.hfa" 23 24 #include "thread.hfa" 22 25 23 26 #include "time_t.hfa" 24 27 #include "time.hfa" 28 29 //----------------------------------------------------------------------------- 30 // Semaphores 31 32 // '0-nary' semaphore 33 // Similar to a counting semaphore except the value of one is never reached 34 // as a consequence, a V() that would bring the value to 1 *spins* until 35 // a P consumes it 36 struct Semaphore0nary { 37 __spinlock_t lock; // needed to protect 38 mpsc_queue($thread) queue; 39 }; 40 41 static inline bool P(Semaphore0nary & this, $thread * thrd) __attribute__((artificial)); 42 static inline bool P(Semaphore0nary & this, $thread * thrd) { 43 /* paranoid */ verify(!(thrd->seqable.next)); 44 /* paranoid */ verify(!(thrd`next)); 45 46 push(this.queue, thrd); 47 return true; 48 } 49 50 static inline bool P(Semaphore0nary & this) __attribute__((artificial)); 51 static inline bool P(Semaphore0nary & this) { 52 $thread * thrd = active_thread(); 53 P(this, thrd); 54 park(); 55 return true; 56 } 57 58 static inline $thread * V(Semaphore0nary & this, const bool doUnpark = true) __attribute__((artificial)); 59 static inline $thread * V(Semaphore0nary & this, const bool doUnpark = true) { 60 $thread * next; 61 lock(this.lock __cfaabi_dbg_ctx2); 62 for (;;) { 63 next = pop(this.queue); 64 if (next) break; 65 Pause(); 66 } 67 unlock(this.lock); 68 69 if (doUnpark) unpark(next); 70 return next; 71 } 72 73 // Wrapper used on top of any sempahore to avoid potential locking 74 struct BinaryBenaphore { 75 volatile ssize_t counter; 76 }; 77 78 static inline { 79 void ?{}(BinaryBenaphore & this) { this.counter = 0; } 80 void ?{}(BinaryBenaphore & this, zero_t) { this.counter = 0; } 81 void ?{}(BinaryBenaphore & this, one_t ) { this.counter = 1; } 82 83 // returns true if no blocking needed 84 bool P(BinaryBenaphore & this) { return __atomic_fetch_sub(&this.counter, 1, __ATOMIC_SEQ_CST) > 0; } 85 bool tryP(BinaryBenaphore & this) { 86 ssize_t c = this.counter; 87 return (c >= 1) && __atomic_compare_exchange_n(&this.counter, &c, c-1, false, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED); 88 } 89 90 // returns true if notify needed 91 bool V(BinaryBenaphore & this) { 92 ssize_t c = 0; 93 for () { 94 if (__atomic_compare_exchange_n(&this.counter, &c, c+1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) { 95 if (c == 0) return true; 96 /* paranoid */ verify(c < 0); 97 return false; 98 } else { 99 if (c == 1) return true; 100 /* paranoid */ verify(c < 1); 101 Pause(); 102 } 103 } 104 } 105 } 106 107 // Binary Semaphore based on the BinaryBenaphore on top of the 0-nary Semaphore 108 struct ThreadBenaphore { 109 BinaryBenaphore ben; 110 Semaphore0nary sem; 111 }; 112 113 static inline void ?{}(ThreadBenaphore & this) {} 114 static inline void ?{}(ThreadBenaphore & this, zero_t) { (this.ben){ 0 }; } 115 static inline void ?{}(ThreadBenaphore & this, one_t ) { (this.ben){ 1 }; } 116 117 static inline bool P(ThreadBenaphore & this) { return /* P(this.ben) ? false : */ P(this.sem); } 118 static inline bool P(ThreadBenaphore & this, $thread * t) { return /* P(this.ben) ? false : */ P(this.sem, t ); } 119 static inline bool tryP(ThreadBenaphore & this) { return tryP(this.ben); } 120 static inline bool P(ThreadBenaphore & this, bool wait) { return wait ? P(this) : tryP(this); } 121 122 static inline $thread * V(ThreadBenaphore & this, const bool doUnpark = true) { 123 // if (V(this.ben)) return 0p; 124 return V(this.sem, doUnpark); 125 } 126 127 //----------------------------------------------------------------------------- 128 // Semaphore 129 struct semaphore { 130 __spinlock_t lock; 131 int count; 132 __queue_t($thread) waiting; 133 }; 134 135 void ?{}(semaphore & this, int count = 1); 136 void ^?{}(semaphore & this); 137 bool P (semaphore & this); 138 bool V (semaphore & this); 139 bool V (semaphore & this, unsigned count); 25 140 26 141 //---------- … … 54 169 static inline size_t get_recursion_count( owner_lock & this ) { return get_recursion_count( (blocking_lock &)this ); } 55 170 171 struct fast_lock { 172 $thread * volatile owner; 173 ThreadBenaphore sem; 174 }; 175 176 static inline bool $try_lock(fast_lock & this, $thread * thrd) { 177 $thread * exp = 0p; 178 return __atomic_compare_exchange_n(&this.owner, &exp, thrd, false, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED); 179 } 180 181 static inline void $lock(fast_lock & this, $thread * thrd) { 182 /* paranoid */verify(thrd != this.owner); 183 184 for (;;) { 185 if ($try_lock(this, thrd)) return; 186 P(this.sem, thrd); 187 } 188 } 189 190 static inline void lock( fast_lock & this ) { 191 $thread * thrd = active_thread(); 192 /* paranoid */verify(thrd != this.owner); 193 194 for (;;) { 195 if ($try_lock(this, thrd)) return; 196 P(this.sem); 197 } 198 } 199 200 static inline void try_lock ( fast_lock & this ) { 201 $thread * thrd = active_thread(); 202 /* paranoid */ verify(thrd != this.owner); 203 return $try_lock(this, thrd); 204 } 205 206 static inline void unlock( fast_lock & this ) { 207 $thread * thrd = active_thread(); 208 /* paranoid */ verify(thrd == this.owner); 209 $thread * next = V(this.sem, false); // implicit fence 210 // open 'owner' only after fence 211 this.owner = 0p; 212 213 // Unpark the next person (can be 0p, unpark handles it) 214 unpark(next); 215 } 216 217 static inline void on_wait( fast_lock & this ) { 218 unlock(this); 219 #warning this is broken 220 } 221 222 static inline void on_notify( fast_lock & this, struct $thread * t ) { 223 $lock(this, t); 224 #warning this is broken 225 } 226 227 static inline void set_recursion_count( fast_lock & this, size_t recursion ) {} 228 static inline size_t get_recursion_count( fast_lock & this ) { return 0; } 229 230 struct mcs_node { 231 mcs_node * volatile next; 232 single_sem sem; 233 }; 234 235 void ?{}(mcs_node & this) { this.next = 0p; } 236 237 static inline mcs_node * volatile & ?`next ( mcs_node * node ) { 238 return node->next; 239 } 240 241 struct mcs_lock { 242 mcs_queue(mcs_node) queue; 243 }; 244 245 static inline void lock(mcs_lock & l, mcs_node & n) { 246 if(push(l.queue, &n)) 247 wait(n.sem); 248 } 249 250 static inline void unlock(mcs_lock & l, mcs_node & n) { 251 mcs_node * next = advance(l.queue, &n); 252 if(next) post(next->sem); 253 } 254 56 255 //----------------------------------------------------------------------------- 57 256 // is_blocking_lock … … 121 320 bool wait( condition_variable(L) & this, L & l, uintptr_t info, Time time ); 122 321 } 123 124 //-----------------------------------------------------------------------------125 // Semaphore126 struct semaphore {127 __spinlock_t lock;128 int count;129 __queue_t($thread) waiting;130 };131 132 void ?{}(semaphore & this, int count = 1);133 void ^?{}(semaphore & this);134 bool P (semaphore & this);135 bool V (semaphore & this);136 bool V (semaphore & this, unsigned count);
Note: See TracChangeset
for help on using the changeset viewer.