2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
5 * @file AthenaKernel/RCUObject.icc
6 * @author scott snyder <snyder@bnl.gov>
8 * @brief read-copy-update (RCU) style synchronization for Athena.
16 * @brief Declare the current event slot of this object to be quiescent.
18 * This will take out a lock and possibly trigger object cleanup.
21 void IRCUObject::quiescent()
23 quiescent (Gaudi::Hive::currentContext());
28 * @brief Declare the event slot @c ctx of this object to be quiescent.
29 * @param ctx The event context.
31 * This will take out a lock and possibly trigger object cleanup.
34 void IRCUObject::quiescent (const EventContext& ctx)
43 * @brief Return the mutex for this object.
46 typename IRCUObject::mutex_t& IRCUObject::mutex()
52 //*************************************************************************
56 * @brief Constructor, with RCUSvc.
57 * @param svc Service with which to register.
58 * @param args... Additional arguments to pass to the @c T constructor.
60 * The service will call @c quiescent at the end of each event.
63 template <typename... Args>
65 RCUObject<T>::RCUObject (IRCUSvc& svc, Args&&... args)
67 m_objref (std::make_unique<T>(std::forward<Args>(args)...)),
68 m_obj (m_objref.get())
74 * @brief Constructor, with number of slots.
75 * @param nslots Number of event slots.
76 * @param args... Additional arguments to pass to the @c T constructor.
79 template <typename... Args>
81 RCUObject<T>::RCUObject (size_t nslots, Args&&... args)
82 : IRCUObject (nslots),
83 m_objref (std::make_unique<T>(std::forward<Args>(args)...)),
84 m_obj (m_objref.get())
90 * @brief Constructor, with RCUSvc.
91 * @param svc Service with which to register.
93 * The service will call @c quiescent at the end of each event.
94 * No current object will be created.
98 RCUObject<T>::RCUObject (IRCUSvc& svc, NoObjectEnum)
107 * @brief Move constructor.
109 * Allow passing these objects via move.
112 RCUObject<T>::RCUObject (RCUObject&& other)
113 : IRCUObject (std::move (other)),
114 m_objref (std::move (other.m_objref)),
115 m_obj (static_cast<const T*> (other.m_obj)),
116 m_garbage (std::move (other.m_garbage))
118 other.m_obj = nullptr;
123 * @brief Return a reader for this @c RCUObject.
127 typename RCUObject<T>::Read_t RCUObject<T>::reader() const
129 return Read_t (*this);
134 * @brief Return a reader for this @c RCUObject.
135 * When destroyed, this reader will declare
136 * the @c RCUObject as quiescent
138 * This version will read the global event context.
142 typename RCUObject<T>::ReadQuiesce_t RCUObject<T>::readerQuiesce()
144 return ReadQuiesce_t (*this);
149 * @brief Return a reader for this @c RCUObject.
150 * When destroyed, this reader will declare
151 * the @c RCUObject as quiescent
152 * @param ctx The event context.
156 typename RCUObject<T>::ReadQuiesce_t
157 RCUObject<T>::readerQuiesce (const EventContext& ctx)
159 return ReadQuiesce_t (*this, ctx);
164 * @brief Return an updater for this @c RCUObject.
166 * This version will read the global event context.
170 typename RCUObject<T>::Update_t RCUObject<T>::updater()
172 return Update_t (*this);
177 * @brief Return an updater for this @c RCUObject.
179 * This version will read the global event context.
183 typename RCUObject<T>::Update_t
184 RCUObject<T>::updater (const EventContext& ctx)
186 return Update_t (*this, ctx);
191 * @brief Queue an object for later deletion.
192 * @param p The object to delete.
194 * The object @c p will be queued for deletion once a grace period
195 * has passed for all slots. In contrast to using @c updater,
196 * this does not change the current object. It also does not mark
197 * the current slot as having completed the grace period (so this can
198 * be called by a thread running outside of a slot context).
201 void RCUObject<T>::discard (std::unique_ptr<const T> p)
204 discard (g, std::move (p));
209 * @brief Queue an object for later deletion.
210 * @param lock Lock object (external locking).
211 * @param p The object to delete.
214 void RCUObject<T>::discard (lock_t& lock, std::unique_ptr<const T> p)
216 makeOld (lock, m_garbage.size());
217 m_garbage.push_front (std::move (p));
223 * @brief Delete all objects.
224 * @param Lock object (external locking).
226 * The caller must be holding the mutex for this object.
230 void RCUObject<T>::clearAll (lock_t& /*lock*/)
237 * @brief Delete old objects.
238 * @param Lock object (external locking).
239 * @param nold Number of old objects to delete.
241 * The caller must be holding the mutex for this object.
242 * Returns true if there are no more objects pending deletion.
246 bool RCUObject<T>::clearOld (lock_t& /*lock*/, size_t nold)
249 m_garbage.pop_back();
252 return m_garbage.empty();
256 //*************************************************************************
260 * @brief Constructor.
261 * @param rcuobj The @c RCUObject we're reading.
265 RCURead<T>::RCURead (const RCUObject<T>& rcuobj)
266 : m_obj (rcuobj.m_obj)
272 * @brief Access data.
276 const T& RCURead<T>::operator*() const
283 * @brief Access data.
287 const T* RCURead<T>::operator->() const
293 //*************************************************************************
297 * @brief Constructor.
298 * @param rcuobj The @c RCUObject we're reading.
300 * This version will read the global event context.
304 RCUReadQuiesce<T>::RCUReadQuiesce (RCUObject<T>& rcuobj)
305 : RCURead<T> (rcuobj),
307 m_ctx (Gaudi::Hive::currentContext())
313 * @brief Constructor.
314 * @param rcuobj The @c RCUObject we're reading.
315 * @param ctx The event context.
319 RCUReadQuiesce<T>::RCUReadQuiesce (RCUObject<T>& rcuobj,
320 const EventContext& ctx)
321 : RCURead<T> (rcuobj),
331 * Mark this event slot quiescent.
335 RCUReadQuiesce<T>::~RCUReadQuiesce()
337 m_rcuobj.quiescent (m_ctx);
341 //*************************************************************************
345 * @brief Constructor.
346 * @param rcuobj The @c RCUObject we're reading.
348 * This version will read the global event context.
352 RCUUpdate<T>::RCUUpdate (RCUObject<T>& rcuobj)
354 m_ctx (Gaudi::Hive::currentContext()),
361 * @brief Constructor.
362 * @param rcuobj The @c RCUObject we're reading.
363 * @param ctx The event context.
367 RCUUpdate<T>::RCUUpdate (RCUObject<T>& rcuobj, const EventContext& ctx)
376 * @brief Access data.
380 const T& RCUUpdate<T>::operator*() const
382 return *m_rcuobj.m_obj;
387 * @brief Access data.
391 const T* RCUUpdate<T>::operator->() const
393 return m_rcuobj.m_obj;
398 * @brief Publish a new version of the data object.
399 * @param ptr The new data object.
402 void RCUUpdate<T>::update (std::unique_ptr<T> ptr)
404 // Queue the current object for deletion, if it exists.
405 if (m_rcuobj.m_objref) {
406 m_rcuobj.discard (m_g, std::move (m_rcuobj.m_objref));
409 // Install the new object.
410 m_rcuobj.m_objref = std::move (ptr);
411 m_rcuobj.m_obj = m_rcuobj.m_objref.get();
413 // Go ahead and end the grace period for the current slot.
414 m_rcuobj.endGrace(m_g, m_ctx);
418 } // namespace Athena