| 258 | } |
| 259 | |
| 260 | void task_group_context::bind_to ( generic_scheduler *local_sched ) { |
| 261 | __TBB_ASSERT ( __TBB_load_relaxed(my_kind) == binding_required, "Already bound or isolated?" ); |
| 262 | __TBB_ASSERT ( !my_parent, "Parent is set before initial binding" ); |
| 263 | my_parent = local_sched->my_innermost_running_task->prefix().context; |
| 264 | #if __TBB_FP_CONTEXT |
| 265 | // Inherit FPU settings only if the context has not captured FPU settings yet. |
| 266 | if ( !(my_version_and_traits & fp_settings) ) |
| 267 | copy_fp_settings(*my_parent); |
| 268 | #endif |
| 269 | |
| 270 | // Condition below prevents unnecessary thrashing parent context's cache line |
| 271 | if ( !(my_parent->my_state & may_have_children) ) |
| 272 | my_parent->my_state |= may_have_children; // full fence is below |
| 273 | if ( my_parent->my_parent ) { |
| 274 | // Even if this context were made accessible for state change propagation |
| 275 | // (by placing __TBB_store_with_release(s->my_context_list_head.my_next, &my_node) |
| 276 | // above), it still could be missed if state propagation from a grand-ancestor |
| 277 | // was underway concurrently with binding. |
| 278 | // Speculative propagation from the parent together with epoch counters |
| 279 | // detecting possibility of such a race allow to avoid taking locks when |
| 280 | // there is no contention. |
| 281 | |
| 282 | // Acquire fence is necessary to prevent reordering subsequent speculative |
| 283 | // loads of parent state data out of the scope where epoch counters comparison |
| 284 | // can reliably validate it. |
| 285 | uintptr_t local_count_snapshot = __TBB_load_with_acquire( my_parent->my_owner->my_context_state_propagation_epoch ); |
| 286 | // Speculative propagation of parent's state. The speculation will be |
| 287 | // validated by the epoch counters check further on. |
| 288 | my_cancellation_requested = my_parent->my_cancellation_requested; |
| 289 | #if __TBB_TASK_PRIORITY |
| 290 | my_priority = my_parent->my_priority; |
| 291 | #endif /* __TBB_TASK_PRIORITY */ |
| 292 | register_with( local_sched ); // Issues full fence |
| 293 | |
| 294 | // If no state propagation was detected by the following condition, the above |
| 295 | // full fence guarantees that the parent had correct state during speculative |
| 296 | // propagation before the fence. Otherwise the propagation from parent is |
| 297 | // repeated under the lock. |
| 298 | if ( local_count_snapshot != the_context_state_propagation_epoch ) { |
| 299 | // Another thread may be propagating state change right now. So resort to lock. |
| 300 | context_state_propagation_mutex_type::scoped_lock lock(the_context_state_propagation_mutex); |
| 301 | my_cancellation_requested = my_parent->my_cancellation_requested; |
| 302 | #if __TBB_TASK_PRIORITY |
| 303 | my_priority = my_parent->my_priority; |
| 304 | #endif /* __TBB_TASK_PRIORITY */ |
| 305 | } |
| 306 | } |
| 307 | else { |
| 308 | register_with( local_sched ); // Issues full fence |
| 309 | // As we do not have grand-ancestors, concurrent state propagation (if any) |
| 310 | // may originate only from the parent context, and thus it is safe to directly |
| 311 | // copy the state from it. |
| 312 | my_cancellation_requested = my_parent->my_cancellation_requested; |
| 313 | #if __TBB_TASK_PRIORITY |
| 314 | my_priority = my_parent->my_priority; |
| 315 | #endif /* __TBB_TASK_PRIORITY */ |
| 316 | } |
| 317 | __TBB_store_relaxed(my_kind, binding_completed); |
no test coverage detected