OpenVPN 3 Core Library
Loading...
Searching...
No Matches
rc.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12// A basic reference-counting garbage collection scheme based
13// on intrusive pointers, where the reference count is embedded in
14// the object via inheritance. Simply inherit from RC to create an
15// object that can be tracked with an RCPtr.
16//
17// We use tend to use RCPtr (or RCWeakPtr) rather than the other
18// smart pointer classes (std or boost) for flexibility and
19// performance.
20//
21// Smart pointers have two basic attributes that determine
22// their performance. Either of these attributes, when required,
23// will degrade the performance of the smart pointer:
24//
25// 1. whether the smart pointer is thread-safe, i.e. it uses an
26// atomic reference counter
27// 2. whether the smart pointer can be referrred to via a
28// weak reference
29//
30// In keeping with the oft-stated C++ motto of only paying for
31// what you use, both attributes can be independently controlled.
32//
33// * thread-unsafe/not-weak-referenceable -- class Foo : public RC<thread_unsafe_refcount>
34// * thread-safe/not-weak-referenceable -- class Foo : public RC<thread_safe_refcount>
35// * thread-unsafe/weak-referenceable -- class Foo : public RCWeak<thread_unsafe_refcount>
36// * thread-safe/weak-referenceable -- class Foo : public RCWeak<thread_safe_refcount>
37//
38// Thread-safe reference counting can be significantly more expensive
39// because an atomic object must be used for the reference count.
40// Therefore, thread-safe reference counting should only be used for
41// objects that have visibility across multiple threads.
42//
43// In addition, having an object be weak-referenceable also
44// imposes a cost, so it should be avoided unless necessary.
45//
46// For clarity and as a general convention in the OpenVPN code,
47// any object that inherits from RC should also declare a Ptr
48// typedef that defines the smart pointer type that should be used to
49// track the object, e.g.:
50//
51// class Foo : public RC<thread_unsafe_refcount> {
52// public:
53// typedef RCPtr<Foo> Ptr; // strong pointer
54// typedef RCWeakPtr<Foo> WPtr; // weak pointer
55// };
56//
57// This allows a smart-pointer to Foo to be referred to
58// as Foo::Ptr or Foo::WPtr.
59//
60// Note that RC/RCWeak fully supports virtual inheritance. For
61// example, consider the diamond inheritance pattern below, where
62// both A and B objects contain their own reference count, but C
63// inherits from both A and B. To prevent C objects from
64// having two separate reference counts, it is necessary to
65// virtually inherit from RC.
66//
67// class A : public virtual RC<thread_unsafe_refcount> {}
68// class B : public virtual RC<thread_unsafe_refcount> {}
69// class C : public A, public B {}
70
71#ifndef OPENVPN_COMMON_RC_H
72#define OPENVPN_COMMON_RC_H
73
74#include <atomic>
75#include <utility>
76
78
79#ifdef OPENVPN_RC_DEBUG
80#include <iostream>
82#endif
83
84namespace openvpn {
85
117template <typename T>
118class RCPtr
119{
120 public:
121 typedef T element_type;
122
123 RCPtr() noexcept;
124 RCPtr(T *p, const bool add_ref = true) noexcept;
125 RCPtr(const RCPtr &rhs) noexcept;
126 RCPtr(RCPtr &&rhs) noexcept;
127 template <typename U>
128 RCPtr(const RCPtr<U> &rhs) noexcept;
130
131 RCPtr &operator=(const RCPtr &rhs) noexcept;
132 RCPtr &operator=(RCPtr &&rhs) noexcept;
133
134 void reset() noexcept;
135 void reset(T *rhs) noexcept;
136 void swap(RCPtr &rhs) noexcept;
137
138 T *get() const noexcept;
139 T &operator*() const noexcept;
140 T *operator->() const noexcept;
141
142 explicit operator bool() const noexcept;
143 bool operator==(const RCPtr &rhs) const;
144 bool operator!=(const RCPtr &rhs) const;
145
146 RCPtr<T> move_strong() noexcept;
147 template <typename U>
148 RCPtr<U> static_pointer_cast() const noexcept;
149 template <typename U>
150 RCPtr<U> dynamic_pointer_cast() const noexcept;
151
152 private:
153 T *px;
154};
166template <typename T>
167RCPtr<T>::RCPtr() noexcept
168 : px(nullptr){};
194template <typename T>
195RCPtr<T>::RCPtr(T *p, const bool add_ref) noexcept
196 : px(p)
197{
198 if (px && add_ref)
200}
206template <typename T>
207RCPtr<T>::RCPtr(const RCPtr &rhs) noexcept
208 : px(rhs.px)
209{
210 if (px)
212}
218template <typename T>
219RCPtr<T>::RCPtr(RCPtr &&rhs) noexcept
220 : px(rhs.px)
221{
222 rhs.px = nullptr;
223}
232template <typename T>
233template <typename U>
234RCPtr<T>::RCPtr(const RCPtr<U> &rhs) noexcept
235 : px(rhs.get())
236{
237 if (px)
239}
248template <typename T>
250{
251 if (px)
253}
263template <typename T>
264RCPtr<T> &RCPtr<T>::operator=(const RCPtr &rhs) noexcept
265{
266 // notice that RCPtr(rhs) is a temp built from rhs, which will decrement old T when scope ends
267 RCPtr(rhs).swap(*this);
268 return *this;
269}
279template <typename T>
281{
282 RCPtr(std::move(rhs)).swap(*this);
283 return *this;
284}
289template <typename T>
290void RCPtr<T>::reset() noexcept
291{
292 RCPtr().swap(*this);
293}
300template <typename T>
301void RCPtr<T>::reset(T *rhs) noexcept
302{
303 RCPtr(rhs).swap(*this);
304}
310template <typename T>
311void RCPtr<T>::swap(RCPtr &rhs) noexcept
312{
313 std::swap(px, rhs.px);
314}
320template <typename T>
321T *RCPtr<T>::get() const noexcept
322{
323 return px;
324}
334template <typename T>
335T &RCPtr<T>::operator*() const noexcept
336{
337 return *px;
338}
344template <typename T>
345T *RCPtr<T>::operator->() const noexcept
346{
347 return px;
348}
355template <typename T>
356RCPtr<T>::operator bool() const noexcept
357{
358 return px != nullptr;
359}
368template <typename T>
369bool RCPtr<T>::operator==(const RCPtr &rhs) const
370{
371 return px == rhs.px;
372}
380template <typename T>
381bool RCPtr<T>::operator!=(const RCPtr &rhs) const
382{
383 return px != rhs.px;
384}
390template <typename T>
392{
393 T *p = px;
394 px = nullptr;
395 return RCPtr<T>(p, false);
396}
405template <typename T>
406template <typename U>
408{
409 return RCPtr<U>(static_cast<U *>(px));
410}
420template <typename T>
421template <typename U>
423{
424 return RCPtr<U>(dynamic_cast<U *>(px));
425}
449template <typename T>
451{
453
454 public:
455 typedef T element_type;
456
457 RCWeakPtr() noexcept;
458 RCWeakPtr(const Strong &p) noexcept;
459 RCWeakPtr(T *p) noexcept;
460
461 void reset(const Strong &p) noexcept;
462 void reset(T *p) noexcept;
463 void reset() noexcept;
464
465 void swap(RCWeakPtr &other) noexcept;
466 olong use_count() const noexcept;
467 bool expired() const noexcept;
468 Strong lock() const noexcept;
469 Strong move_strong() noexcept;
470
471 private:
472 typename T::Controller::Ptr controller;
473};
478template <typename T>
479RCWeakPtr<T>::RCWeakPtr() noexcept {};
485template <typename T>
487{
488 if (p)
489 controller = p->refcount_.controller;
490}
496template <typename T>
498{
499 if (p)
500 controller = p->refcount_.controller;
501}
507template <typename T>
508void RCWeakPtr<T>::reset(const Strong &p) noexcept
509{
510 if (p)
511 controller = p->refcount_.controller;
512 else
513 controller.reset();
514}
520template <typename T>
521void RCWeakPtr<T>::reset(T *p) noexcept
522{
523 if (p)
524 controller = p->refcount_.controller;
525 else
526 controller.reset();
527}
532template <typename T>
533void RCWeakPtr<T>::reset() noexcept
534{
535 controller.reset();
536}
542template <typename T>
543void RCWeakPtr<T>::swap(RCWeakPtr &other) noexcept
544{
545 controller.swap(other.controller);
546}
555template <typename T>
557{
558 if (controller)
559 return controller->use_count();
560 else
561 return 0;
562}
569template <typename T>
570bool RCWeakPtr<T>::expired() const noexcept
571{
572 return use_count() == 0;
573}
582template <typename T>
584{
585 if (controller)
586 return controller->template lock<Strong>();
587 else
588 return Strong();
589}
598template <typename T>
600{
601 typename T::Controller::Ptr c;
602 c.swap(controller);
603 if (c)
604 return c->template lock<Strong>();
605 else
606 return Strong();
607}
608
609/* We're pretty sure these are false positives. They only occur with very
610 specific compiler versions and/or architectures.
611
612 For some reason some gcc versions think that the reference counter goes
613 away too soon when destructing certain MultiCompleteType objects. The
614 warnings/errors do not tell us why they think that.
615
616 So for now we display the warnings, but do not fail -Werror builds over
617 them. So that we can fail them for any other new warnings.
618 */
619#if !defined(__clang__) && defined(__GNUC__)
620#pragma GCC diagnostic push
621#if __GNUC__ == 12
622#pragma GCC diagnostic warning "-Wuse-after-free"
623#endif
624#if __GNUC__ == 13 || __GNUC__ == 14
625#pragma GCC diagnostic warning "-Wstringop-overflow"
626#endif
627#endif
641{
642 public:
643 thread_unsafe_refcount() noexcept;
644 void operator++() noexcept;
645 olong operator--() noexcept;
646 bool inc_if_nonzero() noexcept;
647 olong use_count() const noexcept;
648
649 static constexpr bool is_thread_safe();
650
651#ifdef OPENVPN_RC_NOTIFY
652 void notify_release() noexcept;
653#endif
654
655#ifdef OPENVPN_RC_NOTIFY
656 template <typename T>
657 class ListHead;
658#endif
659
660 private:
663
665};
671inline thread_unsafe_refcount::thread_unsafe_refcount() noexcept
672 : rc(olong(0)) {};
676inline void thread_unsafe_refcount::operator++() noexcept
677{
678 ++rc;
679}
684inline olong thread_unsafe_refcount::operator--() noexcept
685{
686 return --rc;
687}
693inline bool thread_unsafe_refcount::inc_if_nonzero() noexcept
694{
695 if (rc)
696 {
697 ++rc;
698 return true;
699 }
700 else
701 return false;
702}
707inline olong thread_unsafe_refcount::use_count() const noexcept
708{
709 return rc;
710}
718inline constexpr bool thread_unsafe_refcount::is_thread_safe()
719{
720 return false;
721}
722
723#ifdef OPENVPN_RC_NOTIFY
724inline void thread_unsafe_refcount::notify_release() noexcept
725{
726}
727#endif
728
729#ifdef OPENVPN_RC_NOTIFY
730template <typename T>
731class thread_unsafe_refcount::ListHead
732{
733 public:
734 ListHead() noexcept
735 : ptr(nullptr)
736 {
737 }
738
739 T *load() noexcept
740 {
741 return ptr;
742 }
743
744 void insert(T *item) noexcept
745 {
746 item->next = ptr;
747 ptr = item;
748 }
749
750 private:
751 ListHead(const ListHead &) = delete;
752 ListHead &operator=(const ListHead &) = delete;
753
754 T *ptr;
755};
756#endif
757
762{
763 public:
764 thread_safe_refcount() noexcept;
765 void operator++() noexcept;
766 olong operator--() noexcept;
767
768 bool inc_if_nonzero() noexcept;
769 olong use_count() const noexcept;
770 static constexpr bool is_thread_safe();
771
772#ifdef OPENVPN_RC_NOTIFY
773 void notify_release() noexcept;
774#endif
775
776#ifdef OPENVPN_RC_NOTIFY
777 template <typename T>
778 class ListHead;
779#endif
780
781 private:
784
785 std::atomic<olong> rc;
786};
790inline thread_safe_refcount::thread_safe_refcount() noexcept
791 : rc(olong(0))
792{
793}
797inline void thread_safe_refcount::operator++() noexcept
798{
799 rc.fetch_add(1, std::memory_order_relaxed);
800}
805inline olong thread_safe_refcount::operator--() noexcept
806{
807 // http://www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html
808 const olong ret = rc.fetch_sub(1, std::memory_order_release) - 1;
809 if (ret == 0)
810 std::atomic_thread_fence(std::memory_order_acquire);
811 return ret;
812}
820inline bool thread_safe_refcount::inc_if_nonzero() noexcept
821{
822 olong previous = rc.load(std::memory_order_relaxed);
823 while (true)
824 {
825 if (!previous)
826 break;
827 if (rc.compare_exchange_weak(previous, previous + 1, std::memory_order_relaxed))
828 break;
829 }
830 return previous > 0;
831}
836inline olong thread_safe_refcount::use_count() const noexcept
837{
838 return rc.load(std::memory_order_relaxed);
839}
847inline constexpr bool thread_safe_refcount::is_thread_safe()
848{
849 return true;
850}
851
852#ifdef OPENVPN_RC_NOTIFY
853inline void thread_safe_refcount::notify_release() noexcept
854{
855}
856#endif
857
858#ifdef OPENVPN_RC_NOTIFY
859template <typename T>
860class thread_safe_refcount::ListHead
861{
862 public:
863 ListHead() noexcept
864 : ptr(nullptr)
865 {
866 }
867
868 T *load() noexcept
869 {
870 return ptr;
871 }
872
873 void insert(T *item) noexcept
874 {
875 item->next = ptr;
876 ptr = item;
877 }
878
879 private:
880 ListHead(const ListHead &) = delete;
881 ListHead &operator=(const ListHead &) = delete;
882
883 T *ptr;
884};
885#endif
886
887
888#if !defined(__clang__) && defined(__GNUC__)
889#pragma GCC diagnostic pop
890#endif
891
910template <typename RCImpl>
911class RC
912{
913 public:
914 typedef RCPtr<RC> Ptr;
915
916 RC() noexcept = default;
917 virtual ~RC() = default;
918 RC(const RC &) = delete;
919 RC &operator=(const RC &) = delete;
920
921 olong use_count() const noexcept;
922 static constexpr bool is_thread_safe();
923
924 private:
925 template <typename R>
926 friend void intrusive_ptr_add_ref(R *rcptr) noexcept;
927 template <typename R>
928 friend void intrusive_ptr_release(R *rcptr) noexcept;
929 RCImpl refcount_;
930};
936template <typename RCImpl>
937olong RC<RCImpl>::use_count() const noexcept
938{
939 return refcount_.use_count();
940}
947template <typename RCImpl>
949{
950 return RCImpl::is_thread_safe();
951}
952
977template <typename RCImpl>
979{
980 public:
981 virtual ~RCCopyable() = default;
982 RCCopyable() noexcept = default;
983 RCCopyable(const RCCopyable &) noexcept;
984 RCCopyable(RCCopyable &&) noexcept;
985 RCCopyable &operator=(const RCCopyable &) noexcept;
986 RCCopyable &operator=(RCCopyable &&) noexcept;
987 olong use_count() const noexcept;
988
989 private:
990 template <typename R>
991 friend void intrusive_ptr_add_ref(R *rcptr) noexcept;
992 template <typename R>
993 friend void intrusive_ptr_release(R *rcptr) noexcept;
994 RCImpl refcount_;
995};
996
1007template <typename RCImpl>
1008RCCopyable<RCImpl>::RCCopyable(const RCCopyable &) noexcept {};
1019template <typename RCImpl>
1032template <typename RCImpl>
1034{
1035 return *this;
1036}
1048template <typename RCImpl>
1050{
1051 return *this;
1052}
1058template <typename RCImpl>
1060{
1061 return refcount_.use_count();
1062}
1063
1088template <typename RCImpl> // RCImpl = thread_safe_refcount or thread_unsafe_refcount
1090{
1091 template <typename T>
1092 friend class RCWeakPtr;
1093
1094#ifdef OPENVPN_RC_NOTIFY
1095 // Base class of release notification callables
1096 class NotifyBase;
1097 // A release notification callable
1098 template <typename CALLABLE>
1099 class NotifyItem;
1100 // Head of a linked-list of release notification callables
1101 class NotifyListHead;
1102#endif
1103
1104 struct Controller;
1105 struct ControllerRef;
1106
1107 public:
1110
1111 RCWeak() noexcept
1112 : refcount_(this) {};
1113
1114 virtual ~RCWeak() = default;
1115 RCWeak(const RCWeak &) = delete;
1116 RCWeak &operator=(const RCWeak &) = delete;
1117
1118#ifdef OPENVPN_RC_NOTIFY
1119 // Add observers to be called just prior to object deletion,
1120 // but after refcount has been decremented to 0. At this
1121 // point, all weak pointers have expired, and no strong
1122 // pointers are outstanding. Callables can access the
1123 // object by raw pointer but must NOT attempt to create a
1124 // strong pointer referencing the object.
1125
1126 template <typename CALLABLE>
1127 void rc_release_notify(const CALLABLE &c) noexcept
1128 {
1129 refcount_.notify.add(c);
1130 }
1131
1132 template <typename CALLABLE>
1133 void rc_release_notify(CALLABLE &&c) noexcept
1134 {
1135 refcount_.notify.add(std::move(c));
1136 }
1137#endif
1138
1139 private:
1140 template <typename R>
1141 friend void intrusive_ptr_add_ref(R *rcptr) noexcept;
1142 template <typename R>
1143 friend void intrusive_ptr_release(R *rcptr) noexcept;
1144
1146};
1147
1184template <typename RCImpl>
1185struct RCWeak<RCImpl>::Controller : public RC<RCImpl>
1186{
1188
1189 Controller(RCWeak *parent_arg) noexcept;
1190
1191 olong use_count() const noexcept;
1192
1193 template <typename PTR>
1194 PTR lock() noexcept;
1195
1196 RCWeak *const parent;
1197 RCImpl rc;
1198};
1204template <typename RCImpl>
1205RCWeak<RCImpl>::Controller::Controller(RCWeak *parent_arg) noexcept
1206 : parent(parent_arg){};
1212template <typename RCImpl>
1214{
1215 return rc.use_count();
1216}
1226template <typename RCImpl>
1227template <typename PTR>
1229{
1230 if (rc.inc_if_nonzero())
1231 return PTR(static_cast<typename PTR::element_type *>(parent), false);
1232 else
1233 return PTR();
1234}
1235
1243template <typename RCImpl>
1244struct RCWeak<RCImpl>::ControllerRef
1245{
1246 explicit ControllerRef(RCWeak *parent) noexcept;
1247
1248 void operator++() noexcept;
1249 olong operator--() noexcept;
1250
1251#ifdef OPENVPN_RC_NOTIFY
1252 void notify_release() noexcept;
1253#endif
1254
1256
1257#ifdef OPENVPN_RC_NOTIFY
1258 NotifyListHead notify; // linked list of callables to be notified on object release
1259#endif
1260};
1268template <typename RCImpl>
1270 : controller(new Controller(parent)){};
1278template <typename RCImpl>
1280{
1281 ++controller->rc;
1282}
1290template <typename RCImpl>
1292{
1293 return --controller->rc;
1294}
1295
1296#ifdef OPENVPN_RC_NOTIFY
1297template <typename RCImpl>
1299{
1300 notify.release();
1301}
1302#endif
1303
1304#ifdef OPENVPN_RC_NOTIFY
1305// Base class of release notification callables
1306template <typename RCImpl>
1307class RCWeak<RCImpl>::NotifyBase
1308{
1309 public:
1310 NotifyBase() noexcept = default;
1311 virtual void call() noexcept = 0;
1312 virtual ~NotifyBase() = default;
1313 NotifyBase *next = nullptr;
1314
1315 private:
1316 NotifyBase(const NotifyBase &) = delete;
1317 NotifyBase &operator=(const NotifyBase &) = delete;
1318};
1319
1320// A release notification callable
1321template <typename RCImpl>
1322template <typename CALLABLE>
1323class RCWeak<RCImpl>::NotifyItem : public NotifyBase
1324{
1325 public:
1326 NotifyItem(const CALLABLE &c) noexcept
1327 : callable(c)
1328 {
1329 }
1330
1331 NotifyItem(CALLABLE &&c) noexcept
1332 : callable(std::move(c))
1333 {
1334 }
1335
1336 private:
1337 void call() noexcept override
1338 {
1339 callable();
1340 }
1341
1342 CALLABLE callable;
1343};
1344
1345// Head of a linked-list of release notification callables
1346template <typename RCImpl>
1347class RCWeak<RCImpl>::NotifyListHead
1348{
1349 public:
1350 NotifyListHead() noexcept
1351 {
1352 }
1353
1354 template <typename CALLABLE>
1355 void add(const CALLABLE &c) noexcept
1356 {
1357 NotifyBase *item = new NotifyItem<CALLABLE>(c);
1358 head.insert(item);
1359 }
1360
1361 template <typename CALLABLE>
1362 void add(CALLABLE &&c) noexcept
1363 {
1364 NotifyBase *item = new NotifyItem<CALLABLE>(std::move(c));
1365 head.insert(item);
1366 }
1367
1368 void release() noexcept
1369 {
1370 // In thread-safe mode, list traversal is guaranteed to be
1371 // contention-free because we are not called until refcount
1372 // reaches zero and after a std::memory_order_acquire fence.
1373 NotifyBase *nb = head.load();
1374 while (nb)
1375 {
1376 NotifyBase *next = nb->next;
1377 nb->call();
1378 delete nb;
1379 nb = next;
1380 }
1381 }
1382
1383 private:
1384 NotifyListHead(const NotifyListHead &) = delete;
1385 NotifyListHead &operator=(const NotifyListHead &) = delete;
1386
1387 typename RCImpl::template ListHead<NotifyBase> head;
1388};
1389#endif
1399template <typename R>
1400inline void intrusive_ptr_add_ref(R *rcptr) noexcept
1401{
1402#ifdef OPENVPN_RC_DEBUG
1403 std::cout << "ADD REF " << cxx_demangle(typeid(rcptr).name()) << std::endl;
1404#endif
1405 ++rcptr->refcount_;
1406}
1417template <typename R>
1418inline void intrusive_ptr_release(R *rcptr) noexcept
1419{
1420 if (--rcptr->refcount_ == 0)
1421 {
1422#ifdef OPENVPN_RC_DEBUG
1423 std::cout << "DEL OBJ " << cxx_demangle(typeid(rcptr).name()) << std::endl;
1424#endif
1425#ifdef OPENVPN_RC_NOTIFY
1426 rcptr->refcount_.notify_release();
1427#endif
1428 delete rcptr;
1429 }
1430 else
1431 {
1432#ifdef OPENVPN_RC_DEBUG
1433 std::cout << "REL REF " << cxx_demangle(typeid(rcptr).name()) << std::endl;
1434#endif
1435 }
1436}
1437
1438} // namespace openvpn
1439
1440#endif // OPENVPN_COMMON_RC_H
Reference count base class for objects tracked by RCPtr. Allows copying and assignment.
Definition rc.hpp:979
RCCopyable() noexcept=default
virtual ~RCCopyable()=default
olong use_count() const noexcept
Returns the use count as reported by defering to the injected ref count type.
Definition rc.hpp:1059
The smart pointer class.
Definition rc.hpp:119
T * px
Pointer to the controlled object.
Definition rc.hpp:153
T * operator->() const noexcept
Returns the raw pointer to the object T, or nullptr.
Definition rc.hpp:345
RCPtr< U > static_pointer_cast() const noexcept
Returns a "RCPtr<U>" that points to our T object.
Definition rc.hpp:407
~RCPtr()
Destroy the RCPtr<T>::RCPtr object.
Definition rc.hpp:249
RCPtr() noexcept
Construct a new RCPtr<T>::RCPtr object.
Definition rc.hpp:167
RCPtr< T > move_strong() noexcept
Moves ownership of the internal pointer to the returned RCPtr<T>
Definition rc.hpp:391
void reset() noexcept
Points this RCPtr<T> to nullptr safely.
Definition rc.hpp:290
void swap(RCPtr &rhs) noexcept
swaps the contents of two RCPtr<T>
Definition rc.hpp:311
bool operator==(const RCPtr &rhs) const
Evaluates to true if the two RCPtr<T> point to the same object.
Definition rc.hpp:369
RCPtr< U > dynamic_pointer_cast() const noexcept
Returns a "RCPtr<U>" that points to our T object.
Definition rc.hpp:422
T & operator*() const noexcept
Operator returns a ref to the pointed to T.
Definition rc.hpp:335
bool operator!=(const RCPtr &rhs) const
Evaluates to true if the two RCPtr<T> point to different objects.
Definition rc.hpp:381
T * get() const noexcept
Returns the raw pointer to the object T, or nullptr.
Definition rc.hpp:321
RCPtr & operator=(const RCPtr &rhs) noexcept
Assigns an existing RCPtr<T> to point to a different T.
Definition rc.hpp:264
implements a weak pointer for reference counted objects.
Definition rc.hpp:451
void swap(RCWeakPtr &other) noexcept
Swaps thing pointed to by *this withthing pointed to by other.
Definition rc.hpp:543
RCPtr< T > Strong
Definition rc.hpp:452
olong use_count() const noexcept
Returns count of references to the object.
Definition rc.hpp:556
T::Controller::Ptr controller
Smart pointer to the T::ControllerF.
Definition rc.hpp:472
void reset(const Strong &p) noexcept
Reassign this weak ptr to the object referenced by the given strong (RCPtr) pointer.
Definition rc.hpp:508
Reference count base class for objects tracked by RCPtr. Like RC, but also allows weak pointers and r...
Definition rc.hpp:1090
RCWeak() noexcept
Definition rc.hpp:1111
RCPtr< RCWeak > Ptr
Definition rc.hpp:1108
RCWeak & operator=(const RCWeak &)=delete
ControllerRef refcount_
Adapter instance that allows RCPtr to properly interact with RCWeak.
Definition rc.hpp:1145
RCWeakPtr< RCWeak > WPtr
Definition rc.hpp:1109
RCWeak(const RCWeak &)=delete
virtual ~RCWeak()=default
Reference count base class for objects tracked by RCPtr. Disallows copying and assignment.
Definition rc.hpp:912
olong use_count() const noexcept
Delegates call to RCImpl and returns the result.
Definition rc.hpp:937
RC() noexcept=default
RCPtr< RC > Ptr
Definition rc.hpp:914
Implements a memory fenced ref count.
Definition rc.hpp:762
thread_safe_refcount & operator=(const thread_safe_refcount &)=delete
thread_safe_refcount(const thread_safe_refcount &)=delete
std::atomic< olong > rc
Definition rc.hpp:785
implements a simple reference count for objects.
Definition rc.hpp:641
thread_unsafe_refcount(const thread_unsafe_refcount &)=delete
olong rc
The reference count, platform efficient integer type.
Definition rc.hpp:664
thread_unsafe_refcount & operator=(const thread_unsafe_refcount &)=delete
std::string call(const std::string &cmd)
Definition call.hpp:31
Support deferred server-side state creation when client connects.
Definition ovpncli.cpp:95
void intrusive_ptr_release(R *rcptr) noexcept
Helper to decrement a ref count.
Definition rc.hpp:1418
std::string cxx_demangle(const char *mangled_name)
Definition demangle.hpp:24
void intrusive_ptr_add_ref(R *rcptr) noexcept
Helper to increment a ref count.
Definition rc.hpp:1400
long olong
Definition olong.hpp:23
Adapter object for RCWeak::Controller <—> RCPtr.
Definition rc.hpp:1245
Controller::Ptr controller
object containing actual refcount
Definition rc.hpp:1255
Controller structure for our ptr/weakptr implementation.
Definition rc.hpp:1186
RCPtr< Controller > Ptr
Definition rc.hpp:1187
std::string ret
static void add(const Time &t1, const Time::Duration &d1)