Intel(R) Threading Building Blocks Doxygen Documentation  version 4.2.3
_aggregator_impl.h
Go to the documentation of this file.
1 /*
2  Copyright (c) 2005-2019 Intel Corporation
3 
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 
16 
17 
18 
19 */
20 
21 #ifndef __TBB__aggregator_impl_H
22 #define __TBB__aggregator_impl_H
23 
24 #include "../atomic.h"
25 #if !__TBBMALLOC_BUILD
26 #include "../tbb_profiling.h"
27 #endif
28 
29 namespace tbb {
30 namespace interface6 {
31 namespace internal {
32 
33 using namespace tbb::internal;
34 
36 template <typename Derived>
38  public:
40  uintptr_t status;
41 
42  Derived *next;
43  aggregated_operation() : status(0), next(NULL) {}
44 };
45 
47 
52 template < typename operation_type >
54 public:
55  aggregator_generic() : handler_busy(false) { pending_operations = NULL; }
56 
58 
67  template < typename handler_type >
68  void execute(operation_type *op, handler_type &handle_operations, bool long_life_time = true) {
69  operation_type *res;
70  // op->status should be read before inserting the operation into the
71  // aggregator waitlist since it can become invalid after executing a
72  // handler (if the operation has 'short' life time.)
73  const uintptr_t status = op->status;
74 
75  // ITT note: &(op->status) tag is used to cover accesses to this op node. This
76  // thread has created the operation, and now releases it so that the handler
77  // thread may handle the associated operation w/o triggering a race condition;
78  // thus this tag will be acquired just before the operation is handled in the
79  // handle_operations functor.
80  call_itt_notify(releasing, &(op->status));
81  // insert the operation in the queue.
82  do {
83  // Tools may flag the following line as a race; it is a false positive:
84  // This is an atomic read; we don't provide itt_hide_load_word for atomics
85  op->next = res = pending_operations; // NOT A RACE
86  } while (pending_operations.compare_and_swap(op, res) != res);
87  if (!res) { // first in the list; handle the operations.
88  // ITT note: &pending_operations tag covers access to the handler_busy flag,
89  // which this waiting handler thread will try to set before entering
90  // handle_operations.
91  call_itt_notify(acquired, &pending_operations);
92  start_handle_operations(handle_operations);
93  // The operation with 'short' life time can already be destroyed.
94  if (long_life_time)
95  __TBB_ASSERT(op->status, NULL);
96  }
97  // not first; wait for op to be ready.
98  else if (!status) { // operation is blocking here.
99  __TBB_ASSERT(long_life_time, "Waiting for an operation object that might be destroyed during processing.");
100  call_itt_notify(prepare, &(op->status));
101  spin_wait_while_eq(op->status, uintptr_t(0));
102  itt_load_word_with_acquire(op->status);
103  }
104  }
105 
106  private:
110  uintptr_t handler_busy;
111 
113  template < typename handler_type >
114  void start_handle_operations( handler_type &handle_operations ) {
115  operation_type *op_list;
116 
117  // ITT note: &handler_busy tag covers access to pending_operations as it is passed
118  // between active and waiting handlers. Below, the waiting handler waits until
119  // the active handler releases, and the waiting handler acquires &handler_busy as
120  // it becomes the active_handler. The release point is at the end of this
121  // function, when all operations in pending_operations have been handled by the
122  // owner of this aggregator.
123  call_itt_notify(prepare, &handler_busy);
124  // get the handler_busy:
125  // only one thread can possibly spin here at a time
126  spin_wait_until_eq(handler_busy, uintptr_t(0));
127  call_itt_notify(acquired, &handler_busy);
128  // acquire fence not necessary here due to causality rule and surrounding atomics
129  __TBB_store_with_release(handler_busy, uintptr_t(1));
130 
131  // ITT note: &pending_operations tag covers access to the handler_busy flag
132  // itself. Capturing the state of the pending_operations signifies that
133  // handler_busy has been set and a new active handler will now process that list's
134  // operations.
135  call_itt_notify(releasing, &pending_operations);
136  // grab pending_operations
137  op_list = pending_operations.fetch_and_store(NULL);
138 
139  // handle all the operations
140  handle_operations(op_list);
141 
142  // release the handler
143  itt_store_word_with_release(handler_busy, uintptr_t(0));
144  }
145 };
146 
147 template < typename handler_type, typename operation_type >
148 class aggregator : public aggregator_generic<operation_type> {
149  handler_type handle_operations;
150 public:
152  explicit aggregator(handler_type h) : handle_operations(h) {}
153 
154  void initialize_handler(handler_type h) { handle_operations = h; }
155 
156  void execute(operation_type *op) {
157  aggregator_generic<operation_type>::execute(op, handle_operations);
158  }
159 };
160 
161 // the most-compatible friend declaration (vs, gcc, icc) is
162 // template<class U, class V> friend class aggregating_functor;
163 template<typename aggregating_class, typename operation_list>
165  aggregating_class *fi;
166 public:
168  aggregating_functor(aggregating_class *fi_) : fi(fi_) {}
169  void operator()(operation_list* op_list) { fi->handle_operations(op_list); }
170 };
171 
172 } // namespace internal
173 } // namespace interface6
174 
175 namespace internal {
176  using interface6::internal::aggregated_operation;
177  using interface6::internal::aggregator_generic;
178  using interface6::internal::aggregator;
179  using interface6::internal::aggregating_functor;
180 } // namespace internal
181 
182 } // namespace tbb
183 
184 #endif // __TBB__aggregator_impl_H
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 ITT_FORMAT p void ITT_FORMAT p void size_t ITT_FORMAT d void ITT_FORMAT p const wchar_t ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s no args void ITT_FORMAT p size_t ITT_FORMAT d no args const wchar_t const wchar_t ITT_FORMAT s __itt_heap_function h
#define __TBB_ASSERT(predicate, comment)
No-op version of __TBB_ASSERT.
Definition: tbb_stddef.h:169
void itt_store_word_with_release(tbb::atomic< T > &dst, U src)
T itt_load_word_with_acquire(const tbb::atomic< T > &src)
uintptr_t handler_busy
Controls thread access to handle_operations.
The graph class.
void start_handle_operations(handler_type &handle_operations)
Trigger the handling of operations when the handler is free.
void spin_wait_while_eq(const volatile T &location, U value)
Spin WHILE the value of the variable is equal to a given value.
Definition: tbb_machine.h:395
void call_itt_notify(notify_type, void *)
void spin_wait_until_eq(const volatile T &location, const U value)
Spin UNTIL the value of the variable is equal to a given value.
Definition: tbb_machine.h:403
uintptr_t status
Zero value means "wait" status, all other values are "user" specified values and are defined into the...
atomic< operation_type * > pending_operations
An atomically updated list (aka mailbox) of pending operations.
void execute(operation_type *op, handler_type &handle_operations, bool long_life_time=true)
Execute an operation.
Identifiers declared inside namespace internal should never be used directly by client code.
Definition: atomic.h:55
void __TBB_store_with_release(volatile T &location, V value)
Definition: tbb_machine.h:717
value_type fetch_and_store(value_type value)
Definition: atomic.h:278

Copyright © 2005-2019 Intel Corporation. All Rights Reserved.

Intel, Pentium, Intel Xeon, Itanium, Intel XScale and VTune are registered trademarks or trademarks of Intel Corporation or its subsidiaries in the United States and other countries.

* Other names and brands may be claimed as the property of others.