| 434 | } |
| 435 | |
| 436 | CDS_EXPORT_API void smr::help_scan( thread_data* pThis ) |
| 437 | { |
| 438 | assert( static_cast<thread_record*>( pThis )->thread_id_.load( atomics::memory_order_relaxed ) == cds::OS::get_current_thread_id()); |
| 439 | CDS_HPSTAT( ++pThis->help_scan_call_count_ ); |
| 440 | |
| 441 | const cds::OS::ThreadId nullThreadId = cds::OS::c_NullThreadId; |
| 442 | const cds::OS::ThreadId curThreadId = cds::OS::get_current_thread_id(); |
| 443 | for ( thread_record* hprec = thread_list_.load( atomics::memory_order_acquire ); hprec; hprec = hprec->next_ ) |
| 444 | { |
| 445 | if ( hprec == static_cast<thread_record*>( pThis )) |
| 446 | continue; |
| 447 | |
| 448 | // If free_ == true then hprec->retired_ is empty - we don't need to see it |
| 449 | if ( hprec->free_.load( atomics::memory_order_acquire )) { |
| 450 | CDS_TSAN_ANNOTATE_IGNORE_READS_BEGIN; |
| 451 | assert( hprec->retired_.empty()); |
| 452 | CDS_TSAN_ANNOTATE_IGNORE_READS_END; |
| 453 | continue; |
| 454 | } |
| 455 | |
| 456 | // Owns hprec |
| 457 | // Several threads may work concurrently so we use atomic technique |
| 458 | { |
| 459 | cds::OS::ThreadId curOwner = hprec->thread_id_.load( atomics::memory_order_relaxed ); |
| 460 | if ( curOwner == nullThreadId ) { |
| 461 | if ( !hprec->thread_id_.compare_exchange_strong( curOwner, curThreadId, atomics::memory_order_acquire, atomics::memory_order_relaxed )) |
| 462 | continue; |
| 463 | } |
| 464 | else |
| 465 | continue; |
| 466 | } |
| 467 | |
| 468 | // We own the thread record successfully. Now, we can see whether it has retired pointers. |
| 469 | // If it has ones then we move them to pThis that is private for current thread. |
| 470 | hprec->sync(); |
| 471 | retired_array& src = hprec->retired_; |
| 472 | retired_array& dest = pThis->retired_; |
| 473 | |
| 474 | for ( retired_block* block = src.list_head_; block; block = block->next_ ) { |
| 475 | retired_ptr* last = block == src.current_block_ ? src.current_cell_ : block->last(); |
| 476 | for ( retired_ptr* p = block->first(); p != last; ++p ) { |
| 477 | if ( !dest.push( *p )) |
| 478 | scan( pThis ); |
| 479 | } |
| 480 | |
| 481 | if ( block == src.current_block_ ) |
| 482 | break; |
| 483 | } |
| 484 | |
| 485 | src.fini(); |
| 486 | hprec->free_.store( true, atomics::memory_order_relaxed ); |
| 487 | hprec->thread_id_.store( nullThreadId, atomics::memory_order_release ); |
| 488 | } |
| 489 | |
| 490 | scan( pThis ); |
| 491 | } |
| 492 | |
| 493 | CDS_EXPORT_API void smr::statistics( stat& st ) |
nothing calls this directly
no test coverage detected