- File:
-
- 1 edited
-
libcfa/src/concurrency/locks.hfa (modified) (32 diffs)
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/concurrency/locks.hfa
rbeeff61e rbd72c284 30 30 #include "time.hfa" 31 31 32 #include "select.hfa"33 34 32 #include <fstream.hfa> 35 33 … … 72 70 static inline void on_wakeup( single_acquisition_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); } 73 71 static inline void on_notify( single_acquisition_lock & this, struct thread$ * t ) { on_notify( (blocking_lock &)this, t ); } 74 static inline bool register_select( single_acquisition_lock & this, select_node & node ) { return register_select( (blocking_lock &)this, node ); }75 static inline bool unregister_select( single_acquisition_lock & this, select_node & node ) { return unregister_select( (blocking_lock &)this, node ); }76 static inline bool on_selected( single_acquisition_lock & this, select_node & node ) { return on_selected( (blocking_lock &)this, node ); }77 72 78 73 //---------- … … 89 84 static inline void on_wakeup( owner_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); } 90 85 static inline void on_notify( owner_lock & this, struct thread$ * t ) { on_notify( (blocking_lock &)this, t ); } 91 static inline bool register_select( owner_lock & this, select_node & node ) { return register_select( (blocking_lock &)this, node ); }92 static inline bool unregister_select( owner_lock & this, select_node & node ) { return unregister_select( (blocking_lock &)this, node ); }93 static inline bool on_selected( owner_lock & this, select_node & node ) { return on_selected( (blocking_lock &)this, node ); }94 86 95 87 //----------------------------------------------------------------------------- … … 188 180 189 181 // if this is called recursively IT WILL DEADLOCK!!!!! 190 static inline void lock( futex_mutex & this) with(this) {182 static inline void lock(futex_mutex & this) with(this) { 191 183 int state; 192 184 … … 198 190 for (int i = 0; i < spin; i++) Pause(); 199 191 } 192 193 // // no contention try to acquire 194 // if (internal_try_lock(this, state)) return; 200 195 201 196 // if not in contended state, set to be in contended state … … 218 213 219 214 static inline void on_notify( futex_mutex & f, thread$ * t){ unpark(t); } 220 static inline size_t on_wait( futex_mutex & f ) { unlock(f); park(); return 0;}215 static inline size_t on_wait( futex_mutex & f ) {unlock(f); return 0;} 221 216 222 217 // to set recursion count after getting signalled; … … 249 244 250 245 // if this is called recursively IT WILL DEADLOCK!!!!! 251 static inline void lock( go_mutex & this ) with( this) {246 static inline void lock(go_mutex & this) with(this) { 252 247 int state, init_state; 253 248 … … 260 255 while( !val ) { // lock unlocked 261 256 state = 0; 262 if ( internal_try_lock( this, state, init_state )) return;257 if (internal_try_lock(this, state, init_state)) return; 263 258 } 264 259 for (int i = 0; i < 30; i++) Pause(); … … 267 262 while( !val ) { // lock unlocked 268 263 state = 0; 269 if ( internal_try_lock( this, state, init_state )) return;264 if (internal_try_lock(this, state, init_state)) return; 270 265 } 271 266 sched_yield(); 272 267 273 268 // if not in contended state, set to be in contended state 274 state = internal_exchange( this, 2);269 state = internal_exchange(this, 2); 275 270 if ( !state ) return; // state == 0 276 271 init_state = 2; 277 futex( (int*)&val, FUTEX_WAIT, 2); // if val is not 2 this returns with EWOULDBLOCK272 futex((int*)&val, FUTEX_WAIT, 2); // if val is not 2 this returns with EWOULDBLOCK 278 273 } 279 274 } … … 281 276 static inline void unlock( go_mutex & this ) with(this) { 282 277 // if uncontended do atomic unlock and then return 283 if ( __atomic_exchange_n(&val, 0, __ATOMIC_RELEASE) == 1) return;278 if (__atomic_exchange_n(&val, 0, __ATOMIC_RELEASE) == 1) return; 284 279 285 280 // otherwise threads are blocked so we must wake one 286 futex( (int *)&val, FUTEX_WAKE, 1);287 } 288 289 static inline void on_notify( go_mutex & f, thread$ * t){ unpark( t); }290 static inline size_t on_wait( go_mutex & f ) { unlock( f ); park(); return 0;}281 futex((int *)&val, FUTEX_WAKE, 1); 282 } 283 284 static inline void on_notify( go_mutex & f, thread$ * t){ unpark(t); } 285 static inline size_t on_wait( go_mutex & f ) {unlock(f); return 0;} 291 286 static inline void on_wakeup( go_mutex & f, size_t recursion ) {} 287 288 //----------------------------------------------------------------------------- 289 // CLH Spinlock 290 // - No recursive acquisition 291 // - Needs to be released by owner 292 293 struct clh_lock { 294 volatile bool * volatile tail; 295 volatile bool * volatile head; 296 }; 297 298 static inline void ?{}( clh_lock & this ) { this.tail = malloc(); *this.tail = true; } 299 static inline void ^?{}( clh_lock & this ) { free(this.tail); } 300 301 static inline void lock(clh_lock & l) { 302 thread$ * curr_thd = active_thread(); 303 *(curr_thd->clh_node) = false; 304 volatile bool * prev = __atomic_exchange_n((bool **)(&l.tail), (bool *)(curr_thd->clh_node), __ATOMIC_SEQ_CST); 305 while(!__atomic_load_n(prev, __ATOMIC_SEQ_CST)) Pause(); 306 __atomic_store_n((bool **)(&l.head), (bool *)curr_thd->clh_node, __ATOMIC_SEQ_CST); 307 curr_thd->clh_node = prev; 308 } 309 310 static inline void unlock(clh_lock & l) { 311 __atomic_store_n((bool *)(l.head), true, __ATOMIC_SEQ_CST); 312 } 313 314 static inline void on_notify(clh_lock & this, struct thread$ * t ) { unpark(t); } 315 static inline size_t on_wait(clh_lock & this) { unlock(this); return 0; } 316 static inline void on_wakeup(clh_lock & this, size_t recursion ) { lock(this); } 292 317 293 318 //----------------------------------------------------------------------------- … … 312 337 static inline void ^?{}( exp_backoff_then_block_lock & this ){} 313 338 314 static inline bool internal_try_lock( exp_backoff_then_block_lock & this, size_t & compare_val) with(this) {339 static inline bool internal_try_lock(exp_backoff_then_block_lock & this, size_t & compare_val) with(this) { 315 340 return __atomic_compare_exchange_n(&lock_value, &compare_val, 1, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED); 316 341 } 317 342 318 static inline bool try_lock( exp_backoff_then_block_lock & this ) { size_t compare_val = 0; return internal_try_lock( this, compare_val); }319 320 static inline bool try_lock_contention( exp_backoff_then_block_lock & this) with(this) {321 return !__atomic_exchange_n( &lock_value, 2, __ATOMIC_ACQUIRE);322 } 323 324 static inline bool block( exp_backoff_then_block_lock & this) with(this) {343 static inline bool try_lock(exp_backoff_then_block_lock & this) { size_t compare_val = 0; return internal_try_lock(this, compare_val); } 344 345 static inline bool try_lock_contention(exp_backoff_then_block_lock & this) with(this) { 346 return !__atomic_exchange_n(&lock_value, 2, __ATOMIC_ACQUIRE); 347 } 348 349 static inline bool block(exp_backoff_then_block_lock & this) with(this) { 325 350 lock( spinlock __cfaabi_dbg_ctx2 ); 326 351 if (__atomic_load_n( &lock_value, __ATOMIC_SEQ_CST) != 2) { … … 334 359 } 335 360 336 static inline void lock( exp_backoff_then_block_lock & this) with(this) {361 static inline void lock(exp_backoff_then_block_lock & this) with(this) { 337 362 size_t compare_val = 0; 338 363 int spin = 4; … … 353 378 } 354 379 355 static inline void unlock( exp_backoff_then_block_lock & this) with(this) {380 static inline void unlock(exp_backoff_then_block_lock & this) with(this) { 356 381 if (__atomic_exchange_n(&lock_value, 0, __ATOMIC_RELEASE) == 1) return; 357 382 lock( spinlock __cfaabi_dbg_ctx2 ); … … 361 386 } 362 387 363 static inline void on_notify( exp_backoff_then_block_lock & this, struct thread$ * t ) { unpark( t); }364 static inline size_t on_wait( exp_backoff_then_block_lock & this ) { unlock( this ); park(); return 0; }365 static inline void on_wakeup( exp_backoff_then_block_lock & this, size_t recursion ) { lock( this); }388 static inline void on_notify(exp_backoff_then_block_lock & this, struct thread$ * t ) { unpark(t); } 389 static inline size_t on_wait(exp_backoff_then_block_lock & this) { unlock(this); return 0; } 390 static inline void on_wakeup(exp_backoff_then_block_lock & this, size_t recursion ) { lock(this); } 366 391 367 392 //----------------------------------------------------------------------------- … … 393 418 394 419 // if this is called recursively IT WILL DEADLOCK!!!!! 395 static inline void lock( fast_block_lock & this) with(this) {420 static inline void lock(fast_block_lock & this) with(this) { 396 421 lock( lock __cfaabi_dbg_ctx2 ); 397 422 if ( held ) { … … 405 430 } 406 431 407 static inline void unlock( fast_block_lock & this) with(this) {432 static inline void unlock(fast_block_lock & this) with(this) { 408 433 lock( lock __cfaabi_dbg_ctx2 ); 409 434 /* paranoid */ verifyf( held != false, "Attempt to release lock %p that isn't held", &this ); … … 414 439 } 415 440 416 static inline void on_notify( fast_block_lock & this, struct thread$ * t ) with(this) {441 static inline void on_notify(fast_block_lock & this, struct thread$ * t ) with(this) { 417 442 lock( lock __cfaabi_dbg_ctx2 ); 418 443 insert_last( blocked_threads, *t ); 419 444 unlock( lock ); 420 445 } 421 static inline size_t on_wait( fast_block_lock & this) { unlock(this); park(); return 0; }422 static inline void on_wakeup( fast_block_lock & this, size_t recursion ) { }446 static inline size_t on_wait(fast_block_lock & this) { unlock(this); return 0; } 447 static inline void on_wakeup(fast_block_lock & this, size_t recursion ) { } 423 448 424 449 //----------------------------------------------------------------------------- … … 431 456 struct simple_owner_lock { 432 457 // List of blocked threads 433 dlist( select_node) blocked_threads;458 dlist( thread$ ) blocked_threads; 434 459 435 460 // Spin lock used for mutual exclusion … … 452 477 static inline void ?=?( simple_owner_lock & this, simple_owner_lock this2 ) = void; 453 478 454 static inline void lock( simple_owner_lock & this) with(this) {455 if ( owner == active_thread()) {479 static inline void lock(simple_owner_lock & this) with(this) { 480 if (owner == active_thread()) { 456 481 recursion_count++; 457 482 return; … … 459 484 lock( lock __cfaabi_dbg_ctx2 ); 460 485 461 if ( owner != 0p ) { 462 select_node node; 463 insert_last( blocked_threads, node ); 486 if (owner != 0p) { 487 insert_last( blocked_threads, *active_thread() ); 464 488 unlock( lock ); 465 489 park( ); … … 471 495 } 472 496 473 static inline void pop_node( simple_owner_lock & this ) with(this) { 474 __handle_waituntil_OR( blocked_threads ); 475 select_node * node = &try_pop_front( blocked_threads ); 476 if ( node ) { 477 owner = node->blocked_thread; 478 recursion_count = 1; 479 // if ( !node->clause_status || __make_select_node_available( *node ) ) unpark( node->blocked_thread ); 480 wake_one( blocked_threads, *node ); 481 } else { 482 owner = 0p; 483 recursion_count = 0; 484 } 485 } 486 487 static inline void unlock( simple_owner_lock & this ) with(this) { 497 // TODO: fix duplicate def issue and bring this back 498 // void pop_and_set_new_owner( simple_owner_lock & this ) with( this ) { 499 // thread$ * t = &try_pop_front( blocked_threads ); 500 // owner = t; 501 // recursion_count = ( t ? 1 : 0 ); 502 // unpark( t ); 503 // } 504 505 static inline void unlock(simple_owner_lock & this) with(this) { 488 506 lock( lock __cfaabi_dbg_ctx2 ); 489 507 /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this ); … … 492 510 recursion_count--; 493 511 if ( recursion_count == 0 ) { 494 pop_node( this ); 512 // pop_and_set_new_owner( this ); 513 thread$ * t = &try_pop_front( blocked_threads ); 514 owner = t; 515 recursion_count = ( t ? 1 : 0 ); 516 unpark( t ); 495 517 } 496 518 unlock( lock ); 497 519 } 498 520 499 static inline void on_notify(simple_owner_lock & this, thread$ * t ) with(this) {521 static inline void on_notify(simple_owner_lock & this, struct thread$ * t ) with(this) { 500 522 lock( lock __cfaabi_dbg_ctx2 ); 501 523 // lock held 502 524 if ( owner != 0p ) { 503 insert_last( blocked_threads, * (select_node *)t->link_node);525 insert_last( blocked_threads, *t ); 504 526 } 505 527 // lock not held … … 512 534 } 513 535 514 static inline size_t on_wait( simple_owner_lock & this) with(this) {536 static inline size_t on_wait(simple_owner_lock & this) with(this) { 515 537 lock( lock __cfaabi_dbg_ctx2 ); 516 538 /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this ); … … 519 541 size_t ret = recursion_count; 520 542 521 pop_node( this ); 522 523 select_node node; 524 active_thread()->link_node = (void *)&node; 543 // pop_and_set_new_owner( this ); 544 545 thread$ * t = &try_pop_front( blocked_threads ); 546 owner = t; 547 recursion_count = ( t ? 1 : 0 ); 548 unpark( t ); 549 525 550 unlock( lock ); 526 park();527 528 551 return ret; 529 552 } 530 553 531 static inline void on_wakeup( simple_owner_lock & this, size_t recursion ) with(this) { recursion_count = recursion; } 532 533 // waituntil() support 534 static inline bool register_select( simple_owner_lock & this, select_node & node ) with(this) { 535 lock( lock __cfaabi_dbg_ctx2 ); 536 537 // check if we can complete operation. If so race to establish winner in special OR case 538 if ( !node.park_counter && ( owner == active_thread() || owner == 0p ) ) { 539 if ( !__make_select_node_available( node ) ) { // we didn't win the race so give up on registering 540 unlock( lock ); 541 return false; 542 } 543 } 544 545 if ( owner == active_thread() ) { 546 recursion_count++; 547 if ( node.park_counter ) __make_select_node_available( node ); 548 unlock( lock ); 549 return true; 550 } 551 552 if ( owner != 0p ) { 553 insert_last( blocked_threads, node ); 554 unlock( lock ); 555 return false; 556 } 557 558 owner = active_thread(); 559 recursion_count = 1; 560 561 if ( node.park_counter ) __make_select_node_available( node ); 562 unlock( lock ); 563 return true; 564 } 565 566 static inline bool unregister_select( simple_owner_lock & this, select_node & node ) with(this) { 567 lock( lock __cfaabi_dbg_ctx2 ); 568 if ( node`isListed ) { 569 remove( node ); 570 unlock( lock ); 571 return false; 572 } 573 574 if ( owner == active_thread() ) { 575 recursion_count--; 576 if ( recursion_count == 0 ) { 577 pop_node( this ); 578 } 579 } 580 unlock( lock ); 581 return false; 582 } 583 584 static inline bool on_selected( simple_owner_lock & this, select_node & node ) { return true; } 585 554 static inline void on_wakeup(simple_owner_lock & this, size_t recursion ) with(this) { recursion_count = recursion; } 586 555 587 556 //----------------------------------------------------------------------------- … … 609 578 610 579 // if this is called recursively IT WILL DEADLOCK! 611 static inline void lock( spin_queue_lock & this) with(this) {580 static inline void lock(spin_queue_lock & this) with(this) { 612 581 mcs_spin_node node; 613 582 lock( lock, node ); … … 617 586 } 618 587 619 static inline void unlock( spin_queue_lock & this) with(this) {588 static inline void unlock(spin_queue_lock & this) with(this) { 620 589 __atomic_store_n(&held, false, __ATOMIC_RELEASE); 621 590 } 622 591 623 static inline void on_notify( spin_queue_lock & this, struct thread$ * t ) {592 static inline void on_notify(spin_queue_lock & this, struct thread$ * t ) { 624 593 unpark(t); 625 594 } 626 static inline size_t on_wait( spin_queue_lock & this ) { unlock( this ); park(); return 0; }627 static inline void on_wakeup( spin_queue_lock & this, size_t recursion ) { lock( this); }595 static inline size_t on_wait(spin_queue_lock & this) { unlock(this); return 0; } 596 static inline void on_wakeup(spin_queue_lock & this, size_t recursion ) { lock(this); } 628 597 629 598 … … 652 621 653 622 // if this is called recursively IT WILL DEADLOCK!!!!! 654 static inline void lock( mcs_block_spin_lock & this) with(this) {623 static inline void lock(mcs_block_spin_lock & this) with(this) { 655 624 mcs_node node; 656 625 lock( lock, node ); … … 664 633 } 665 634 666 static inline void on_notify( mcs_block_spin_lock & this, struct thread$ * t ) { unpark( t); }667 static inline size_t on_wait( mcs_block_spin_lock & this) { unlock( this ); park(); return 0; }668 static inline void on_wakeup( mcs_block_spin_lock & this, size_t recursion ) {lock( this); }635 static inline void on_notify(mcs_block_spin_lock & this, struct thread$ * t ) { unpark(t); } 636 static inline size_t on_wait(mcs_block_spin_lock & this) { unlock(this); return 0; } 637 static inline void on_wakeup(mcs_block_spin_lock & this, size_t recursion ) {lock(this); } 669 638 670 639 //----------------------------------------------------------------------------- … … 692 661 693 662 // if this is called recursively IT WILL DEADLOCK!!!!! 694 static inline void lock( block_spin_lock & this) with(this) {663 static inline void lock(block_spin_lock & this) with(this) { 695 664 lock( lock ); 696 665 while(__atomic_load_n(&held, __ATOMIC_SEQ_CST)) Pause(); … … 699 668 } 700 669 701 static inline void unlock( block_spin_lock & this) with(this) {670 static inline void unlock(block_spin_lock & this) with(this) { 702 671 __atomic_store_n(&held, false, __ATOMIC_RELEASE); 703 672 } 704 673 705 static inline void on_notify( block_spin_lock & this, struct thread$ * t ) with(this.lock) {674 static inline void on_notify(block_spin_lock & this, struct thread$ * t ) with(this.lock) { 706 675 // first we acquire internal fast_block_lock 707 676 lock( lock __cfaabi_dbg_ctx2 ); … … 717 686 unpark(t); 718 687 } 719 static inline size_t on_wait( block_spin_lock & this ) { unlock( this ); park(); return 0; }720 static inline void on_wakeup( block_spin_lock & this, size_t recursion ) with(this) {688 static inline size_t on_wait(block_spin_lock & this) { unlock(this); return 0; } 689 static inline void on_wakeup(block_spin_lock & this, size_t recursion ) with(this) { 721 690 // now we acquire the entire block_spin_lock upon waking up 722 691 while(__atomic_load_n(&held, __ATOMIC_SEQ_CST)) Pause(); … … 745 714 forall(L & | is_blocking_lock(L)) { 746 715 struct info_thread; 716 717 // // for use by sequence 718 // info_thread(L) *& Back( info_thread(L) * this ); 719 // info_thread(L) *& Next( info_thread(L) * this ); 747 720 } 748 721
Note:
See TracChangeset
for help on using the changeset viewer.