1717
1818namespace srsran {
1919
20- // / \brief Observer of calls to stop() on the associated stop_event_source.
21- // /
22- // / When it gets reset or destroyed, it notifies the stop_event_source that one observer is gone.
23- class stop_event_token
24- {
25- static constexpr uint32_t stop_bit = 1U << 31U ;
26- static constexpr uint32_t count_mask = stop_bit - 1 ;
27-
28- public:
29- stop_event_token () = default ;
30- stop_event_token (std::atomic<uint32_t >& token_count_, std::atomic<bool >& dtor_guard_) :
31- token_count (&token_count_), dtor_guard(&dtor_guard_)
32- {
33- inc_token ();
34- }
35-
36- stop_event_token (const stop_event_token& other) : token_count(other.token_count), dtor_guard(other.dtor_guard)
37- {
38- inc_token ();
39- }
40- stop_event_token (stop_event_token&& other) noexcept :
41- token_count (std::exchange(other.token_count, nullptr )), dtor_guard(std::exchange(other.dtor_guard, nullptr ))
42- {
43- }
44-
45- stop_event_token& operator =(const stop_event_token& other)
46- {
47- if (this != &other) {
48- reset ();
49- token_count = other.token_count ;
50- dtor_guard = other.dtor_guard ;
51- inc_token ();
52- }
53- return *this ;
54- }
55- stop_event_token& operator =(stop_event_token&& other) noexcept
56- {
57- reset ();
58- token_count = std::exchange (other.token_count , nullptr );
59- dtor_guard = std::exchange (other.dtor_guard , nullptr );
60- return *this ;
61- }
62-
63- ~stop_event_token ()
64- {
65- if (token_count != nullptr ) {
66- auto cur = token_count->fetch_sub (1 , std::memory_order_acq_rel) - 1 ;
67- if ((cur & count_mask) == 0 ) {
68- // count reached zero.
69- // Wake all stoppers.
70- futex_util::wake_all (*token_count);
71- // Update dtor guard.
72- dtor_guard->store (false , std::memory_order_release);
73- }
74- token_count = nullptr ;
75- dtor_guard = nullptr ;
76- }
77- }
78-
79- // / Checks if the associated stop_event_source has been stopped.
80- [[nodiscard]] bool stop_requested () const
81- {
82- return token_count == nullptr or (token_count->load (std::memory_order_acquire) & stop_bit) > 0 ;
83- }
84-
85- // / Destroys the observer.
86- void reset () { stop_event_token{}.swap (*this ); }
87-
88- void swap (stop_event_token& other) noexcept
89- {
90- std::swap (token_count, other.token_count );
91- std::swap (dtor_guard, other.dtor_guard );
92- }
93-
94- private:
95- void inc_token ()
96- {
97- if (token_count == nullptr ) {
98- return ;
99- }
100- auto prev = token_count->fetch_add (1 , std::memory_order_relaxed);
101- if ((prev & count_mask) == 0 ) {
102- // Transition from 0 to 1. Update dtor guard.
103- dtor_guard->store (true , std::memory_order_release);
104- }
105- if (prev & stop_bit) {
106- // Stop was already requested. Release token.
107- reset ();
108- }
109- }
110-
111- std::atomic<uint32_t >* token_count = nullptr ;
112- std::atomic<bool >* dtor_guard = nullptr ;
113- };
20+ class stop_event_token ;
11421
11522// / \brief Event to signal stop to multiple observers.
11623// /
@@ -133,7 +40,7 @@ class stop_event_source
13340 }
13441
13542 // / Creates a new observer of stop() requests.
136- [[nodiscard]] stop_event_token get_token () { return stop_event_token{token_count, dtor_guard}; }
43+ [[nodiscard]] stop_event_token get_token ();
13744
13845 // / Requests all tokens to stop and blocks until all tokens are reset.
13946 void stop ()
@@ -174,10 +81,94 @@ class stop_event_source
17481 [[nodiscard]] uint32_t nof_tokens_approx () const { return token_count.load (std::memory_order_relaxed) & count_mask; }
17582
17683private:
84+ friend stop_event_token;
85+
17786 // / State variable composed by 1 MSB bit for signalling stop and 31 LSB bits for counting observers.
17887 std::atomic<uint32_t > token_count{0 };
17988 // / Variable used to protect token_count from destruction when token still has to call futex wake.
18089 std::atomic<bool > dtor_guard{false };
18190};
18291
92+ // / \brief Observer of calls to stop() on the associated stop_event_source.
93+ // /
94+ // / When it gets reset or destroyed, it notifies the stop_event_source that one observer is gone.
95+ class stop_event_token
96+ {
97+ static constexpr uint32_t stop_bit = 1U << 31U ;
98+ static constexpr uint32_t count_mask = stop_bit - 1 ;
99+
100+ public:
101+ stop_event_token () = default ;
102+ explicit stop_event_token (stop_event_source& parent_) : parent(&parent_) { inc_token (); }
103+
104+ stop_event_token (const stop_event_token& other) : parent(other.parent) { inc_token (); }
105+ stop_event_token (stop_event_token&& other) noexcept : parent(std::exchange(other.parent, nullptr )) {}
106+
107+ stop_event_token& operator =(const stop_event_token& other)
108+ {
109+ if (this != &other) {
110+ reset ();
111+ parent = other.parent ;
112+ inc_token ();
113+ }
114+ return *this ;
115+ }
116+ stop_event_token& operator =(stop_event_token&& other) noexcept
117+ {
118+ reset ();
119+ parent = std::exchange (other.parent , nullptr );
120+ return *this ;
121+ }
122+
123+ ~stop_event_token ()
124+ {
125+ if (parent != nullptr ) {
126+ auto cur = parent->token_count .fetch_sub (1 , std::memory_order_acq_rel) - 1 ;
127+ if ((cur & count_mask) == 0 ) {
128+ // count reached zero.
129+ // Wake all stoppers.
130+ futex_util::wake_all (parent->token_count );
131+ // Update dtor guard.
132+ parent->dtor_guard .store (false , std::memory_order_release);
133+ }
134+ parent = nullptr ;
135+ }
136+ }
137+
138+ // / Checks if the associated stop_event_source has been stopped.
139+ [[nodiscard]] bool stop_requested () const
140+ {
141+ return (parent == nullptr ) or ((parent->token_count .load (std::memory_order_acquire) & stop_bit) > 0 );
142+ }
143+
144+ // / Destroys the observer.
145+ void reset () { stop_event_token{}.swap (*this ); }
146+
147+ void swap (stop_event_token& other) noexcept { std::swap (parent, other.parent ); }
148+
149+ private:
150+ void inc_token ()
151+ {
152+ if (parent == nullptr ) {
153+ return ;
154+ }
155+ auto prev = parent->token_count .fetch_add (1 , std::memory_order_relaxed);
156+ if ((prev & count_mask) == 0 ) {
157+ // Transition from 0 to 1. Update dtor guard.
158+ parent->dtor_guard .store (true , std::memory_order_release);
159+ }
160+ if (prev & stop_bit) {
161+ // Stop was already requested. Release token.
162+ reset ();
163+ }
164+ }
165+
166+ stop_event_source* parent = nullptr ;
167+ };
168+
169+ inline stop_event_token stop_event_source::get_token ()
170+ {
171+ return stop_event_token{*this };
172+ }
173+
183174} // namespace srsran
0 commit comments