| 349 | #endif//__TBB_SLEEP_PERMISSION |
| 350 | |
| 351 | void task_scheduler_observer_v3::observe( bool enable ) { |
| 352 | if( enable ) { |
| 353 | if( !my_proxy ) { |
| 354 | my_proxy = new observer_proxy( *this ); |
| 355 | my_busy_count = 0; // proxy stores versioning information, clear it |
| 356 | if ( !my_proxy->is_global() ) { |
| 357 | // Local observer activation |
| 358 | generic_scheduler* s = governor::local_scheduler_if_initialized(); |
| 359 | #if __TBB_TASK_ARENA |
| 360 | __TBB_ASSERT( my_proxy->get_v6_observer(), NULL ); |
| 361 | intptr_t tag = my_proxy->get_v6_observer()->my_context_tag; |
| 362 | if( tag != interface6::task_scheduler_observer::implicit_tag ) { // explicit arena |
| 363 | task_arena *a = reinterpret_cast<task_arena*>(tag); |
| 364 | a->initialize(); |
| 365 | my_proxy->my_list = &a->my_arena->my_observers; |
| 366 | } else |
| 367 | #endif |
| 368 | { |
| 369 | if( !s ) s = governor::init_scheduler( (unsigned)task_scheduler_init::automatic, 0, true ); |
| 370 | __TBB_ASSERT( __TBB_InitOnce::initialization_done(), NULL ); |
| 371 | __TBB_ASSERT( s && s->my_arena, NULL ); |
| 372 | my_proxy->my_list = &s->my_arena->my_observers; |
| 373 | } |
| 374 | my_proxy->my_list->insert(my_proxy); |
| 375 | // Notify newly activated observer and other pending ones if it belongs to current arena |
| 376 | if(s && &s->my_arena->my_observers == my_proxy->my_list ) |
| 377 | my_proxy->my_list->notify_entry_observers( s->my_last_local_observer, s->is_worker() ); |
| 378 | } else { |
| 379 | // Obsolete. Global observer activation |
| 380 | if( !__TBB_InitOnce::initialization_done() ) |
| 381 | DoOneTimeInitializations(); |
| 382 | my_proxy->my_list = &the_global_observer_list; |
| 383 | my_proxy->my_list->insert(my_proxy); |
| 384 | if( generic_scheduler* s = governor::local_scheduler_if_initialized() ) { |
| 385 | // Notify newly created observer of its own thread. |
| 386 | // Any other pending observers are notified too. |
| 387 | the_global_observer_list.notify_entry_observers( s->my_last_global_observer, s->is_worker() ); |
| 388 | } |
| 389 | } |
| 390 | } |
| 391 | } else { |
| 392 | // Make sure that possible concurrent proxy list cleanup does not conflict |
| 393 | // with the observer destruction here. |
| 394 | if ( observer_proxy* proxy = (observer_proxy*)__TBB_FetchAndStoreW(&my_proxy, 0) ) { |
| 395 | // List destruction should not touch this proxy after we've won the above interlocked exchange. |
| 396 | __TBB_ASSERT( proxy->my_observer == this, NULL ); |
| 397 | __TBB_ASSERT( is_alive(proxy->my_ref_count), "Observer's proxy died prematurely" ); |
| 398 | __TBB_ASSERT( proxy->my_ref_count >= 1, "reference for observer missing" ); |
| 399 | observer_list &list = *proxy->my_list; |
| 400 | { |
| 401 | // Ensure that none of the list walkers relies on observer pointer validity |
| 402 | observer_list::scoped_lock lock(list.mutex(), /*is_writer=*/true); |
| 403 | proxy->my_observer = NULL; |
| 404 | // Proxy may still be held by other threads (to track the last notified observer) |
| 405 | if( !--proxy->my_ref_count ) {// nobody can increase it under exclusive lock |
| 406 | list.remove(proxy); |
| 407 | __TBB_ASSERT( !proxy->my_ref_count, NULL ); |
| 408 | delete proxy; |
nothing calls this directly
no test coverage detected