CMS 3D CMS Logo

Callback.h
Go to the documentation of this file.
1 #ifndef FWCore_Framework_Callback_h
2 #define FWCore_Framework_Callback_h
3 // -*- C++ -*-
4 //
5 // Package: Framework
6 // Class : Callback
7 //
16 //
17 // Author: Chris Jones
18 // Created: Sun Apr 17 14:30:24 EDT 2005
19 //
20 
21 // system include files
22 #include <array>
23 #include <vector>
24 #include <type_traits>
25 #include <atomic>
26 // user include files
38 
39 namespace edm {
40  void exceptionContext(cms::Exception&, ESModuleCallingContext const&);
41 
42  namespace eventsetup {
43  class EventSetupRecordImpl;
44 
45  // The default decorator that does nothing
46  template <typename TRecord>
48  void pre(const TRecord&) {}
49  void post(const TRecord&) {}
50  };
51 
52  template <typename T, //producer's type
53  typename TReturn, //return type of the producer's method
54  typename TRecord, //the record passed in as an argument
55  typename TDecorator //allows customization using pre/post calls
56  = CallbackSimpleDecorator<TRecord>>
57  class Callback {
58  public:
59  using method_type = TReturn (T ::*)(const TRecord&);
60 
61  Callback(T* iProd, method_type iMethod, unsigned int iID, const TDecorator& iDec = TDecorator())
62  : proxyData_{},
63  producer_(iProd),
64  callingContext_(&iProd->description()),
65  method_(iMethod),
66  id_(iID),
68  decorator_(iDec) {}
69 
71 
72  Callback(const Callback&) = delete;
73  const Callback& operator=(const Callback&) = delete;
74 
76  EventSetupRecordImpl const* iRecord,
77  EventSetupImpl const* iEventSetupImpl,
78  ServiceToken const& token,
79  ESParentContext const& iParent) {
80  bool expected = false;
81  auto doPrefetch = wasCalledForThisRecord_.compare_exchange_strong(expected, true);
82  taskList_.add(iTask);
83  auto group = iTask.group();
84  if (doPrefetch) {
87  if UNLIKELY (producer_->hasMayConsumes()) {
88  //after prefetching need to do the mayGet
89  ServiceWeakToken weakToken = token;
90  auto mayGetTask = edm::make_waiting_task(
91  [this, iRecord, iEventSetupImpl, weakToken, group](std::exception_ptr const* iExcept) {
92  if (iExcept) {
93  runProducerAsync(group, iExcept, iRecord, iEventSetupImpl, weakToken.lock());
94  return;
95  }
96  if (handleMayGet(iRecord, iEventSetupImpl)) {
97  auto runTask = edm::make_waiting_task(
98  [this, group, iRecord, iEventSetupImpl, weakToken](std::exception_ptr const* iExcept) {
99  runProducerAsync(group, iExcept, iRecord, iEventSetupImpl, weakToken.lock());
100  });
102  iEventSetupImpl,
103  &((*postMayGetProxies_).front()),
104  weakToken.lock());
105  } else {
106  runProducerAsync(group, iExcept, iRecord, iEventSetupImpl, weakToken.lock());
107  }
108  });
109 
110  //Get everything we can before knowing about the mayGets
111  prefetchNeededDataAsync(WaitingTaskHolder(*group, mayGetTask), iEventSetupImpl, getTokenIndices(), token);
112  } else {
113  ServiceWeakToken weakToken = token;
115  [this, group, iRecord, iEventSetupImpl, weakToken](std::exception_ptr const* iExcept) {
116  runProducerAsync(group, iExcept, iRecord, iEventSetupImpl, weakToken.lock());
117  });
119  }
120  }
121  }
122 
123  template <class DataT>
124  void holdOntoPointer(DataT* iData) {
126  }
127 
128  void storeReturnedValues(TReturn iReturn) {
130  setData<typename type::head_type, typename type::tail_type>(iReturn);
131  }
132 
133  template <class RemainingContainerT, class DataT, class ProductsT>
134  void setData(ProductsT& iProducts) {
135  DataT* temp = reinterpret_cast<DataT*>(proxyData_[produce::find_index<TReturn, DataT>::value]);
136  if (nullptr != temp) {
137  moveFromTo(iProducts, *temp);
138  }
139  if constexpr (not std::is_same_v<produce::Null, RemainingContainerT>) {
140  setData<typename RemainingContainerT::head_type, typename RemainingContainerT::tail_type>(iProducts);
141  }
142  }
144  wasCalledForThisRecord_ = false;
145  taskList_.reset();
146  }
147 
148  unsigned int transitionID() const { return id_; }
149  ESProxyIndex const* getTokenIndices() const { return producer_->getTokenIndices(id_); }
150 
151  private:
153  EventSetupImpl const* iImpl,
154  ESProxyIndex const* proxies,
155  edm::ServiceToken const& token) const {
156  auto recs = producer_->getTokenRecordIndices(id_);
157  auto n = producer_->numberOfTokenIndices(id_);
158  for (size_t i = 0; i != n; ++i) {
159  auto rec = iImpl->findImpl(recs[i]);
160  if (rec) {
161  rec->prefetchAsync(task, proxies[i], iImpl, token, edm::ESParentContext{&callingContext_});
162  }
163  }
164  }
165 
166  bool handleMayGet(EventSetupRecordImpl const* iRecord, EventSetupImpl const* iEventSetupImpl) {
167  //Handle mayGets
168  TRecord rec;
170  rec.setImpl(iRecord, transitionID(), getTokenIndices(), iEventSetupImpl, &pc);
171  postMayGetProxies_ = producer_->updateFromMayConsumes(id_, rec);
172  return static_cast<bool>(postMayGetProxies_);
173  }
174 
175  void runProducerAsync(oneapi::tbb::task_group* iGroup,
176  std::exception_ptr const* iExcept,
177  EventSetupRecordImpl const* iRecord,
178  EventSetupImpl const* iEventSetupImpl,
179  ServiceToken const& token) {
180  if (iExcept) {
181  //The cache held by the CallbackProxy was already set to invalid at the beginning of the IOV
182  taskList_.doneWaiting(*iExcept);
183  return;
184  }
186  ServiceWeakToken weakToken = token;
187  producer_->queue().push(*iGroup, [this, iRecord, iEventSetupImpl, weakToken]() {
189  std::exception_ptr exceptPtr;
190  try {
191  convertException::wrap([this, iRecord, iEventSetupImpl, weakToken] {
192  auto proxies = getTokenIndices();
193  if (postMayGetProxies_) {
194  proxies = &((*postMayGetProxies_).front());
195  }
196  TRecord rec;
198  rec.setImpl(iRecord, transitionID(), proxies, iEventSetupImpl, &pc);
199  ServiceRegistry::Operate operate(weakToken.lock());
201  struct EndGuard {
202  EndGuard(EventSetupRecordImpl const* iRecord, ESModuleCallingContext const& iContext)
203  : record_{iRecord}, context_{iContext} {}
204  ~EndGuard() { record_->activityRegistry()->postESModuleSignal_.emit(record_->key(), context_); }
205  EventSetupRecordImpl const* record_;
206  ESModuleCallingContext const& context_;
207  };
208  EndGuard guard(iRecord, callingContext_);
209  decorator_.pre(rec);
211  decorator_.post(rec);
212  });
213  } catch (cms::Exception& iException) {
215  exceptPtr = std::current_exception();
216  }
217  taskList_.doneWaiting(exceptPtr);
218  });
219  }
220 
222  std::optional<std::vector<ESProxyIndex>> postMayGetProxies_;
227  // This transition id identifies which setWhatProduced call this Callback is associated with
228  const unsigned int id_;
229  std::atomic<bool> wasCalledForThisRecord_;
230  TDecorator decorator_;
231  };
232  } // namespace eventsetup
233 } // namespace edm
234 
235 #endif
void storeReturnedValues(TReturn iReturn)
Definition: Callback.h:128
void prefetchNeededDataAsync(WaitingTaskHolder task, EventSetupImpl const *iImpl, ESProxyIndex const *proxies, edm::ServiceToken const &token) const
Definition: Callback.h:152
void exceptionContext(cms::Exception &, ESModuleCallingContext const &)
const unsigned int id_
Definition: Callback.h:228
void prefetchAsync(WaitingTaskHolder iTask, ESProxyIndex iProxyIndex, EventSetupImpl const *, ServiceToken const &, ESParentContext) const
prefetch the data to setup for subsequent calls to getImplementation
PreESModulePrefetching preESModulePrefetchingSignal_
ESModuleCallingContext callingContext_
Definition: Callback.h:224
void holdOntoPointer(DataT *iData)
Definition: Callback.h:124
void prefetchAsync(WaitingTaskHolder iTask, EventSetupRecordImpl const *iRecord, EventSetupImpl const *iEventSetupImpl, ServiceToken const &token, ESParentContext const &iParent)
Definition: Callback.h:75
std::array< void *, produce::size< TReturn >::value > proxyData_
Definition: Callback.h:221
bool handleMayGet(EventSetupRecordImpl const *iRecord, EventSetupImpl const *iEventSetupImpl)
Definition: Callback.h:166
void reset()
Resets access to the resource so that added tasks will wait.
Callback(T *iProd, method_type iMethod, unsigned int iID, const TDecorator &iDec=TDecorator())
Definition: Callback.h:61
PostESModulePrefetching postESModulePrefetchingSignal_
constexpr element_type const * get() const
TReturn(T ::*)(const TRecord &) method_type
Definition: Callback.h:59
oneapi::tbb::task_group * group() const noexcept
void emit(Args &&... args) const
Definition: Signal.h:48
void doneWaiting(std::exception_ptr iPtr)
Signals that the resource is now available and tasks should be spawned.
unsigned int transitionID() const
Definition: Callback.h:148
void moveFromTo(FromT &iFrom, ToT &iTo)
void add(oneapi::tbb::task_group *, WaitingTask *)
Adds task to the waiting list.
FunctorWaitingTask< F > * make_waiting_task(F f)
Definition: WaitingTask.h:92
ESProxyIndex const * getTokenIndices() const
Definition: Callback.h:149
std::atomic< bool > wasCalledForThisRecord_
Definition: Callback.h:229
ServiceToken lock() const
Definition: ServiceToken.h:101
edm::WaitingTaskList taskList_
Definition: Callback.h:225
void runProducerAsync(oneapi::tbb::task_group *iGroup, std::exception_ptr const *iExcept, EventSetupRecordImpl const *iRecord, EventSetupImpl const *iEventSetupImpl, ServiceToken const &token)
Definition: Callback.h:175
EventSetupRecordKey const & key() const
Callback * clone()
Definition: Callback.h:70
PreESModule preESModuleSignal_
void setContext(State state, ESParentContext const &parent)
std::optional< std::vector< ESProxyIndex > > postMayGetProxies_
Definition: Callback.h:222
void setData(ProductsT &iProducts)
Definition: Callback.h:134
HLT enums.
const Callback & operator=(const Callback &)=delete
auto wrap(F iFunc) -> decltype(iFunc())
#define UNLIKELY(x)
Definition: Likely.h:21
edm::propagate_const< T * > producer_
Definition: Callback.h:223
long double T
eventsetup::EventSetupRecordImpl const * findImpl(const eventsetup::EventSetupRecordKey &) const
ActivityRegistry const * activityRegistry() const noexcept