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);
572 return use_count() == 0;
586 return controller->template lock<Strong>();
601 typename T::Controller::Ptr c;
604 return c->template lock<Strong>();
619#if !defined(__clang__) && defined(__GNUC__)
620#pragma GCC diagnostic push
622#pragma GCC diagnostic warning "-Wuse-after-free"
624#if __GNUC__ == 13 || __GNUC__ == 14
625#pragma GCC diagnostic warning "-Wstringop-overflow"
644 void operator++()
noexcept;
645 olong operator--()
noexcept;
646 bool inc_if_nonzero()
noexcept;
647 olong use_count()
const noexcept;
649 static constexpr bool is_thread_safe();
651#ifdef OPENVPN_RC_NOTIFY
652 void notify_release()
noexcept;
655#ifdef OPENVPN_RC_NOTIFY
656 template <
typename T>
671inline thread_unsafe_refcount::thread_unsafe_refcount() noexcept
676inline void thread_unsafe_refcount::operator++() noexcept
684inline olong thread_unsafe_refcount::operator--() noexcept
693inline bool thread_unsafe_refcount::inc_if_nonzero() noexcept
707inline olong thread_unsafe_refcount::use_count() const noexcept
718inline constexpr bool thread_unsafe_refcount::is_thread_safe()
723#ifdef OPENVPN_RC_NOTIFY
724inline void thread_unsafe_refcount::notify_release() noexcept
729#ifdef OPENVPN_RC_NOTIFY
731class thread_unsafe_refcount::ListHead
744 void insert(T *item)
noexcept
751 ListHead(
const ListHead &) =
delete;
752 ListHead &operator=(
const ListHead &) =
delete;
765 void operator++()
noexcept;
766 olong operator--()
noexcept;
768 bool inc_if_nonzero()
noexcept;
769 olong use_count()
const noexcept;
770 static constexpr bool is_thread_safe();
772#ifdef OPENVPN_RC_NOTIFY
773 void notify_release()
noexcept;
776#ifdef OPENVPN_RC_NOTIFY
777 template <
typename T>
785 std::atomic<olong>
rc;
790inline thread_safe_refcount::thread_safe_refcount() noexcept
797inline void thread_safe_refcount::operator++() noexcept
799 rc.fetch_add(1, std::memory_order_relaxed);
805inline olong thread_safe_refcount::operator--() noexcept
808 const olong ret =
rc.fetch_sub(1, std::memory_order_release) - 1;
810 std::atomic_thread_fence(std::memory_order_acquire);
820inline bool thread_safe_refcount::inc_if_nonzero() noexcept
822 olong previous =
rc.load(std::memory_order_relaxed);
827 if (
rc.compare_exchange_weak(previous, previous + 1, std::memory_order_relaxed))
836inline olong thread_safe_refcount::use_count() const noexcept
838 return rc.load(std::memory_order_relaxed);
847inline constexpr bool thread_safe_refcount::is_thread_safe()
852#ifdef OPENVPN_RC_NOTIFY
853inline void thread_safe_refcount::notify_release() noexcept
858#ifdef OPENVPN_RC_NOTIFY
860class thread_safe_refcount::ListHead
873 void insert(T *item)
noexcept
880 ListHead(
const ListHead &) =
delete;
881 ListHead &operator=(
const ListHead &) =
delete;
888#if !defined(__clang__) && defined(__GNUC__)
889#pragma GCC diagnostic pop
910template <
typename RCImpl>
916 RC() noexcept = default;
917 virtual ~
RC() = default;
919 RC &operator=(const
RC &) = delete;
922 static constexpr
bool is_thread_safe();
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;
936template <typename RCImpl>
947template <
typename RCImpl>
950 return RCImpl::is_thread_safe();
977template <
typename RCImpl>
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;
1007template <typename RCImpl>
1019template <
typename RCImpl>
1032template <
typename RCImpl>
1048template <
typename RCImpl>
1058template <
typename RCImpl>
1088template <
typename RCImpl>
1091 template <
typename T>
1094#ifdef OPENVPN_RC_NOTIFY
1098 template <
typename CALLABLE>
1101 class NotifyListHead;
1112 : refcount_(this) {};
1118#ifdef OPENVPN_RC_NOTIFY
1126 template <
typename CALLABLE>
1127 void rc_release_notify(
const CALLABLE &c)
noexcept
1129 refcount_.notify.add(c);
1132 template <
typename CALLABLE>
1133 void rc_release_notify(CALLABLE &&c)
noexcept
1135 refcount_.notify.add(std::move(c));
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;
1184template <
typename RCImpl>
1191 olong use_count() const noexcept;
1193 template <typename PTR>
1194 PTR lock() noexcept;
1204template <typename RCImpl>
1206 : parent(parent_arg){};
1212template <
typename RCImpl>
1215 return rc.use_count();
1226template <
typename RCImpl>
1227template <
typename PTR>
1230 if (
rc.inc_if_nonzero())
1231 return PTR(
static_cast<typename PTR::element_type *
>(parent),
false);
1243template <
typename RCImpl>
1248 void operator++()
noexcept;
1249 olong operator--()
noexcept;
1251#ifdef OPENVPN_RC_NOTIFY
1252 void notify_release()
noexcept;
1257#ifdef OPENVPN_RC_NOTIFY
1258 NotifyListHead notify;
1268template <
typename RCImpl>
1278template <
typename RCImpl>
1290template <
typename RCImpl>
1293 return --controller->rc;
1296#ifdef OPENVPN_RC_NOTIFY
1297template <
typename RCImpl>
1304#ifdef OPENVPN_RC_NOTIFY
1306template <
typename RCImpl>
1307class RCWeak<RCImpl>::NotifyBase
1310 NotifyBase() noexcept = default;
1311 virtual
void call() noexcept = 0;
1312 virtual ~NotifyBase() = default;
1313 NotifyBase *next =
nullptr;
1316 NotifyBase(const NotifyBase &) = delete;
1317 NotifyBase &operator=(const NotifyBase &) = delete;
1321template <typename RCImpl>
1322template <typename CALLABLE>
1323class
RCWeak<RCImpl>::NotifyItem : public NotifyBase
1326 NotifyItem(
const CALLABLE &c) noexcept
1331 NotifyItem(CALLABLE &&c) noexcept
1332 : callable(std::move(c))
1337 void call() noexcept
override
1346template <
typename RCImpl>
1347class RCWeak<RCImpl>::NotifyListHead
1350 NotifyListHead() noexcept
1354 template <
typename CALLABLE>
1355 void add(
const CALLABLE &c)
noexcept
1357 NotifyBase *item =
new NotifyItem<CALLABLE>(c);
1361 template <
typename CALLABLE>
1362 void add(CALLABLE &&c)
noexcept
1364 NotifyBase *item =
new NotifyItem<CALLABLE>(std::move(c));
1368 void release() noexcept
1373 NotifyBase *nb = head.load();
1376 NotifyBase *next = nb->next;
1384 NotifyListHead(
const NotifyListHead &) =
delete;
1385 NotifyListHead &operator=(
const NotifyListHead &) =
delete;
1387 typename RCImpl::template ListHead<NotifyBase> head;
1399template <
typename R>
1402#ifdef OPENVPN_RC_DEBUG
1403 std::cout <<
"ADD REF " <<
cxx_demangle(
typeid(rcptr).name()) << std::endl;
1417template <
typename R>
1420 if (--rcptr->refcount_ == 0)
1422#ifdef OPENVPN_RC_DEBUG
1423 std::cout <<
"DEL OBJ " <<
cxx_demangle(
typeid(rcptr).name()) << std::endl;
1425#ifdef OPENVPN_RC_NOTIFY
1426 rcptr->refcount_.notify_release();
1432#ifdef OPENVPN_RC_DEBUG
1433 std::cout <<
"REL REF " <<
cxx_demangle(
typeid(rcptr).name()) << std::endl;
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)
Support deferred server-side state creation when client connects.
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)