| 88 | } |
| 89 | |
| 90 | void observer_list::clear () { |
| 91 | __TBB_ASSERT( this != &the_global_observer_list, "Method clear() cannot be used on the list of global observers" ); |
| 92 | // Though the method will work fine for the empty list, we require the caller |
| 93 | // to check for the list emptiness before invoking it to avoid extra overhead. |
| 94 | __TBB_ASSERT( !empty(), NULL ); |
| 95 | { |
| 96 | scoped_lock lock(mutex(), /*is_writer=*/true); |
| 97 | observer_proxy *next = my_head; |
| 98 | while ( observer_proxy *p = next ) { |
| 99 | __TBB_ASSERT( p->my_version >= 6, NULL ); |
| 100 | next = p->my_next; |
| 101 | // Both proxy p and observer p->my_observer (if non-null) are guaranteed |
| 102 | // to be alive while the list is locked. |
| 103 | task_scheduler_observer_v3 *obs = p->my_observer; |
| 104 | // Make sure that possible concurrent observer destruction does not |
| 105 | // conflict with the proxy list cleanup. |
| 106 | if ( !obs || !(p = (observer_proxy*)__TBB_FetchAndStoreW(&obs->my_proxy, 0)) ) |
| 107 | continue; |
| 108 | // accessing 'obs' after detaching of obs->my_proxy leads to the race with observer destruction |
| 109 | __TBB_ASSERT( !next || p == next->my_prev, NULL ); |
| 110 | __TBB_ASSERT( is_alive(p->my_ref_count), "Observer's proxy died prematurely" ); |
| 111 | __TBB_ASSERT( p->my_ref_count == 1, "Reference for observer is missing" ); |
| 112 | #if TBB_USE_ASSERT |
| 113 | p->my_observer = NULL; |
| 114 | p->my_ref_count = 0; |
| 115 | #endif /* TBB_USE_ASSERT */ |
| 116 | remove(p); |
| 117 | delete p; |
| 118 | } |
| 119 | } |
| 120 | while( my_head ) |
| 121 | __TBB_Yield(); |
| 122 | } |
| 123 | |
| 124 | void observer_list::insert ( observer_proxy* p ) { |
| 125 | scoped_lock lock(mutex(), /*is_writer=*/true); |