| 373 | } // namespace |
| 374 | |
| 375 | CDS_EXPORT_API void smr::scan( thread_data* pThreadRec ) |
| 376 | { |
| 377 | thread_record* pRec = static_cast<thread_record*>( pThreadRec ); |
| 378 | pRec->sync(); |
| 379 | |
| 380 | CDS_HPSTAT( ++pRec->scan_call_count_ ); |
| 381 | |
| 382 | hp_vector plist; |
| 383 | size_t plist_size = last_plist_size_.load( std::memory_order_relaxed ); |
| 384 | plist.reserve( plist_size ); |
| 385 | |
| 386 | // Stage 1: Scan HP list and insert non-null values in plist |
| 387 | thread_record* pNode = thread_list_.load( atomics::memory_order_acquire ); |
| 388 | while ( pNode ) { |
| 389 | if ( pNode->thread_id_.load( std::memory_order_relaxed ) != cds::OS::c_NullThreadId ) { |
| 390 | copy_hazards( plist, pNode->hazards_.array_, pNode->hazards_.initial_capacity_ ); |
| 391 | |
| 392 | for ( guard_block* block = pNode->hazards_.extended_list_.load( atomics::memory_order_acquire ); |
| 393 | block; |
| 394 | block = block->next_block_ ) |
| 395 | { |
| 396 | copy_hazards( plist, block->first(), defaults::c_extended_guard_block_size ); |
| 397 | } |
| 398 | } |
| 399 | |
| 400 | pNode = pNode->next_; |
| 401 | } |
| 402 | |
| 403 | // Store plist size for next scan() call (vector reallocation optimization) |
| 404 | if ( plist.size() > plist_size ) |
| 405 | last_plist_size_.compare_exchange_weak( plist_size, plist.size(), std::memory_order_relaxed, std::memory_order_relaxed ); |
| 406 | |
| 407 | // Sort plist to simplify search in |
| 408 | std::sort( plist.begin(), plist.end()); |
| 409 | |
| 410 | // Stage 2: Search plist |
| 411 | size_t free_count = 0; |
| 412 | size_t retired_count = 0; |
| 413 | retired_block* last_block = pRec->retired_.current_block_; |
| 414 | retired_ptr* last_block_cell = pRec->retired_.current_cell_; |
| 415 | |
| 416 | pRec->retired_.current_block_ = pRec->retired_.list_head_; |
| 417 | pRec->retired_.current_cell_ = pRec->retired_.current_block_->first(); |
| 418 | |
| 419 | for ( retired_block* block = pRec->retired_.list_head_; block; block = block->next_ ) { |
| 420 | bool const end_block = block == last_block; |
| 421 | size_t const size = end_block ? last_block_cell - block->first() : retired_block::c_capacity; |
| 422 | |
| 423 | retired_count += retired_block::c_capacity; |
| 424 | free_count += retire_data( plist, pRec->retired_, block, size ); |
| 425 | |
| 426 | if ( end_block ) |
| 427 | break; |
| 428 | } |
| 429 | CDS_HPSTAT( pRec->free_call_count_ += free_count ); |
| 430 | |
| 431 | // If the count of freed elements is too small, increase retired array |
| 432 | if ( free_count < retired_count / 4 && last_block == pRec->retired_.list_tail_ && last_block_cell == last_block->last()) |
nothing calls this directly
no test coverage detected