Changeset 5a46e09 for libcfa/src
- Timestamp:
- Jun 29, 2021, 5:33:38 PM (3 years ago)
- Branches:
- ADT, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- 660665f
- Parents:
- bae0d35
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/concurrency/locks.hfa
rbae0d35 r5a46e09 18 18 19 19 #include <stdbool.h> 20 #include <stdio.h> 20 21 21 22 #include "bits/weakso_locks.hfa" … … 237 238 } 238 239 240 struct linear_backoff_then_block_lock { 241 // Spin lock used for mutual exclusion 242 __spinlock_t spinlock; 243 244 // Current thread owning the lock 245 struct $thread * owner; 246 247 // List of blocked threads 248 dlist( $thread ) blocked_threads; 249 250 // Used for comparing and exchanging 251 volatile size_t lock_value; 252 253 // used for linear backoff spinning 254 int spin_start; 255 int spin_end; 256 int spin_count; 257 258 // after unsuccessful linear backoff yield this many times 259 int yield_count; 260 }; 261 262 static inline void ?{}( linear_backoff_then_block_lock & this, int spin_start, int spin_end, int spin_count, int yield_count ) { 263 this.spinlock{}; 264 this.blocked_threads{}; 265 this.lock_value = 0; 266 this.spin_start = spin_start; 267 this.spin_end = spin_end; 268 this.spin_count = spin_count; 269 this.yield_count = yield_count; 270 } 271 static inline void ?{}( linear_backoff_then_block_lock & this ) { this{4, 1024, 16, 0}; } 272 static inline void ^?{}( linear_backoff_then_block_lock & this ) {} 273 274 static inline bool internal_try_lock(linear_backoff_then_block_lock & this, size_t & compare_val) with(this) { 275 if (__atomic_compare_exchange_n(&lock_value, &compare_val, 1, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) { 276 owner = active_thread(); 277 return true; 278 } 279 return false; 280 } 281 282 static inline bool try_lock(linear_backoff_then_block_lock & this) { size_t compare_val = 0; return internal_try_lock(this, compare_val); } 283 284 static inline bool try_lock_contention(linear_backoff_then_block_lock & this) with(this) { 285 if (__atomic_exchange_n(&lock_value, 2, __ATOMIC_ACQUIRE) == 0) { 286 owner = active_thread(); 287 return true; 288 } 289 return false; 290 } 291 292 static inline bool block(linear_backoff_then_block_lock & this) with(this) { 293 lock( spinlock __cfaabi_dbg_ctx2 ); 294 if (lock_value != 2) { 295 unlock( spinlock ); 296 return true; 297 } 298 insert_last( blocked_threads, *active_thread() ); 299 unlock( spinlock ); 300 park( ); 301 return true; 302 } 303 304 static inline bool lock(linear_backoff_then_block_lock & this) with(this) { 305 // if owner just return 306 if (active_thread() == owner) return true; 307 size_t compare_val = 0; 308 int spin = spin_start; 309 // linear backoff 310 for( ;; ) { 311 compare_val = 0; 312 if (internal_try_lock(this, compare_val)) return true; 313 if (2 == compare_val) break; 314 for (int i = 0; i < spin; i++) Pause(); 315 if (spin >= spin_end) break; 316 spin += spin; 317 } 318 319 // linear backoff bounded by spin_count 320 spin = spin_start; 321 int spin_counter = 0; 322 int yield_counter = 0; 323 for ( ;; ) { 324 if(try_lock_contention(this)) return true; 325 if(spin_counter < spin_count) { 326 for (int i = 0; i < spin; i++) Pause(); 327 if (spin < spin_end) spin += spin; 328 else spin_counter++; 329 } else if (yield_counter < yield_count) { 330 // after linear backoff yield yield_count times 331 yield_counter++; 332 yield(); 333 } else { break; } 334 } 335 336 // block until signalled 337 while (block(this)) if(try_lock_contention(this)) return true; 338 339 // this should never be reached as block(this) always returns true 340 return false; 341 } 342 343 static inline void unlock(linear_backoff_then_block_lock & this) with(this) { 344 verify(lock_value > 0); 345 owner = 0p; 346 if (__atomic_exchange_n(&lock_value, 0, __ATOMIC_RELEASE) == 1) return; 347 lock( spinlock __cfaabi_dbg_ctx2 ); 348 $thread * t = &try_pop_front( blocked_threads ); 349 unlock( spinlock ); 350 unpark( t ); 351 } 352 353 354 void on_notify(linear_backoff_then_block_lock & this, struct $thread * t ) { unpark(t); } 355 size_t on_wait(linear_backoff_then_block_lock & this) { unlock(this); return 0; } 356 void on_wakeup(linear_backoff_then_block_lock & this, size_t recursion ) { lock(this); } 357 239 358 //----------------------------------------------------------------------------- 240 359 // is_blocking_lock
Note: See TracChangeset
for help on using the changeset viewer.