ATLAS Offline Software
Loading...
Searching...
No Matches
RCUObject.icc
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4/**
5 * @file AthenaKernel/RCUObject.icc
6 * @author scott snyder <snyder@bnl.gov>
7 * @date Aug, 2016
8 * @brief read-copy-update (RCU) style synchronization for Athena.
9 */
10
11
12namespace Athena {
13
14
15/**
16 * @brief Declare the current event slot of this object to be quiescent.
17 *
18 * This will take out a lock and possibly trigger object cleanup.
19 */
20inline
21void IRCUObject::quiescent()
22{
23 quiescent (Gaudi::Hive::currentContext());
24}
25
26
27/**
28 * @brief Declare the event slot @c ctx of this object to be quiescent.
29 * @param ctx The event context.
30 *
31 * This will take out a lock and possibly trigger object cleanup.
32 */
33inline
34void IRCUObject::quiescent (const EventContext& ctx)
35{
36 if (m_dirty) {
37 quiescentOol (ctx);
38 }
39}
40
41
42/**
43 * @brief Return the mutex for this object.
44 */
45inline
46typename IRCUObject::mutex_t& IRCUObject::mutex()
47{
48 return m_mutex;
49}
50
51
52//*************************************************************************
53
54
55/**
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.
59 *
60 * The service will call @c quiescent at the end of each event.
61 */
62template <class T>
63template <typename... Args>
64inline
65RCUObject<T>::RCUObject (IRCUSvc& svc, Args&&... args)
66 : IRCUObject (svc),
67 m_objref (std::make_unique<T>(std::forward<Args>(args)...)),
68 m_obj (m_objref.get())
69{
70}
71
72
73/**
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.
77 */
78template <class T>
79template <typename... Args>
80inline
81RCUObject<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())
85{
86}
87
88
89/**
90 * @brief Constructor, with RCUSvc.
91 * @param svc Service with which to register.
92 *
93 * The service will call @c quiescent at the end of each event.
94 * No current object will be created.
95 */
96template <class T>
97inline
98RCUObject<T>::RCUObject (IRCUSvc& svc, NoObjectEnum)
99 : IRCUObject (svc),
100 m_objref(),
101 m_obj (nullptr)
102{
103}
104
105
106/**
107 * @brief Move constructor.
108 *
109 * Allow passing these objects via move.
110 */
111template <class T>
112RCUObject<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))
117{
118 other.m_obj = nullptr;
119}
120
121
122/**
123 * @brief Return a reader for this @c RCUObject.
124 */
125template <class T>
126inline
127typename RCUObject<T>::Read_t RCUObject<T>::reader() const
128{
129 return Read_t (*this);
130}
131
132
133/**
134 * @brief Return a reader for this @c RCUObject.
135 * When destroyed, this reader will declare
136 * the @c RCUObject as quiescent
137 *
138 * This version will read the global event context.
139 */
140template <class T>
141inline
142typename RCUObject<T>::ReadQuiesce_t RCUObject<T>::readerQuiesce()
143{
144 return ReadQuiesce_t (*this);
145}
146
147
148/**
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.
153 */
154template <class T>
155inline
156typename RCUObject<T>::ReadQuiesce_t
157RCUObject<T>::readerQuiesce (const EventContext& ctx)
158{
159 return ReadQuiesce_t (*this, ctx);
160}
161
162
163/**
164 * @brief Return an updater for this @c RCUObject.
165 *
166 * This version will read the global event context.
167 */
168template <class T>
169inline
170typename RCUObject<T>::Update_t RCUObject<T>::updater()
171{
172 return Update_t (*this);
173}
174
175
176/**
177 * @brief Return an updater for this @c RCUObject.
178 *
179 * This version will read the global event context.
180 */
181template <class T>
182inline
183typename RCUObject<T>::Update_t
184RCUObject<T>::updater (const EventContext& ctx)
185{
186 return Update_t (*this, ctx);
187}
188
189
190/**
191 * @brief Queue an object for later deletion.
192 * @param p The object to delete.
193 *
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).
199 */
200template <class T>
201void RCUObject<T>::discard (std::unique_ptr<const T> p)
202{
203 lock_t g (mutex());
204 discard (g, std::move (p));
205}
206
207
208/**
209 * @brief Queue an object for later deletion.
210 * @param lock Lock object (external locking).
211 * @param p The object to delete.
212 */
213template <class T>
214void RCUObject<T>::discard (lock_t& lock, std::unique_ptr<const T> p)
215{
216 makeOld (lock, m_garbage.size());
217 m_garbage.push_front (std::move (p));
218 setGrace (lock);
219}
220
221
222/**
223 * @brief Delete all objects.
224 * @param Lock object (external locking).
225 *
226 * The caller must be holding the mutex for this object.
227 */
228template <class T>
229inline
230void RCUObject<T>::clearAll (lock_t& /*lock*/)
231{
232 m_garbage.clear();
233}
234
235
236/**
237 * @brief Delete old objects.
238 * @param Lock object (external locking).
239 * @param nold Number of old objects to delete.
240 *
241 * The caller must be holding the mutex for this object.
242 * Returns true if there are no more objects pending deletion.
243 */
244template <class T>
245inline
246bool RCUObject<T>::clearOld (lock_t& /*lock*/, size_t nold)
247{
248 while (nold > 0) {
249 m_garbage.pop_back();
250 --nold;
251 }
252 return m_garbage.empty();
253}
254
255
256//*************************************************************************
257
258
259/**
260 * @brief Constructor.
261 * @param rcuobj The @c RCUObject we're reading.
262 */
263template <class T>
264inline
265RCURead<T>::RCURead (const RCUObject<T>& rcuobj)
266 : m_obj (rcuobj.m_obj)
267{
268}
269
270
271/**
272 * @brief Access data.
273 */
274template <class T>
275inline
276const T& RCURead<T>::operator*() const
277{
278 return *m_obj;
279}
280
281
282/**
283 * @brief Access data.
284 */
285template <class T>
286inline
287const T* RCURead<T>::operator->() const
288{
289 return m_obj;
290}
291
292
293//*************************************************************************
294
295
296/**
297 * @brief Constructor.
298 * @param rcuobj The @c RCUObject we're reading.
299 *
300 * This version will read the global event context.
301 */
302template <class T>
303inline
304RCUReadQuiesce<T>::RCUReadQuiesce (RCUObject<T>& rcuobj)
305 : RCURead<T> (rcuobj),
306 m_rcuobj (rcuobj),
307 m_ctx (Gaudi::Hive::currentContext())
308{
309}
310
311
312/**
313 * @brief Constructor.
314 * @param rcuobj The @c RCUObject we're reading.
315 * @param ctx The event context.
316 */
317template <class T>
318inline
319RCUReadQuiesce<T>::RCUReadQuiesce (RCUObject<T>& rcuobj,
320 const EventContext& ctx)
321 : RCURead<T> (rcuobj),
322 m_rcuobj (rcuobj),
323 m_ctx (ctx)
324{
325}
326
327
328/**
329 * @brief Destructor.
330 *
331 * Mark this event slot quiescent.
332 */
333template <class T>
334inline
335RCUReadQuiesce<T>::~RCUReadQuiesce()
336{
337 m_rcuobj.quiescent (m_ctx);
338}
339
340
341//*************************************************************************
342
343
344/**
345 * @brief Constructor.
346 * @param rcuobj The @c RCUObject we're reading.
347 *
348 * This version will read the global event context.
349 */
350template <class T>
351inline
352RCUUpdate<T>::RCUUpdate (RCUObject<T>& rcuobj)
353 : m_rcuobj (rcuobj),
354 m_ctx (Gaudi::Hive::currentContext()),
355 m_g (rcuobj.mutex())
356{
357}
358
359
360/**
361 * @brief Constructor.
362 * @param rcuobj The @c RCUObject we're reading.
363 * @param ctx The event context.
364 */
365template <class T>
366inline
367RCUUpdate<T>::RCUUpdate (RCUObject<T>& rcuobj, const EventContext& ctx)
368 : m_rcuobj (rcuobj),
369 m_ctx (ctx),
370 m_g (rcuobj.mutex())
371{
372}
373
374
375/**
376 * @brief Access data.
377 */
378template <class T>
379inline
380const T& RCUUpdate<T>::operator*() const
381{
382 return *m_rcuobj.m_obj;
383}
384
385
386/**
387 * @brief Access data.
388 */
389template <class T>
390inline
391const T* RCUUpdate<T>::operator->() const
392{
393 return m_rcuobj.m_obj;
394}
395
396
397/**
398 * @brief Publish a new version of the data object.
399 * @param ptr The new data object.
400 */
401template <class T>
402void RCUUpdate<T>::update (std::unique_ptr<T> ptr)
403{
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));
407 }
408
409 // Install the new object.
410 m_rcuobj.m_objref = std::move (ptr);
411 m_rcuobj.m_obj = m_rcuobj.m_objref.get();
412
413 // Go ahead and end the grace period for the current slot.
414 m_rcuobj.endGrace(m_g, m_ctx);
415}
416
417
418} // namespace Athena