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 <vector>
23 #include <type_traits>
24 #include <atomic>
25 // user include files
37 
38 namespace edm {
39  void exceptionContext(cms::Exception&, ESModuleCallingContext const&);
40 
41  namespace eventsetup {
42  class EventSetupRecordImpl;
43 
44  // The default decorator that does nothing
45  template <typename TRecord>
47  void pre(const TRecord&) {}
48  void post(const TRecord&) {}
49  };
50 
51  template <typename T, //producer's type
52  typename TReturn, //return type of the producer's method
53  typename TRecord, //the record passed in as an argument
54  typename TDecorator //allows customization using pre/post calls
55  = CallbackSimpleDecorator<TRecord>>
56  class Callback {
57  public:
58  using method_type = TReturn (T ::*)(const TRecord&);
59 
60  Callback(T* iProd, method_type iMethod, unsigned int iID, const TDecorator& iDec = TDecorator())
61  : proxyData_{},
62  producer_(iProd),
63  callingContext_(&iProd->description()),
64  method_(iMethod),
65  id_(iID),
67  decorator_(iDec) {}
68 
70 
71  Callback(const Callback&) = delete;
72  const Callback& operator=(const Callback&) = delete;
73 
75  EventSetupRecordImpl const* iRecord,
76  EventSetupImpl const* iEventSetupImpl,
77  ServiceToken const& token,
78  ESParentContext const& iParent) {
79  bool expected = false;
80  auto doPrefetch = wasCalledForThisRecord_.compare_exchange_strong(expected, true);
81  taskList_.add(iTask);
82  auto group = iTask.group();
83  if (doPrefetch) {
86  if UNLIKELY (producer_->hasMayConsumes()) {
87  //after prefetching need to do the mayGet
88  ServiceWeakToken weakToken = token;
89  auto mayGetTask = edm::make_waiting_task(
90  [this, iRecord, iEventSetupImpl, weakToken, group](std::exception_ptr const* iExcept) {
91  if (iExcept) {
92  runProducerAsync(group, iExcept, iRecord, iEventSetupImpl, weakToken.lock());
93  return;
94  }
95  if (handleMayGet(iRecord, iEventSetupImpl)) {
96  auto runTask = edm::make_waiting_task(
97  [this, group, iRecord, iEventSetupImpl, weakToken](std::exception_ptr const* iExcept) {
98  runProducerAsync(group, iExcept, iRecord, iEventSetupImpl, weakToken.lock());
99  });
101  iEventSetupImpl,
102  &((*postMayGetProxies_).front()),
103  weakToken.lock());
104  } else {
105  runProducerAsync(group, iExcept, iRecord, iEventSetupImpl, weakToken.lock());
106  }
107  });
108 
109  //Get everything we can before knowing about the mayGets
110  prefetchNeededDataAsync(WaitingTaskHolder(*group, mayGetTask), iEventSetupImpl, getTokenIndices(), token);
111  } else {
112  ServiceWeakToken weakToken = token;
114  [this, group, iRecord, iEventSetupImpl, weakToken](std::exception_ptr const* iExcept) {
115  runProducerAsync(group, iExcept, iRecord, iEventSetupImpl, weakToken.lock());
116  });
118  }
119  }
120  }
121 
122  template <class DataT>
123  void holdOntoPointer(DataT* iData) {
125  }
126 
127  void storeReturnedValues(TReturn iReturn) {
129  setData<typename type::head_type, typename type::tail_type>(iReturn);
130  }
131 
132  template <class RemainingContainerT, class DataT, class ProductsT>
133  void setData(ProductsT& iProducts) {
134  DataT* temp = reinterpret_cast<DataT*>(proxyData_[produce::find_index<TReturn, DataT>::value]);
135  if (nullptr != temp) {
136  moveFromTo(iProducts, *temp);
137  }
138  if constexpr (not std::is_same_v<produce::Null, RemainingContainerT>) {
139  setData<typename RemainingContainerT::head_type, typename RemainingContainerT::tail_type>(iProducts);
140  }
141  }
143  wasCalledForThisRecord_ = false;
144  taskList_.reset();
145  }
146 
147  unsigned int transitionID() const { return id_; }
148  ESProxyIndex const* getTokenIndices() const { return producer_->getTokenIndices(id_); }
149 
150  private:
152  EventSetupImpl const* iImpl,
153  ESProxyIndex const* proxies,
154  edm::ServiceToken const& token) const {
155  auto recs = producer_->getTokenRecordIndices(id_);
156  auto n = producer_->numberOfTokenIndices(id_);
157  for (size_t i = 0; i != n; ++i) {
158  auto rec = iImpl->findImpl(recs[i]);
159  if (rec) {
160  rec->prefetchAsync(task, proxies[i], iImpl, token, edm::ESParentContext{&callingContext_});
161  }
162  }
163  }
164 
165  bool handleMayGet(EventSetupRecordImpl const* iRecord, EventSetupImpl const* iEventSetupImpl) {
166  //Handle mayGets
167  TRecord rec;
169  rec.setImpl(iRecord, transitionID(), getTokenIndices(), iEventSetupImpl, &pc);
170  postMayGetProxies_ = producer_->updateFromMayConsumes(id_, rec);
171  return static_cast<bool>(postMayGetProxies_);
172  }
173 
174  void runProducerAsync(oneapi::tbb::task_group* iGroup,
175  std::exception_ptr const* iExcept,
176  EventSetupRecordImpl const* iRecord,
177  EventSetupImpl const* iEventSetupImpl,
178  ServiceToken const& token) {
179  if (iExcept) {
180  //The cache held by the CallbackProxy was already set to invalid at the beginning of the IOV
181  taskList_.doneWaiting(*iExcept);
182  return;
183  }
185  ServiceWeakToken weakToken = token;
186  producer_->queue().push(*iGroup, [this, iRecord, iEventSetupImpl, weakToken]() {
188  std::exception_ptr exceptPtr;
189  try {
190  convertException::wrap([this, iRecord, iEventSetupImpl, weakToken] {
191  auto proxies = getTokenIndices();
192  if (postMayGetProxies_) {
193  proxies = &((*postMayGetProxies_).front());
194  }
195  TRecord rec;
197  rec.setImpl(iRecord, transitionID(), proxies, iEventSetupImpl, &pc);
198  ServiceRegistry::Operate operate(weakToken.lock());
200  struct EndGuard {
201  EndGuard(EventSetupRecordImpl const* iRecord, ESModuleCallingContext const& iContext)
202  : record_{iRecord}, context_{iContext} {}
203  ~EndGuard() { record_->activityRegistry()->postESModuleSignal_.emit(record_->key(), context_); }
204  EventSetupRecordImpl const* record_;
205  ESModuleCallingContext const& context_;
206  };
207  EndGuard guard(iRecord, callingContext_);
208  decorator_.pre(rec);
210  decorator_.post(rec);
211  });
212  } catch (cms::Exception& iException) {
214  exceptPtr = std::current_exception();
215  }
216  taskList_.doneWaiting(exceptPtr);
217  });
218  }
219 
221  std::optional<std::vector<ESProxyIndex>> postMayGetProxies_;
226  // This transition id identifies which setWhatProduced call this Callback is associated with
227  const unsigned int id_;
228  std::atomic<bool> wasCalledForThisRecord_;
229  TDecorator decorator_;
230  };
231  } // namespace eventsetup
232 } // namespace edm
233 
234 #endif
void storeReturnedValues(TReturn iReturn)
Definition: Callback.h:127
void prefetchNeededDataAsync(WaitingTaskHolder task, EventSetupImpl const *iImpl, ESProxyIndex const *proxies, edm::ServiceToken const &token) const
Definition: Callback.h:151
void exceptionContext(cms::Exception &, ESModuleCallingContext const &)
const unsigned int id_
Definition: Callback.h:227
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:223
void holdOntoPointer(DataT *iData)
Definition: Callback.h:123
void prefetchAsync(WaitingTaskHolder iTask, EventSetupRecordImpl const *iRecord, EventSetupImpl const *iEventSetupImpl, ServiceToken const &token, ESParentContext const &iParent)
Definition: Callback.h:74
std::array< void *, produce::size< TReturn >::value > proxyData_
Definition: Callback.h:220
bool handleMayGet(EventSetupRecordImpl const *iRecord, EventSetupImpl const *iEventSetupImpl)
Definition: Callback.h:165
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:60
PostESModulePrefetching postESModulePrefetchingSignal_
constexpr element_type const * get() const
TReturn(T ::*)(const TRecord &) method_type
Definition: Callback.h:58
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:147
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:101
ESProxyIndex const * getTokenIndices() const
Definition: Callback.h:148
std::atomic< bool > wasCalledForThisRecord_
Definition: Callback.h:228
ServiceToken lock() const
Definition: ServiceToken.h:101
edm::WaitingTaskList taskList_
Definition: Callback.h:224
void runProducerAsync(oneapi::tbb::task_group *iGroup, std::exception_ptr const *iExcept, EventSetupRecordImpl const *iRecord, EventSetupImpl const *iEventSetupImpl, ServiceToken const &token)
Definition: Callback.h:174
EventSetupRecordKey const & key() const
Callback * clone()
Definition: Callback.h:69
PreESModule preESModuleSignal_
void setContext(State state, ESParentContext const &parent)
std::optional< std::vector< ESProxyIndex > > postMayGetProxies_
Definition: Callback.h:221
void setData(ProductsT &iProducts)
Definition: Callback.h:133
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:222
long double T
eventsetup::EventSetupRecordImpl const * findImpl(const eventsetup::EventSetupRecordKey &) const
ActivityRegistry const * activityRegistry() const noexcept