71#ifndef OPENVPN_COMMON_RC_H
72#define OPENVPN_COMMON_RC_H
79#ifdef OPENVPN_RC_DEBUG
124 RCPtr(T *p, const
bool add_ref = true) noexcept;
127 template <typename U>
139 T &operator*() const noexcept;
140 T *operator->() const noexcept;
142 explicit operator
bool() const noexcept;
143 bool operator==(const
RCPtr &rhs) const;
144 bool operator!=(const
RCPtr &rhs) const;
147 template <typename U>
149 template <typename U>
303 RCPtr(rhs).swap(*
this);
313 std::swap(
px, rhs.px);
358 return px !=
nullptr;
461 void reset(const
Strong &p) noexcept;
462 void reset(T *p) noexcept;
463 void reset() noexcept;
466 olong use_count() const noexcept;
467 bool expired() const noexcept;
468 Strong lock() const noexcept;
469 Strong move_strong() noexcept;
472 typename T::Controller::Ptr controller;
545 controller.
swap(other.controller);
571 return use_count() == 0;
585 return controller->template lock<Strong>();
599 typename T::Controller::Ptr c;
602 return c->template lock<Strong>();
616#if !defined(__clang__) && defined(__GNUC__)
617#pragma GCC diagnostic push
619#pragma GCC diagnostic warning "-Wuse-after-free"
621#if __GNUC__ == 13 || __GNUC__ == 14 || __GNUC__ == 15
622#pragma GCC diagnostic warning "-Wstringop-overflow"
641 void operator++()
noexcept;
642 olong operator--()
noexcept;
643 bool inc_if_nonzero()
noexcept;
644 olong use_count()
const noexcept;
646 static constexpr bool is_thread_safe();
648#ifdef OPENVPN_RC_NOTIFY
649 void notify_release()
noexcept;
652#ifdef OPENVPN_RC_NOTIFY
653 template <
typename T>
668inline thread_unsafe_refcount::thread_unsafe_refcount() noexcept
673inline void thread_unsafe_refcount::operator++() noexcept
681inline olong thread_unsafe_refcount::operator--() noexcept
690inline bool thread_unsafe_refcount::inc_if_nonzero() noexcept
703inline olong thread_unsafe_refcount::use_count() const noexcept
714inline constexpr bool thread_unsafe_refcount::is_thread_safe()
719#ifdef OPENVPN_RC_NOTIFY
720inline void thread_unsafe_refcount::notify_release() noexcept
725#ifdef OPENVPN_RC_NOTIFY
727class thread_unsafe_refcount::ListHead
740 void insert(T *item)
noexcept
747 ListHead(
const ListHead &) =
delete;
748 ListHead &operator=(
const ListHead &) =
delete;
761 void operator++()
noexcept;
762 olong operator--()
noexcept;
764 bool inc_if_nonzero()
noexcept;
765 olong use_count()
const noexcept;
766 static constexpr bool is_thread_safe();
768#ifdef OPENVPN_RC_NOTIFY
769 void notify_release()
noexcept;
772#ifdef OPENVPN_RC_NOTIFY
773 template <
typename T>
781 std::atomic<olong>
rc;
786inline thread_safe_refcount::thread_safe_refcount() noexcept
793inline void thread_safe_refcount::operator++() noexcept
795 rc.fetch_add(1, std::memory_order_relaxed);
801inline olong thread_safe_refcount::operator--() noexcept
804 const olong ret =
rc.fetch_sub(1, std::memory_order_release) - 1;
806 std::atomic_thread_fence(std::memory_order_acquire);
816inline bool thread_safe_refcount::inc_if_nonzero() noexcept
818 olong previous =
rc.load(std::memory_order_relaxed);
823 if (
rc.compare_exchange_weak(previous, previous + 1, std::memory_order_relaxed))
832inline olong thread_safe_refcount::use_count() const noexcept
834 return rc.load(std::memory_order_relaxed);
843inline constexpr bool thread_safe_refcount::is_thread_safe()
848#ifdef OPENVPN_RC_NOTIFY
849inline void thread_safe_refcount::notify_release() noexcept
854#ifdef OPENVPN_RC_NOTIFY
856class thread_safe_refcount::ListHead
869 void insert(T *item)
noexcept
876 ListHead(
const ListHead &) =
delete;
877 ListHead &operator=(
const ListHead &) =
delete;
884#if !defined(__clang__) && defined(__GNUC__)
885#pragma GCC diagnostic pop
906template <
typename RCImpl>
912 RC() noexcept = default;
913 virtual ~
RC() = default;
915 RC &operator=(const
RC &) = delete;
918 static constexpr
bool is_thread_safe();
921 template <typename R>
922 friend
void intrusive_ptr_add_ref(R *rcptr) noexcept;
923 template <typename R>
924 friend
void intrusive_ptr_release(R *rcptr) noexcept;
932template <typename RCImpl>
943template <
typename RCImpl>
946 return RCImpl::is_thread_safe();
973template <
typename RCImpl>
986 template <typename R>
987 friend
void intrusive_ptr_add_ref(R *rcptr) noexcept;
988 template <typename R>
989 friend
void intrusive_ptr_release(R *rcptr) noexcept;
1003template <typename RCImpl>
1015template <
typename RCImpl>
1028template <
typename RCImpl>
1044template <
typename RCImpl>
1054template <
typename RCImpl>
1084template <
typename RCImpl>
1087 template <
typename T>
1090#ifdef OPENVPN_RC_NOTIFY
1094 template <
typename CALLABLE>
1097 class NotifyListHead;
1108 : refcount_(this) {};
1114#ifdef OPENVPN_RC_NOTIFY
1122 template <
typename CALLABLE>
1123 void rc_release_notify(
const CALLABLE &c)
noexcept
1125 refcount_.notify.add(c);
1128 template <
typename CALLABLE>
1129 void rc_release_notify(CALLABLE &&c)
noexcept
1131 refcount_.notify.add(std::move(c));
1136 template <
typename R>
1137 friend void intrusive_ptr_add_ref(R *rcptr)
noexcept;
1138 template <
typename R>
1139 friend void intrusive_ptr_release(R *rcptr)
noexcept;
1180template <
typename RCImpl>
1187 olong use_count() const noexcept;
1189 template <typename PTR>
1190 PTR lock() noexcept;
1200template <typename RCImpl>
1202 : parent(parent_arg){};
1208template <
typename RCImpl>
1211 return rc.use_count();
1222template <
typename RCImpl>
1223template <
typename PTR>
1226 if (
rc.inc_if_nonzero())
1227 return PTR(
static_cast<typename PTR::element_type *
>(parent),
false);
1238template <
typename RCImpl>
1243 void operator++()
noexcept;
1244 olong operator--()
noexcept;
1246#ifdef OPENVPN_RC_NOTIFY
1247 void notify_release()
noexcept;
1252#ifdef OPENVPN_RC_NOTIFY
1253 NotifyListHead notify;
1263template <
typename RCImpl>
1273template <
typename RCImpl>
1285template <
typename RCImpl>
1288 return --controller->rc;
1291#ifdef OPENVPN_RC_NOTIFY
1292template <
typename RCImpl>
1299#ifdef OPENVPN_RC_NOTIFY
1301template <
typename RCImpl>
1302class RCWeak<RCImpl>::NotifyBase
1305 NotifyBase() noexcept = default;
1306 virtual
void call() noexcept = 0;
1307 virtual ~NotifyBase() = default;
1308 NotifyBase *next =
nullptr;
1311 NotifyBase(const NotifyBase &) = delete;
1312 NotifyBase &operator=(const NotifyBase &) = delete;
1316template <typename RCImpl>
1317template <typename CALLABLE>
1318class
RCWeak<RCImpl>::NotifyItem : public NotifyBase
1321 NotifyItem(
const CALLABLE &c) noexcept
1326 NotifyItem(CALLABLE &&c) noexcept
1327 : callable(std::move(c))
1332 void call() noexcept
override
1341template <
typename RCImpl>
1342class RCWeak<RCImpl>::NotifyListHead
1345 NotifyListHead() noexcept
1349 template <
typename CALLABLE>
1350 void add(
const CALLABLE &c)
noexcept
1352 NotifyBase *item =
new NotifyItem<CALLABLE>(c);
1356 template <
typename CALLABLE>
1357 void add(CALLABLE &&c)
noexcept
1359 NotifyBase *item =
new NotifyItem<CALLABLE>(std::move(c));
1363 void release() noexcept
1368 NotifyBase *nb = head.load();
1371 NotifyBase *next = nb->next;
1379 NotifyListHead(
const NotifyListHead &) =
delete;
1380 NotifyListHead &operator=(
const NotifyListHead &) =
delete;
1382 typename RCImpl::template ListHead<NotifyBase> head;
1394template <
typename R>
1397#ifdef OPENVPN_RC_DEBUG
1398 std::cout <<
"ADD REF " <<
cxx_demangle(
typeid(rcptr).name()) <<
"\n";
1412template <
typename R>
1415 if (--rcptr->refcount_ == 0)
1417#ifdef OPENVPN_RC_DEBUG
1418 std::cout <<
"DEL OBJ " <<
cxx_demangle(
typeid(rcptr).name()) <<
"\n";
1420#ifdef OPENVPN_RC_NOTIFY
1421 rcptr->refcount_.notify_release();
1427#ifdef OPENVPN_RC_DEBUG
1428 std::cout <<
"REL REF " <<
cxx_demangle(
typeid(rcptr).name()) <<
"\n";
Reference count base class for objects tracked by RCPtr. Allows copying and assignment.
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.
T * px
Pointer to the controlled object.
T * operator->() const noexcept
Returns the raw pointer to the object T, or nullptr.
RCPtr< U > static_pointer_cast() const noexcept
Returns a "RCPtr<U>" that points to our T object.
~RCPtr()
Destroy the RCPtr<T>::RCPtr object.
RCPtr() noexcept
Construct a new RCPtr<T>::RCPtr object.
RCPtr< T > move_strong() noexcept
Moves ownership of the internal pointer to the returned RCPtr<T>
void reset() noexcept
Points this RCPtr<T> to nullptr safely.
void swap(RCPtr &rhs) noexcept
swaps the contents of two RCPtr<T>
bool operator==(const RCPtr &rhs) const
Evaluates to true if the two RCPtr<T> point to the same object.
RCPtr< U > dynamic_pointer_cast() const noexcept
Returns a "RCPtr<U>" that points to our T object.
T & operator*() const noexcept
Operator returns a ref to the pointed to T.
bool operator!=(const RCPtr &rhs) const
Evaluates to true if the two RCPtr<T> point to different objects.
T * get() const noexcept
Returns the raw pointer to the object T, or nullptr.
RCPtr & operator=(const RCPtr &rhs) noexcept
Assigns an existing RCPtr<T> to point to a different T.
implements a weak pointer for reference counted objects.
void swap(RCWeakPtr &other) noexcept
Swaps thing pointed to by *this withthing pointed to by other.
olong use_count() const noexcept
Returns count of references to the object.
T::Controller::Ptr controller
Smart pointer to the T::ControllerF.
void reset(const Strong &p) noexcept
Reassign this weak ptr to the object referenced by the given strong (RCPtr) pointer.
Reference count base class for objects tracked by RCPtr. Like RC, but also allows weak pointers and r...
RCWeak & operator=(const RCWeak &)=delete
ControllerRef refcount_
Adapter instance that allows RCPtr to properly interact with RCWeak.
RCWeak(const RCWeak &)=delete
virtual ~RCWeak()=default
Reference count base class for objects tracked by RCPtr. Disallows copying and assignment.
olong use_count() const noexcept
Delegates call to RCImpl and returns the result.
Implements a memory fenced ref count.
thread_safe_refcount & operator=(const thread_safe_refcount &)=delete
thread_safe_refcount(const thread_safe_refcount &)=delete
implements a simple reference count for objects.
thread_unsafe_refcount(const thread_unsafe_refcount &)=delete
olong rc
The reference count, platform efficient integer type.
thread_unsafe_refcount & operator=(const thread_unsafe_refcount &)=delete
std::string call(const std::string &cmd)
void intrusive_ptr_release(R *rcptr) noexcept
Helper to decrement a ref count.
std::string cxx_demangle(const char *mangled_name)
void intrusive_ptr_add_ref(R *rcptr) noexcept
Helper to increment a ref count.
Adapter object for RCWeak::Controller <—> RCPtr.
Controller::Ptr controller
object containing actual refcount
Controller structure for our ptr/weakptr implementation.
static void add(const Time &t1, const Time::Duration &d1)