TLA Line data Source code
1 : //
2 : // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3 : // Copyright (c) 2026 Steve Gerbino
4 : //
5 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 : //
8 : // Official repository: https://github.com/cppalliance/corosio
9 : //
10 :
11 : #ifndef BOOST_COROSIO_DETAIL_OBJECT_REF_HPP
12 : #define BOOST_COROSIO_DETAIL_OBJECT_REF_HPP
13 :
14 : #include <boost/corosio/detail/platform.hpp>
15 : #include <boost/corosio/io/io_object.hpp>
16 : #include <atomic>
17 : #include <utility>
18 :
19 : namespace boost::corosio::detail {
20 :
21 : /// Add one reference to `impl`. `impl` must be non-null.
22 : inline void
23 HIT 105679 : acquire(io_object::implementation* impl) noexcept
24 : {
25 105679 : impl->refs_.fetch_add(1, std::memory_order_relaxed);
26 105679 : }
27 :
28 : /** Drop one reference; runs `retire()` at zero. `impl` must be
29 : non-null.
30 :
31 : Uses release on the decrement and an acquire fence before the
32 : zero-action so writes made while holding a reference are visible
33 : to the recycler. TSan cannot model a standalone fence, so under
34 : it the decrement itself is acq_rel instead -- strictly stronger,
35 : and TSan's happens-before tracking models the exchange directly.
36 : */
37 : inline void
38 126004 : release(io_object::implementation* impl) noexcept
39 : {
40 : #if BOOST_COROSIO_TSAN
41 : if (impl->refs_.fetch_sub(1, std::memory_order_acq_rel) == 1)
42 : impl->retire();
43 : #else
44 252008 : if (impl->refs_.fetch_sub(1, std::memory_order_release) == 1)
45 : {
46 : std::atomic_thread_fence(std::memory_order_acquire);
47 20325 : impl->retire();
48 : }
49 : #endif
50 126004 : }
51 :
52 : /** Owning intrusive reference to an I/O implementation.
53 :
54 : Replaces `std::shared_ptr<void>` op keepalives: copy acquires,
55 : move steals, destruction releases. Kept deliberately minimal —
56 : two words smaller than a shared_ptr and no control block.
57 : */
58 : class object_ref
59 : {
60 : io_object::implementation* p_ = nullptr;
61 :
62 : public:
63 : /// Destroy the object_ref, releasing the held reference, if any.
64 950945 : ~object_ref() { reset(); }
65 :
66 : /// Construct an object_ref holding no reference.
67 30938 : object_ref() noexcept = default;
68 :
69 : /// Construct an object_ref that acquires a new reference to `p`.
70 105659 : explicit object_ref(io_object::implementation* p) noexcept : p_(p)
71 : {
72 105659 : if (p_)
73 105659 : acquire(p_);
74 105659 : }
75 :
76 : /// Construct a copy, acquiring another reference to `other`'s target.
77 3 : object_ref(object_ref const& other) noexcept : p_(other.p_)
78 : {
79 3 : if (p_)
80 3 : acquire(p_);
81 3 : }
82 :
83 : /// Construct by transferring the reference out of `other`.
84 511944 : object_ref(object_ref&& other) noexcept
85 511944 : : p_(std::exchange(other.p_, nullptr))
86 : {
87 511944 : }
88 :
89 : /// Release the held reference, if any, and acquire `other`'s target.
90 2 : object_ref& operator=(object_ref const& other) noexcept
91 : {
92 2 : object_ref(other).swap(*this);
93 2 : return *this;
94 : }
95 :
96 : /// Release the held reference, if any, and take ownership of `other`'s.
97 408367 : object_ref& operator=(object_ref&& other) noexcept
98 : {
99 408367 : object_ref(std::move(other)).swap(*this);
100 408367 : return *this;
101 : }
102 :
103 : /// Release the held reference, if any.
104 1431925 : void reset() noexcept
105 : {
106 1431925 : if (p_)
107 105662 : release(std::exchange(p_, nullptr));
108 1431925 : }
109 :
110 : /// Return the held implementation pointer.
111 3 : io_object::implementation* get() const noexcept { return p_; }
112 :
113 : /// Return true if a reference is held.
114 13452 : explicit operator bool() const noexcept { return p_ != nullptr; }
115 :
116 : /// Exchange the implementation pointers held by `*this` and `other`.
117 408369 : void swap(object_ref& other) noexcept { std::swap(p_, other.p_); }
118 : };
119 :
120 : } // namespace boost::corosio::detail
121 :
122 : #endif
|