| 423 | } |
| 424 | |
| 425 | size_t generic_scheduler::prepare_task_pool ( size_t num_tasks ) { |
| 426 | size_t T = __TBB_load_relaxed(my_arena_slot->tail); // mirror |
| 427 | if ( T + num_tasks <= my_arena_slot->my_task_pool_size ) |
| 428 | return T; |
| 429 | acquire_task_pool(); |
| 430 | size_t H = __TBB_load_relaxed(my_arena_slot->head); // mirror |
| 431 | T -= H; |
| 432 | size_t new_size = T + num_tasks; |
| 433 | __TBB_ASSERT(!my_arena_slot->my_task_pool_size || my_arena_slot->my_task_pool_size >= min_task_pool_size, NULL); |
| 434 | if( !my_arena_slot->my_task_pool_size ) { |
| 435 | __TBB_ASSERT( !in_arena() && !my_arena_slot->task_pool_ptr, NULL ); |
| 436 | if( new_size < min_task_pool_size ) new_size = min_task_pool_size; |
| 437 | my_arena_slot->allocate_task_pool( new_size ); |
| 438 | } |
| 439 | // If the free space at the beginning of the task pool is too short, we |
| 440 | // are likely facing a pathological single-producer-multiple-consumers |
| 441 | // scenario, and thus it's better to expand the task pool |
| 442 | else if ( new_size <= my_arena_slot->my_task_pool_size - min_task_pool_size/4 ) { |
| 443 | // Relocate the busy part to the beginning of the deque |
| 444 | memmove( my_arena_slot->task_pool_ptr, my_arena_slot->task_pool_ptr + H, T * sizeof(task*) ); |
| 445 | my_arena_slot->fill_with_canary_pattern( T, my_arena_slot->tail ); |
| 446 | commit_relocated_tasks(T); |
| 447 | } |
| 448 | else { |
| 449 | // Grow task pool. As this operation is rare, and its cost is asymptotically |
| 450 | // amortizable, we can tolerate new task pool allocation done under the lock. |
| 451 | if ( new_size < 2 * my_arena_slot->my_task_pool_size ) |
| 452 | new_size = 2 * my_arena_slot->my_task_pool_size; |
| 453 | task** old_pool = my_arena_slot->task_pool_ptr; |
| 454 | my_arena_slot->allocate_task_pool( new_size ); // updates my_task_pool_size |
| 455 | __TBB_ASSERT( T <= my_arena_slot->my_task_pool_size, "new task pool is too short" ); |
| 456 | memcpy( my_arena_slot->task_pool_ptr, old_pool + H, T * sizeof(task*) ); |
| 457 | commit_relocated_tasks(T); |
| 458 | __TBB_ASSERT( old_pool, "attempt to free NULL TaskPool" ); |
| 459 | NFS_Free( old_pool ); |
| 460 | } |
| 461 | assert_task_pool_valid(); |
| 462 | return T; |
| 463 | } |
| 464 | |
| 465 | /** ATTENTION: |
| 466 | This method is mostly the same as generic_scheduler::lock_task_pool(), with |
nothing calls this directly
no test coverage detected