1//
2// RefCountedObject.h
3//
4// Library: Foundation
5// Package: Core
6// Module: RefCountedObject
7//
8// Definition of the RefCountedObject class.
9//
10// Copyright (c) 2004-2009, Applied Informatics Software Engineering GmbH.
11// and Contributors.
12//
13// SPDX-License-Identifier: BSL-1.0
14//
15
16
17#ifndef Foundation_RefCountedObject_INCLUDED
18#define Foundation_RefCountedObject_INCLUDED
19
20
21#include "Poco/Foundation.h"
22#include "Poco/MemoryPool.h"
23#include "Poco/Mutex.h"
24#include <atomic>
25
26
27#if defined(_DEBUG) && defined(POCO_REFCOUNT_DC)
28#define ENABLE_REFCOUNT_DC
29#endif
30
31
32#ifdef ENABLE_REFCOUNT_DC
33
34#include "Poco/NestedDiagnosticContext.h"
35#include "Poco/OrderedMap.h"
36#include "Poco/Mutex.h"
37
38
39namespace Poco {
40
41
42//
43// RefCountDiagnosticContext
44//
45
46class Foundation_API RefCountDiagnosticContext
47 /// This utility class is used for debugging and testing purposes
48 /// of the reference counting functionality and should not be used
49 /// for any other purpose. it is enabled only for debug builds and
50 /// if POCO_REFCOUNT_DC macro is defined in Config.h.
51 ///
52 /// See poco_rcdc_* set of macros below for explanation how it is used.
53{
54public:
55 class TraceRecord
56 {
57 public:
58 TraceRecord(void *ptr, int refCount, const char* func, const std::string &backtrace = "");
59 TraceRecord(const TraceRecord& other);
60 TraceRecord(TraceRecord&& other);
61 TraceRecord& operator == (const TraceRecord& other);
62 TraceRecord& operator == (TraceRecord&& other);
63
64 private:
65 TraceRecord();
66
67 void* _ptr = 0;
68 int _refCount = 0;
69 std::string _functionName;
70 std::string _backtrace;
71
72 friend class RefCountDiagnosticContext;
73 };
74
75 typedef OrderedMap<void*, std::vector<TraceRecord>> TraceMap;
76
77 RefCountDiagnosticContext(bool full = false);
78 ~RefCountDiagnosticContext();
79
80 void addEntry(TraceRecord&& record) const;
81 void dumpRef(std::ostream &os, bool leakOnly = true) const;
82 void dumpAllRef(std::ostream &os) const;
83 void dumpLeakRef(std::ostream &os) const;
84 void clear() const;
85
86 // definition in Foundation.cpp
87 static RefCountDiagnosticContext& get();
88
89private:
90 RefCountDiagnosticContext(const RefCountDiagnosticContext&) = delete;
91 RefCountDiagnosticContext& operator = (const RefCountDiagnosticContext&) = delete;
92 RefCountDiagnosticContext(RefCountDiagnosticContext&&) = delete;
93 RefCountDiagnosticContext& operator = (RefCountDiagnosticContext&&) = delete;
94
95 static TraceMap& traceMap() { return _traceMap; }
96
97 // definitions in Foundation.cpp
98 static TraceMap _traceMap;
99 static SpinlockMutex _mutex;
100 static bool _full;
101};
102
103
104//
105// inlines
106//
107
108inline void RefCountDiagnosticContext::addEntry(TraceRecord&& record) const
109{
110 SpinlockMutex::ScopedLock l(_mutex);
111 traceMap()[record._ptr].emplace_back(std::move(record));
112}
113
114
115inline void RefCountDiagnosticContext::dumpAllRef(std::ostream& os) const
116{
117 dumpRef(os, false);
118 if (!_full)
119 {
120 os << std::endl;
121 os << "Full dump requested but not recorded, leaks only (if any) displayed.";
122 os << std::endl;
123 }
124}
125
126
127inline void RefCountDiagnosticContext::dumpLeakRef(std::ostream& os) const
128{
129 dumpRef(os, true);
130}
131
132
133inline void RefCountDiagnosticContext::clear() const
134{
135 SpinlockMutex::ScopedLock l(_mutex);
136 traceMap().clear();
137}
138
139
140typedef RefCountDiagnosticContext RCDC;
141
142
143} // namespace Poco
144
145
146// Diagnostic utility macros for tracing and managing records of refcount increments/decrements.
147// To trim stack backtrace entries from beginning or end, adjust parameters to NDC::backTrace()
148// below. Usable only for classes that inherit from [Weak]RefCountedObject.
149//
150// Note: since access to the internal RefCountDiagnosticContext (static) storage is protected
151// by a static mutex, using this functionality partially disables the multi-threaded nature
152// of RefCounted access, so it should never be permanently enabled in code, but used as a
153// temporary reference counting troubleshooting tool (compile debug, with POCO_REFCOUNT_DC in
154// Config.h defined to enable/disable this functionality).
155//
156// Backtrace works only with g++ at this time; without it this functionality is of limited use.
157// Disabled by default for all builds and always (even if POCO_REFCOUNT_DC is defined) disabled
158// for non-debug builds.
159
160#define poco_rcdc_log RCDC::get().addEntry(RCDC::TraceRecord((void*)this, _counter, __func__, NDC::backtrace(1, 7)))
161
162#define poco_rcdc_dump_leak(os) RCDC::get().dumpLeakRef(os)
163
164#define poco_rcdc_dump_all(os) RCDC::get().dumpAllRef(os)
165
166#define poco_rcdc_reset RCDC::get().clear();
167
168#else // !ENABLE_REFCOUNT_DC
169
170
171namespace Poco { typedef void RCDC; }
172
173#define poco_rcdc_log
174#define poco_rcdc_dump_leak(os)
175#define poco_rcdc_dump_all(os)
176#define poco_rcdc_reset
177
178#endif // ENABLE_REFCOUNT_DC
179
180
181namespace Poco {
182
183
184//
185// RefCountedObject
186//
187
188
189class RefCounter
190 /// A class for thread-safe atomic reference counting.
191{
192public:
193 RefCounter();
194 /// Creates RefCounter.
195
196 ~RefCounter();
197 /// Destroys RefCounter.
198
199 int operator++ ();
200 /// Prefix increment.
201
202 int operator++ (int);
203 /// Postfix increment.
204
205 int operator-- ();
206 /// Prefix decrement.
207
208 int operator-- (int);
209 /// Postfix decrement.
210
211 operator int();
212 /// Returns the current value as int.
213
214private:
215 RefCounter(const RefCounter&) = delete;
216 RefCounter(RefCounter&&) = delete;
217 RefCounter& operator = (const RefCounter&) = delete;
218 RefCounter& operator = (RefCounter&&) = delete;
219
220 mutable std::atomic<int> _counter;
221};
222
223//
224// inlines
225//
226
227inline int RefCounter::operator++()
228{
229#ifdef ENABLE_REFCOUNT_DC
230 int c = _counter.fetch_add(1, std::memory_order_relaxed) + 1;
231 poco_rcdc_log;
232 return c;
233#endif
234 return _counter.fetch_add(1, std::memory_order_relaxed) + 1;
235}
236
237
238inline int RefCounter::operator++(int)
239{
240#ifdef ENABLE_REFCOUNT_DC
241 int c = _counter.fetch_add(1, std::memory_order_relaxed);
242 poco_rcdc_log;
243 return c;
244#endif
245 return _counter.fetch_add(1, std::memory_order_relaxed);
246}
247
248
249inline int RefCounter::operator--()
250{
251#ifdef ENABLE_REFCOUNT_DC
252 int c = _counter.fetch_sub(1, std::memory_order_acquire) - 1;
253 poco_rcdc_log;
254 return c;
255#endif
256 return _counter.fetch_sub(1, std::memory_order_acquire) - 1;
257}
258
259
260inline int RefCounter::operator--(int)
261{
262#ifdef ENABLE_REFCOUNT_DC
263 int c = _counter.fetch_sub(1, std::memory_order_acquire);
264 poco_rcdc_log;
265 return c;
266#endif
267 return _counter.fetch_sub(1, std::memory_order_acquire);
268}
269
270
271inline RefCounter::operator int()
272{
273 return _counter;
274}
275
276
277//
278// RefCountedObject
279//
280
281class Foundation_API RefCountedObject
282 /// A class for thread-safe strong reference counting.
283 ///
284 /// It maintains the reference count, and deletes itself
285 /// when the count reaches zero; it follows that a
286 /// RefCountedObject must always be created on the heap.
287{
288public:
289 RefCountedObject();
290 /// Creates RefCountedObject
291
292 void duplicate() const;
293 /// Increments the reference counter.
294
295 void release();
296 /// Decrements the reference counter.
297 /// If counter value after decrement is zero,
298 /// this object is deleted.
299
300 int referenceCount() const;
301 /// Returns the reference count.
302
303protected:
304 virtual ~RefCountedObject();
305 /// Destroys RefCountedObject
306
307private:
308 RefCountedObject(const RefCountedObject&) = delete;
309 RefCountedObject(RefCountedObject&&) = delete;
310 RefCountedObject& operator = (const RefCountedObject&) = delete;
311 RefCountedObject& operator = (RefCountedObject&&) = delete;
312
313 mutable RefCounter _counter;
314
315 friend class RefCountDiagnosticContext;
316};
317
318//
319// inlines
320//
321
322inline void RefCountedObject::duplicate() const
323{
324 _counter++;
325}
326
327
328inline void RefCountedObject::release()
329{
330 if (--_counter == 0) delete this;
331}
332
333
334inline int RefCountedObject::referenceCount() const
335{
336 return _counter;
337}
338
339
340typedef RefCountedObject RCO;
341
342
343//
344// WeakRefCounter
345//
346
347
348// global memory pool for weak counters;
349// see definition in Foundation.cpp
350template<typename T>
351extern FastMemoryPool<T>& getFastMemoryPool();
352
353
354class Foundation_API WeakRefCounter
355 /// A class for thread-safe strong and weak reference
356 /// counting.
357 ///
358 /// WeakRefCounter is created on the heap from WeakRefCountedObject
359 /// and may outlive the WeakRefCountedObject that created it.
360 /// It maintains two reference counts, "strong" and "weak"; deletes
361 /// itself when both counts reach zero. This is the only reference
362 /// counting facility accessed by WeakRefPtr.
363 ///
364 /// Note: this class has a very specific library-internal purpose;
365 /// it is not meant for general use.
366{
367public:
368 WeakRefCounter();
369 /// Creates WeakRefCounter.
370
371 void duplicate();
372 /// Increments strong counter.
373
374 int release();
375 /// Decrements strong counter.
376 /// If, after decrement, both strong and weak
377 /// counters are zero, it deletes this object.
378
379 WeakRefCounter* duplicateWeak();
380 /// Increments weak counter.
381
382 WeakRefCounter* releaseWeak();
383 /// Decrements weak counter.
384 /// If, after decrement, both strong and weak
385 /// counters are zero, it deletes this object.
386
387 int count() const;
388 /// Rteturns the current value of the strong
389 /// reference count.
390
391 int weakCount() const;
392 /// Rteturns the current value of the weak
393 /// reference count.
394
395private:
396 ~WeakRefCounter();
397 /// Destroys WeakRefCounter.
398
399 void* operator new(std::size_t);
400 /// Returns a block of memory from FastMemoryPool.
401
402 void operator delete(void* ptr);
403 /// Returns the block of memory to the FastMemoryPool.
404
405 void* operator new [] (std::size_t);
406 /// Not used; must never be accessed.
407 /// throws InvalidAccessException.
408
409 void operator delete [] (void* ptr);
410 /// Not used; does nothing.
411
412 WeakRefCounter(const WeakRefCounter&);
413 WeakRefCounter(WeakRefCounter&&);
414 WeakRefCounter& operator = (const WeakRefCounter&);
415 WeakRefCounter& operator = (WeakRefCounter&&);
416
417 mutable RefCounter _counter;
418 mutable RefCounter _weakCounter;
419
420 friend class WeakRefCountedObject;
421 template <typename T, class M> friend class FastMemoryPool;
422};
423
424//
425// inlines
426//
427
428inline void WeakRefCounter::duplicate()
429{
430 _counter++;
431}
432
433
434inline int WeakRefCounter::release()
435{
436 if (--_counter == 0 && _weakCounter == 0)
437 {
438 delete this;
439 return 0;
440 }
441 return _counter;
442}
443
444
445inline WeakRefCounter* WeakRefCounter::duplicateWeak()
446{
447 _weakCounter++;
448 return this;
449}
450
451
452inline WeakRefCounter* WeakRefCounter::releaseWeak()
453{
454 if (--_weakCounter == 0 && _counter == 0)
455 {
456 delete this;
457 return nullptr;
458 }
459 return this;
460}
461
462
463inline int WeakRefCounter::count() const
464{
465 return _counter;
466}
467
468
469inline int WeakRefCounter::weakCount() const
470{
471 return _weakCounter;
472}
473
474
475//
476// RefCountedObject
477//
478
479class Foundation_API WeakRefCountedObject
480 /// A base class for objects that employ weak/strong
481 /// reference counting based garbage collection.
482 ///
483 /// Reference-counted objects inhibit construction
484 /// by copying and assignment.
485 ///
486 /// The semantics of the RefCountedImpl object
487 /// and involved classes are as follows:
488 ///
489 /// - WeakRefCountedObject (WRCO) is used by WeakRefPtr and
490 /// RefPtr; RefPtr accesses only WRCO, WeakRefPtr accesses
491 /// only WeakRefCounter (which is created from this class
492 /// and may outlive it if "strong" count reaches zero before
493 /// the weak one)
494 ///
495 /// - WRCO must be created on the heap and should never be
496 /// created on the stack (if a user class inherits from WRCO,
497 /// it should have protected destructor)
498 ///
499 /// - both reference counts are maintained by WeakRefCounter,
500 /// which deletes itself under normal circumstances
501 /// (see below for an exception to normal circumstances)
502 ///
503 /// - WeakRefCounter may "outlive" this object if weak reference
504 /// count is greater than zero at the time when the strong
505 /// reference count reaches zero
506 ///
507 /// - WeakRefCounter will always delete itself. except in one "corner"
508 /// case when a WRCO object is created outside of RefPtr/WealRefPtr
509 /// wrappers and deleted using `delete` operator, without release()
510 /// ever be called; since not calling release() means that the counter
511 /// was never notified of the reference count change, it follows that
512 /// it is the responsibility of this object to delete the counter
513 ///
514 /// - reference counting is thread-safe; reference counted objects,
515 /// as well as the smart pointers "wrapping" them, however, are not
516 /// thread-safe; access to null counter pointer means there is a
517 /// bug somewhere in user application (there are debug build checks
518 /// indicating such circumstances, but no non-debug checks,
519 /// so - thread carefully!)
520 ///
521 /// - mutexes are not used, so there is no performance difference between
522 /// single- and multi-threaded modes of operation; note that, depending
523 /// on the underlying atomics implementation, locking may still happen
524 /// in both modes
525{
526public:
527 void duplicate() const;
528 /// Increments the object's reference count.
529
530 void release() const throw();
531 /// Decrements the object's reference count;
532 /// deletes the object if the count reaches
533 /// zero.
534
535 int referenceCount() const;
536 /// Returns the reference count.
537
538 WeakRefCounter* counter() const;
539 /// Return pointer to counter.
540
541protected:
542
543 WeakRefCountedObject();
544 /// Creates the RefCountedObjectImpl.
545 /// The initial reference count is one.;
546
547 virtual ~WeakRefCountedObject();
548 /// Destroys the RefCountedObjectImpl.
549
550private:
551 WeakRefCountedObject(const WeakRefCountedObject&) = delete;
552 WeakRefCountedObject& operator = (const WeakRefCountedObject&) = delete;
553 WeakRefCountedObject(WeakRefCountedObject&&) = delete;
554 WeakRefCountedObject& operator = (WeakRefCountedObject&&) = delete;
555
556 mutable std::atomic<WeakRefCounter*> _pCounter;
557
558 friend class RefCountDiagnosticContext;
559 template <typename T, class M> friend class FastMemoryPool;
560};
561
562
563typedef WeakRefCountedObject WRCO;
564
565
566//
567// inlines
568//
569
570inline void WeakRefCountedObject::duplicate() const
571{
572 poco_assert_dbg(_pCounter.load() != 0);
573 _pCounter.load()->duplicate();
574}
575
576
577inline void WeakRefCountedObject::release() const throw()
578{
579 poco_assert_dbg(_pCounter.load() != 0);
580 if(_pCounter.load()->release() == 0)
581 {
582 // _pCounter has deleted itself, disarm
583 // the delete in the destructor
584 _pCounter = 0;
585 delete this;
586 return;
587 }
588}
589
590
591inline int WeakRefCountedObject::referenceCount() const
592{
593 return _pCounter.load()->count();
594}
595
596
597inline WeakRefCounter* WeakRefCountedObject::counter() const
598{
599 return _pCounter;
600}
601
602
603} // namespace Poco
604
605
606#endif // Foundation_RefCountedObject_INCLUDED
607