| 34 | namespace internal { |
| 35 | |
| 36 | void arena::process( generic_scheduler& s ) { |
| 37 | __TBB_ASSERT( is_alive(my_guard), NULL ); |
| 38 | __TBB_ASSERT( governor::is_set(&s), NULL ); |
| 39 | __TBB_ASSERT( !s.my_innermost_running_task, NULL ); |
| 40 | __TBB_ASSERT( !s.my_dispatching_task, NULL ); |
| 41 | |
| 42 | __TBB_ASSERT( my_num_slots != 1, NULL ); |
| 43 | // Start search for an empty slot from the one we occupied the last time |
| 44 | unsigned index = s.my_arena_index < my_num_slots ? s.my_arena_index : s.my_random.get() % (my_num_slots - 1) + 1, |
| 45 | end = index; |
| 46 | __TBB_ASSERT( index != 0, "A worker cannot occupy slot 0" ); |
| 47 | __TBB_ASSERT( index < my_num_slots, NULL ); |
| 48 | |
| 49 | // Find a vacant slot |
| 50 | for ( ;; ) { |
| 51 | if ( !my_slots[index].my_scheduler && as_atomic(my_slots[index].my_scheduler).compare_and_swap(&s, NULL ) == NULL ) |
| 52 | break; |
| 53 | if ( ++index == my_num_slots ) |
| 54 | index = 1; |
| 55 | if ( index == end ) { |
| 56 | // Likely this arena is already saturated |
| 57 | goto quit; |
| 58 | } |
| 59 | } |
| 60 | ITT_NOTIFY(sync_acquired, my_slots + index); |
| 61 | s.my_arena = this; |
| 62 | s.my_arena_index = index; |
| 63 | s.my_arena_slot = my_slots + index; |
| 64 | #if __TBB_TASK_PRIORITY |
| 65 | s.my_local_reload_epoch = *s.my_ref_reload_epoch; |
| 66 | __TBB_ASSERT( !s.my_offloaded_tasks, NULL ); |
| 67 | #endif /* __TBB_TASK_PRIORITY */ |
| 68 | s.attach_mailbox( affinity_id(index+1) ); |
| 69 | |
| 70 | s.my_arena_slot->hint_for_pop = index; // initial value for round-robin |
| 71 | |
| 72 | #if !__TBB_FP_CONTEXT |
| 73 | my_cpu_ctl_env.set_env(); |
| 74 | #endif |
| 75 | |
| 76 | #if __TBB_SCHEDULER_OBSERVER |
| 77 | __TBB_ASSERT( !s.my_last_local_observer, "There cannot be notified local observers when entering arena" ); |
| 78 | my_observers.notify_entry_observers( s.my_last_local_observer, /*worker=*/true ); |
| 79 | #endif /* __TBB_SCHEDULER_OBSERVER */ |
| 80 | |
| 81 | atomic_update( my_limit, index + 1, std::less<unsigned>() ); |
| 82 | |
| 83 | for ( ;; ) { |
| 84 | // Try to steal a task. |
| 85 | // Passing reference count is technically unnecessary in this context, |
| 86 | // but omitting it here would add checks inside the function. |
| 87 | __TBB_ASSERT( is_alive(my_guard), NULL ); |
| 88 | task* t = s.receive_or_steal_task( s.my_dummy_task->prefix().ref_count, /*return_if_no_work=*/true ); |
| 89 | if (t) { |
| 90 | // A side effect of receive_or_steal_task is that my_innermost_running_task can be set. |
| 91 | // But for the outermost dispatch loop of a worker it has to be NULL. |
| 92 | s.my_innermost_running_task = NULL; |
| 93 | __TBB_ASSERT( !s.my_dispatching_task, NULL ); |
no test coverage detected