- File:
-
- 1 edited
-
libcfa/src/concurrency/locks.hfa (modified) (9 diffs)
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/concurrency/locks.hfa
r7f958c4 r2ed32fa7 101 101 102 102 //----------------------------------------------------------------------------- 103 // MCS Spin Lock 104 // - No recursive acquisition 105 // - Needs to be released by owner 106 107 struct mcs_spin_node { 108 mcs_spin_node * volatile next; 109 volatile bool locked; 110 }; 111 112 struct mcs_spin_queue { 113 mcs_spin_node * volatile tail; 114 }; 115 116 static inline void ?{}(mcs_spin_node & this) { this.next = 0p; this.locked = true; } 117 118 static inline mcs_spin_node * volatile & ?`next ( mcs_spin_node * node ) { 119 return node->next; 120 } 121 122 struct mcs_spin_lock { 123 mcs_spin_queue queue; 124 }; 125 126 static inline void lock(mcs_spin_lock & l, mcs_spin_node & n) { 127 mcs_spin_node * prev = __atomic_exchange_n(&l.queue.tail, &n, __ATOMIC_SEQ_CST); 128 n.locked = true; 129 if(prev == 0p) return; 130 prev->next = &n; 131 while(__atomic_load_n(&n.locked, __ATOMIC_RELAXED)) Pause(); 132 } 133 134 static inline void unlock(mcs_spin_lock & l, mcs_spin_node & n) { 135 mcs_spin_node * n_ptr = &n; 136 if (__atomic_compare_exchange_n(&l.queue.tail, &n_ptr, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) return; 137 while (__atomic_load_n(&n.next, __ATOMIC_RELAXED) == 0p) {} 138 n.next->locked = false; 139 } 140 141 //----------------------------------------------------------------------------- 142 // CLH Spinlock 143 // - No recursive acquisition 144 // - Needs to be released by owner 145 146 struct clh_lock { 147 volatile bool * volatile tail; 148 }; 149 150 static inline void ?{}( clh_lock & this ) { this.tail = malloc(); *this.tail = true; } 151 static inline void ^?{}( clh_lock & this ) { free(this.tail); } 152 153 static inline void lock(clh_lock & l) { 154 thread$ * curr_thd = active_thread(); 155 *(curr_thd->clh_node) = false; 156 volatile bool * prev = __atomic_exchange_n((bool **)(&l.tail), (bool *)(curr_thd->clh_node), __ATOMIC_SEQ_CST); 157 while(!__atomic_load_n(prev, __ATOMIC_ACQUIRE)) Pause(); 158 curr_thd->clh_prev = prev; 159 } 160 161 static inline void unlock(clh_lock & l) { 162 thread$ * curr_thd = active_thread(); 163 __atomic_store_n(curr_thd->clh_node, true, __ATOMIC_RELEASE); 164 curr_thd->clh_node = curr_thd->clh_prev; 165 } 166 167 //----------------------------------------------------------------------------- 103 168 // Linear backoff Spinlock 104 169 struct linear_backoff_then_block_lock { … … 205 270 // Fast Block Lock 206 271 207 // High efficiencyminimal blocking lock272 // minimal blocking lock 208 273 // - No reacquire for cond var 209 274 // - No recursive acquisition 210 275 // - No ownership 211 276 struct fast_block_lock { 277 // List of blocked threads 278 dlist( thread$ ) blocked_threads; 279 212 280 // Spin lock used for mutual exclusion 213 281 __spinlock_t lock; 214 282 215 // List of blocked threads 216 dlist( thread$ ) blocked_threads; 217 283 // flag showing if lock is held 218 284 bool held:1; 285 286 #ifdef __CFA_DEBUG__ 287 // for deadlock detection 288 struct thread$ * owner; 289 #endif 219 290 }; 220 291 … … 231 302 static inline void lock(fast_block_lock & this) with(this) { 232 303 lock( lock __cfaabi_dbg_ctx2 ); 304 305 #ifdef __CFA_DEBUG__ 306 assert(!(held && owner == active_thread())); 307 #endif 233 308 if (held) { 234 309 insert_last( blocked_threads, *active_thread() ); … … 238 313 } 239 314 held = true; 315 #ifdef __CFA_DEBUG__ 316 owner = active_thread(); 317 #endif 240 318 unlock( lock ); 241 319 } … … 246 324 thread$ * t = &try_pop_front( blocked_threads ); 247 325 held = ( t ? true : false ); 326 #ifdef __CFA_DEBUG__ 327 owner = ( t ? t : 0p ); 328 #endif 248 329 unpark( t ); 249 330 unlock( lock ); … … 253 334 static inline size_t on_wait(fast_block_lock & this) { unlock(this); return 0; } 254 335 static inline void on_wakeup(fast_block_lock & this, size_t recursion ) { } 336 337 //----------------------------------------------------------------------------- 338 // simple_owner_lock 339 340 // pthread owner lock 341 // - reacquire for cond var 342 // - recursive acquisition 343 // - ownership 344 struct simple_owner_lock { 345 // List of blocked threads 346 dlist( thread$ ) blocked_threads; 347 348 // Spin lock used for mutual exclusion 349 __spinlock_t lock; 350 351 // owner showing if lock is held 352 struct thread$ * owner; 353 354 size_t recursion_count; 355 }; 356 357 static inline void ?{}( simple_owner_lock & this ) with(this) { 358 lock{}; 359 blocked_threads{}; 360 owner = 0p; 361 recursion_count = 0; 362 } 363 static inline void ^?{}( simple_owner_lock & this ) {} 364 static inline void ?{}( simple_owner_lock & this, simple_owner_lock this2 ) = void; 365 static inline void ?=?( simple_owner_lock & this, simple_owner_lock this2 ) = void; 366 367 static inline void lock(simple_owner_lock & this) with(this) { 368 if (owner == active_thread()) { 369 recursion_count++; 370 return; 371 } 372 lock( lock __cfaabi_dbg_ctx2 ); 373 374 if (owner != 0p) { 375 insert_last( blocked_threads, *active_thread() ); 376 unlock( lock ); 377 park( ); 378 return; 379 } 380 owner = active_thread(); 381 recursion_count = 1; 382 unlock( lock ); 383 } 384 385 // TODO: fix duplicate def issue and bring this back 386 // void pop_and_set_new_owner( simple_owner_lock & this ) with( this ) { 387 // thread$ * t = &try_pop_front( blocked_threads ); 388 // owner = t; 389 // recursion_count = ( t ? 1 : 0 ); 390 // unpark( t ); 391 // } 392 393 static inline void unlock(simple_owner_lock & this) with(this) { 394 lock( lock __cfaabi_dbg_ctx2 ); 395 /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this ); 396 /* paranoid */ verifyf( owner == active_thread(), "Thread %p other than the owner %p attempted to release owner lock %p", owner, active_thread(), &this ); 397 // if recursion count is zero release lock and set new owner if one is waiting 398 recursion_count--; 399 if ( recursion_count == 0 ) { 400 // pop_and_set_new_owner( this ); 401 thread$ * t = &try_pop_front( blocked_threads ); 402 owner = t; 403 recursion_count = ( t ? 1 : 0 ); 404 unpark( t ); 405 } 406 unlock( lock ); 407 } 408 409 static inline void on_notify(simple_owner_lock & this, struct thread$ * t ) with(this) { 410 lock( lock __cfaabi_dbg_ctx2 ); 411 // lock held 412 if ( owner != 0p ) { 413 insert_last( blocked_threads, *t ); 414 unlock( lock ); 415 } 416 // lock not held 417 else { 418 owner = t; 419 recursion_count = 1; 420 unpark( t ); 421 unlock( lock ); 422 } 423 } 424 425 static inline size_t on_wait(simple_owner_lock & this) with(this) { 426 lock( lock __cfaabi_dbg_ctx2 ); 427 /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this ); 428 /* paranoid */ verifyf( owner == active_thread(), "Thread %p other than the owner %p attempted to release owner lock %p", owner, active_thread(), &this ); 429 430 size_t ret = recursion_count; 431 432 // pop_and_set_new_owner( this ); 433 434 thread$ * t = &try_pop_front( blocked_threads ); 435 owner = t; 436 recursion_count = ( t ? 1 : 0 ); 437 unpark( t ); 438 439 unlock( lock ); 440 return ret; 441 } 442 443 static inline void on_wakeup(simple_owner_lock & this, size_t recursion ) with(this) { recursion_count = recursion; } 444 445 //----------------------------------------------------------------------------- 446 // Spin Queue Lock 447 448 // - No reacquire for cond var 449 // - No recursive acquisition 450 // - No ownership 451 // - spin lock with no locking/atomics in unlock 452 struct spin_queue_lock { 453 // Spin lock used for mutual exclusion 454 mcs_spin_lock lock; 455 456 // flag showing if lock is held 457 volatile bool held; 458 459 #ifdef __CFA_DEBUG__ 460 // for deadlock detection 461 struct thread$ * owner; 462 #endif 463 }; 464 465 static inline void ?{}( spin_queue_lock & this ) with(this) { 466 lock{}; 467 held = false; 468 } 469 static inline void ^?{}( spin_queue_lock & this ) {} 470 static inline void ?{}( spin_queue_lock & this, spin_queue_lock this2 ) = void; 471 static inline void ?=?( spin_queue_lock & this, spin_queue_lock this2 ) = void; 472 473 // if this is called recursively IT WILL DEADLOCK!!!!! 474 static inline void lock(spin_queue_lock & this) with(this) { 475 mcs_spin_node node; 476 #ifdef __CFA_DEBUG__ 477 assert(!(held && owner == active_thread())); 478 #endif 479 lock( lock, node ); 480 while(__atomic_load_n(&held, __ATOMIC_SEQ_CST)) Pause(); 481 __atomic_store_n(&held, true, __ATOMIC_SEQ_CST); 482 unlock( lock, node ); 483 #ifdef __CFA_DEBUG__ 484 owner = active_thread(); 485 #endif 486 } 487 488 static inline void unlock(spin_queue_lock & this) with(this) { 489 #ifdef __CFA_DEBUG__ 490 owner = 0p; 491 #endif 492 __atomic_store_n(&held, false, __ATOMIC_RELEASE); 493 } 494 495 static inline void on_notify(spin_queue_lock & this, struct thread$ * t ) { unpark(t); } 496 static inline size_t on_wait(spin_queue_lock & this) { unlock(this); return 0; } 497 static inline void on_wakeup(spin_queue_lock & this, size_t recursion ) { } 498 499 500 //----------------------------------------------------------------------------- 501 // MCS Block Spin Lock 502 503 // - No reacquire for cond var 504 // - No recursive acquisition 505 // - No ownership 506 // - Blocks but first node spins (like spin queue but blocking for not first thd) 507 struct mcs_block_spin_lock { 508 // Spin lock used for mutual exclusion 509 mcs_lock lock; 510 511 // flag showing if lock is held 512 volatile bool held; 513 514 #ifdef __CFA_DEBUG__ 515 // for deadlock detection 516 struct thread$ * owner; 517 #endif 518 }; 519 520 static inline void ?{}( mcs_block_spin_lock & this ) with(this) { 521 lock{}; 522 held = false; 523 } 524 static inline void ^?{}( mcs_block_spin_lock & this ) {} 525 static inline void ?{}( mcs_block_spin_lock & this, mcs_block_spin_lock this2 ) = void; 526 static inline void ?=?( mcs_block_spin_lock & this, mcs_block_spin_lock this2 ) = void; 527 528 // if this is called recursively IT WILL DEADLOCK!!!!! 529 static inline void lock(mcs_block_spin_lock & this) with(this) { 530 mcs_node node; 531 #ifdef __CFA_DEBUG__ 532 assert(!(held && owner == active_thread())); 533 #endif 534 lock( lock, node ); 535 while(held) Pause(); 536 held = true; 537 unlock( lock, node ); 538 #ifdef __CFA_DEBUG__ 539 owner = active_thread(); 540 #endif 541 } 542 543 static inline void unlock(mcs_block_spin_lock & this) with(this) { 544 #ifdef __CFA_DEBUG__ 545 owner = 0p; 546 #endif 547 held = false; 548 } 549 550 static inline void on_notify(mcs_block_spin_lock & this, struct thread$ * t ) { unpark(t); } 551 static inline size_t on_wait(mcs_block_spin_lock & this) { unlock(this); return 0; } 552 static inline void on_wakeup(mcs_block_spin_lock & this, size_t recursion ) { } 553 554 //----------------------------------------------------------------------------- 555 // Block Spin Lock 556 557 // - No reacquire for cond var 558 // - No recursive acquisition 559 // - No ownership 560 // - Blocks but first node spins (like spin queue but blocking for not first thd) 561 struct block_spin_lock { 562 // Spin lock used for mutual exclusion 563 fast_block_lock lock; 564 565 // flag showing if lock is held 566 volatile bool held; 567 568 #ifdef __CFA_DEBUG__ 569 // for deadlock detection 570 struct thread$ * owner; 571 #endif 572 }; 573 574 static inline void ?{}( block_spin_lock & this ) with(this) { 575 lock{}; 576 held = false; 577 } 578 static inline void ^?{}( block_spin_lock & this ) {} 579 static inline void ?{}( block_spin_lock & this, block_spin_lock this2 ) = void; 580 static inline void ?=?( block_spin_lock & this, block_spin_lock this2 ) = void; 581 582 // if this is called recursively IT WILL DEADLOCK!!!!! 583 static inline void lock(block_spin_lock & this) with(this) { 584 #ifdef __CFA_DEBUG__ 585 assert(!(held && owner == active_thread())); 586 #endif 587 lock( lock ); 588 while(held) Pause(); 589 held = true; 590 unlock( lock ); 591 #ifdef __CFA_DEBUG__ 592 owner = active_thread(); 593 #endif 594 } 595 596 static inline void unlock(block_spin_lock & this) with(this) { 597 #ifdef __CFA_DEBUG__ 598 owner = 0p; 599 #endif 600 held = false; 601 } 602 603 static inline void on_notify(block_spin_lock & this, struct thread$ * t ) { unpark(t); } 604 static inline size_t on_wait(block_spin_lock & this) { unlock(this); return 0; } 605 static inline void on_wakeup(block_spin_lock & this, size_t recursion ) { } 255 606 256 607 //----------------------------------------------------------------------------- … … 332 683 // - signalling without holding branded lock is UNSAFE! 333 684 // - only allows usage of one lock, cond var is branded after usage 685 334 686 struct fast_cond_var { 335 687 // List of blocked threads 336 688 dlist( info_thread(L) ) blocked_threads; 337 338 689 #ifdef __CFA_DEBUG__ 339 690 L * lock_used; … … 341 692 }; 342 693 343 344 694 void ?{}( fast_cond_var(L) & this ); 345 695 void ^?{}( fast_cond_var(L) & this ); … … 349 699 350 700 uintptr_t front( fast_cond_var(L) & this ); 351 352 701 bool empty ( fast_cond_var(L) & this ); 353 702 354 703 void wait( fast_cond_var(L) & this, L & l ); 355 704 void wait( fast_cond_var(L) & this, L & l, uintptr_t info ); 356 } 705 706 707 //----------------------------------------------------------------------------- 708 // pthread_cond_var 709 // 710 // - cond var with minimal footprint 711 // - supports operations needed for phthread cond 712 713 struct pthread_cond_var { 714 dlist( info_thread(L) ) blocked_threads; 715 __spinlock_t lock; 716 }; 717 718 void ?{}( pthread_cond_var(L) & this ); 719 void ^?{}( pthread_cond_var(L) & this ); 720 721 bool notify_one( pthread_cond_var(L) & this ); 722 bool notify_all( pthread_cond_var(L) & this ); 723 724 uintptr_t front( pthread_cond_var(L) & this ); 725 bool empty ( pthread_cond_var(L) & this ); 726 727 void wait( pthread_cond_var(L) & this, L & l ); 728 void wait( pthread_cond_var(L) & this, L & l, uintptr_t info ); 729 bool wait( pthread_cond_var(L) & this, L & l, timespec t ); 730 bool wait( pthread_cond_var(L) & this, L & l, uintptr_t info, timespec t ); 731 }
Note:
See TracChangeset
for help on using the changeset viewer.