19 #if __TBB_SCHEDULER_OBSERVER
30 padded<observer_list> the_global_observer_list;
33 static atomic<int> observer_proxy_count;
35 struct check_observer_proxy_count {
36 ~check_observer_proxy_count() {
37 if( observer_proxy_count!=0 ) {
38 runtime_warning(
"Leaked %ld observer_proxy objects\n",
long(observer_proxy_count) );
43 static check_observer_proxy_count the_check_observer_proxy_count;
46 #if __TBB_ARENA_OBSERVER
47 interface6::task_scheduler_observer* observer_proxy::get_v6_observer() {
48 if(my_version != 6)
return NULL;
49 return static_cast<interface6::task_scheduler_observer*
>(my_observer);
53 #if __TBB_ARENA_OBSERVER
54 bool observer_proxy::is_global() {
59 observer_proxy::observer_proxy( task_scheduler_observer_v3& tso )
60 : my_list(NULL), my_next(NULL), my_prev(NULL), my_observer(&tso)
63 ++observer_proxy_count;
68 #if __TBB_ARENA_OBSERVER
69 load<relaxed>(my_observer->my_busy_count)
70 == interface6::task_scheduler_observer::v6_trait ? 6 :
73 __TBB_ASSERT( my_version >= 6 || !load<relaxed>(my_observer->my_busy_count), NULL );
77 observer_proxy::~observer_proxy () {
78 __TBB_ASSERT( !my_ref_count,
"Attempt to destroy proxy still in use" );
82 --observer_proxy_count;
86 template<memory_semantics M,
class T,
class V>
87 T atomic_fetch_and_store ( T*
addr,
const V& val ) {
88 return (T)atomic_traits<
sizeof(T), M>::fetch_and_store(
addr, (T)val );
91 void observer_list::clear () {
92 __TBB_ASSERT(
this != &the_global_observer_list,
"Method clear() cannot be used on the list of global observers" );
97 scoped_lock
lock(mutex(),
true);
98 observer_proxy *next = my_head;
99 while ( observer_proxy *
p = next ) {
104 task_scheduler_observer_v3 *obs =
p->my_observer;
107 if ( !obs || !(
p = (observer_proxy*)__TBB_FetchAndStoreW(&obs->my_proxy, 0)) )
111 __TBB_ASSERT( is_alive(
p->my_ref_count),
"Observer's proxy died prematurely" );
112 __TBB_ASSERT(
p->my_ref_count == 1,
"Reference for observer is missing" );
114 p->my_observer = NULL;
125 void observer_list::insert ( observer_proxy*
p ) {
126 scoped_lock
lock(mutex(),
true);
128 p->my_prev = my_tail;
129 my_tail->my_next =
p;
136 void observer_list::remove ( observer_proxy*
p ) {
137 __TBB_ASSERT( my_head,
"Attempt to remove an item from an empty list" );
138 __TBB_ASSERT( !my_tail->my_next,
"Last item's my_next must be NULL" );
141 my_tail =
p->my_prev;
145 p->my_next->my_prev =
p->my_prev;
147 if (
p == my_head ) {
149 my_head =
p->my_next;
153 p->my_prev->my_next =
p->my_next;
155 __TBB_ASSERT( (my_head && my_tail) || (!my_head && !my_tail), NULL );
158 void observer_list::remove_ref( observer_proxy*
p ) {
159 int r =
p->my_ref_count;
163 int r_old =
p->my_ref_count.compare_and_swap(r-1,r);
174 observer_list::scoped_lock
lock(mutex(),
true);
175 r = --
p->my_ref_count;
184 void observer_list::do_notify_entry_observers( observer_proxy*&
last,
bool worker ) {
186 observer_proxy *
p =
last, *prev =
p;
188 task_scheduler_observer_v3* tso=NULL;
191 scoped_lock
lock(mutex(),
false);
195 if( observer_proxy* q =
p->my_next ) {
197 remove_ref_fast(prev);
223 tso =
p->my_observer;
226 ++tso->my_busy_count;
235 tso->on_scheduler_entry(worker);
237 intptr_t bc = --tso->my_busy_count;
243 void observer_list::do_notify_exit_observers( observer_proxy*
last,
bool worker ) {
245 observer_proxy *
p = NULL, *prev = NULL;
247 task_scheduler_observer_v3* tso=NULL;
250 scoped_lock
lock(mutex(),
false);
255 __TBB_ASSERT(
p->my_next,
"List items before 'last' must have valid my_next pointer" );
257 remove_ref_fast(prev);
271 __TBB_ASSERT(
p,
"Nonzero 'last' must guarantee that the global list is non-empty" );
273 tso =
p->my_observer;
278 ++tso->my_busy_count;
286 tso->on_scheduler_exit(worker);
288 intptr_t bc = --tso->my_busy_count;
294 void task_scheduler_observer_v3::observe(
bool enable ) {
297 my_proxy =
new observer_proxy( *
this );
299 #if __TBB_ARENA_OBSERVER
300 if ( !my_proxy->is_global() ) {
302 generic_scheduler*
s = governor::local_scheduler_if_initialized();
304 intptr_t tag = my_proxy->get_v6_observer()->my_context_tag;
305 if( tag != interface6::task_scheduler_observer::implicit_tag ) {
306 task_arena *a =
reinterpret_cast<task_arena*
>(tag);
307 if ( a->my_arena==NULL )
309 my_proxy->my_list = &a->my_arena->my_observers;
311 if( !(
s &&
s->my_arena) )
312 s = governor::init_scheduler( task_scheduler_init::automatic, 0,
true );
313 __TBB_ASSERT( __TBB_InitOnce::initialization_done(), NULL );
315 my_proxy->my_list = &
s->my_arena->my_observers;
317 my_proxy->my_list->insert(my_proxy);
319 if(
s && &
s->my_arena->my_observers == my_proxy->my_list )
320 my_proxy->my_list->notify_entry_observers(
s->my_last_local_observer,
s->is_worker() );
325 if( !__TBB_InitOnce::initialization_done() )
327 my_proxy->my_list = &the_global_observer_list;
328 my_proxy->my_list->insert(my_proxy);
329 if( generic_scheduler*
s = governor::local_scheduler_if_initialized() ) {
332 the_global_observer_list.notify_entry_observers(
s->my_last_global_observer,
s->is_worker() );
339 if ( observer_proxy* proxy = (observer_proxy*)__TBB_FetchAndStoreW(&my_proxy, 0) ) {
342 __TBB_ASSERT( is_alive(proxy->my_ref_count),
"Observer's proxy died prematurely" );
343 __TBB_ASSERT( proxy->my_ref_count >= 1,
"reference for observer missing" );
344 observer_list &list = *proxy->my_list;
347 observer_list::scoped_lock
lock(list.mutex(),
true);
348 proxy->my_observer = NULL;
350 if( !--proxy->my_ref_count ) {
356 while( my_busy_count )
#define __TBB_ASSERT_EX(predicate, comment)
"Extended" version is useful to suppress warnings if a variable is only used with an assert
#define __TBB_ASSERT(predicate, comment)
No-op version of __TBB_ASSERT.
void const char const char int ITT_FORMAT __itt_group_sync s
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int void size_t ITT_FORMAT d void ITT_FORMAT p void ITT_FORMAT p __itt_model_site __itt_model_site_instance ITT_FORMAT p __itt_model_task __itt_model_task_instance ITT_FORMAT p void * lock
void const char const char int ITT_FORMAT __itt_group_sync p
void __TBB_EXPORTED_FUNC runtime_warning(const char *format,...)
Report a runtime warning.
void poison_pointer(T *__TBB_atomic &)
void DoOneTimeInitializations()
Performs thread-safe lazy one-time general TBB initialization.
auto last(Container &c) -> decltype(begin(c))