|
| 1 | + |
| 2 | +#include<atomic> |
| 3 | + |
| 4 | +#include"../tbb/include/oneapi/tbb/detail/_namespace_injection.h" |
| 5 | +#include"../tbb/include/oneapi/tbb/task_arena.h" |
| 6 | + |
| 7 | +#include"../tbb/src/tbb/observer_proxy.h" |
| 8 | +#include"../tbb/src/tbb/main.h" |
| 9 | +#include"../tbb/src/tbb/thread_data.h" |
| 10 | + |
| 11 | +#ifdef _WIN32 |
| 12 | +# defineDLL_EXPORT__declspec(dllexport) |
| 13 | +#else |
| 14 | +# defineDLL_EXPORT |
| 15 | +#endif |
| 16 | + |
| 17 | +namespacetbb { |
| 18 | + |
| 19 | +namespaceinterface6 { |
| 20 | +classtask_scheduler_observer; |
| 21 | +} |
| 22 | + |
| 23 | +namespaceinternal { |
| 24 | + |
| 25 | +classtask_scheduler_observer_v3 { |
| 26 | +friendclasstbb::detail::r1::observer_proxy; |
| 27 | +friendclasstbb::detail::r1::observer_list; |
| 28 | +friendclassinterface6::task_scheduler_observer; |
| 29 | + |
| 30 | +//! Pointer to the proxy holding this observer. |
| 31 | +/** Observers are proxied by the scheduler to maintain persistent lists of them. **/ |
| 32 | + tbb::detail::r1::observer_proxy* my_proxy; |
| 33 | + |
| 34 | +//! Counter preventing the observer from being destroyed while in use by the scheduler. |
| 35 | +/** Valid only when observation is on. **/ |
| 36 | + std::atomic<intptr_t> my_busy_count; |
| 37 | + |
| 38 | +public: |
| 39 | +//! Enable or disable observation |
| 40 | +/** For local observers the method can be used only when the current thread |
| 41 | + has the task scheduler initialized or is attached to an arena. |
| 42 | + Repeated calls with the same state are no-ops. **/ |
| 43 | +void __TBB_EXPORTED_METHOD observe( bool state=true ); |
| 44 | + |
| 45 | +//! Returns true if observation is enabled, false otherwise. |
| 46 | +boolis_observing() const {return my_proxy!=NULL;} |
| 47 | + |
| 48 | +//! Construct observer with observation disabled. |
| 49 | +task_scheduler_observer_v3() : my_proxy(NULL) { my_busy_count.store(0); } |
| 50 | + |
| 51 | +//! Entry notification |
| 52 | +/** Invoked from inside observe(true) call and whenever a worker enters the arena |
| 53 | + this observer is associated with. If a thread is already in the arena when |
| 54 | + the observer is activated, the entry notification is called before it |
| 55 | + executes the first stolen task. |
| 56 | + Obsolete semantics. For global observers it is called by a thread before |
| 57 | + the first steal since observation became enabled. **/ |
| 58 | +virtualvoidon_scheduler_entry( bool/*is_worker*/ ) {} |
| 59 | + |
| 60 | +//! Exit notification |
| 61 | +/** Invoked from inside observe(false) call and whenever a worker leaves the |
| 62 | + arena this observer is associated with. |
| 63 | + Obsolete semantics. For global observers it is called by a thread before |
| 64 | + the first steal since observation became enabled. **/ |
| 65 | +virtualvoidon_scheduler_exit( bool/*is_worker*/ ) {} |
| 66 | + |
| 67 | +//! Destructor automatically switches observation off if it is enabled. |
| 68 | +virtual~task_scheduler_observer_v3() { if(my_proxy) observe(false);} |
| 69 | +}; |
| 70 | + |
| 71 | +} // namespace internal |
| 72 | + |
| 73 | +namespaceinterface6 { |
| 74 | + |
| 75 | +classtask_scheduler_observer : publicinternal::task_scheduler_observer_v3 { |
| 76 | +friendclassinternal::task_scheduler_observer_v3; |
| 77 | +friendclasstbb::detail::r1::observer_proxy; |
| 78 | +friendclasstbb::detail::r1::observer_list; |
| 79 | + |
| 80 | +/** Negative numbers with the largest absolute value to minimize probability |
| 81 | + of coincidence in case of a bug in busy count usage. **/ |
| 82 | +// TODO: take more high bits for version number |
| 83 | +staticconstintptr_t v6_trait = (intptr_t)((~(uintptr_t)0 >> 1) + 1); |
| 84 | + |
| 85 | +//! contains task_arena pointer or tag indicating local or global semantics of the observer |
| 86 | +intptr_t my_context_tag; |
| 87 | +enum { global_tag = 0, implicit_tag = 1 }; |
| 88 | + |
| 89 | +public: |
| 90 | +//! Construct local or global observer in inactive state (observation disabled). |
| 91 | +/** For a local observer entry/exit notifications are invoked whenever a worker |
| 92 | + thread joins/leaves the arena of the observer's owner thread. If a thread is |
| 93 | + already in the arena when the observer is activated, the entry notification is |
| 94 | + called before it executes the first stolen task. **/ |
| 95 | +/** TODO: Obsolete. |
| 96 | + Global observer semantics is obsolete as it violates master thread isolation |
| 97 | + guarantees and is not composable. Thus the current default behavior of the |
| 98 | + constructor is obsolete too and will be changed in one of the future versions |
| 99 | + of the library. **/ |
| 100 | +explicittask_scheduler_observer( bool local = false ) { |
| 101 | + my_context_tag = local? implicit_tag : global_tag; |
| 102 | + } |
| 103 | + |
| 104 | +//! Construct local observer for a given arena in inactive state (observation disabled). |
| 105 | +/** entry/exit notifications are invoked whenever a thread joins/leaves arena. |
| 106 | + If a thread is already in the arena when the observer is activated, the entry notification |
| 107 | + is called before it executes the first stolen task. **/ |
| 108 | +explicittask_scheduler_observer( task_arena & a) { |
| 109 | + my_context_tag = (intptr_t)&a; |
| 110 | + } |
| 111 | + |
| 112 | +/** Destructor protects instance of the observer from concurrent notification. |
| 113 | + It is recommended to disable observation before destructor of a derived class starts, |
| 114 | + otherwise it can lead to concurrent notification callback on partly destroyed object **/ |
| 115 | +virtual~task_scheduler_observer() { if(my_proxy) observe(false); } |
| 116 | + |
| 117 | +//! Enable or disable observation |
| 118 | +/** Warning: concurrent invocations of this method are not safe. |
| 119 | + Repeated calls with the same state are no-ops. **/ |
| 120 | +voidobserve( bool state=true ) { |
| 121 | +if( state && !my_proxy ) { |
| 122 | +__TBB_ASSERT( !my_busy_count, "Inconsistent state of task_scheduler_observer instance"); |
| 123 | + my_busy_count.store(v6_trait); |
| 124 | + } |
| 125 | +internal::task_scheduler_observer_v3::observe(state); |
| 126 | + } |
| 127 | +}; |
| 128 | + |
| 129 | +} // namespace interface6 |
| 130 | + |
| 131 | +} // namespace tbb |
| 132 | + |
| 133 | +namespacetbb { |
| 134 | +namespaceinternal { |
| 135 | + |
| 136 | +DLL_EXPORT |
| 137 | +void __TBB_EXPORTED_FUNC task_scheduler_observer_v3::observe( bool enable ) { |
| 138 | +auto* tso = (tbb::detail::d1::task_scheduler_observer*) (this); |
| 139 | +tbb::detail::r1::observe(*tso, enable); |
| 140 | +} |
| 141 | + |
| 142 | +} // namespace internal |
| 143 | +} // namespace tbb |
0 commit comments