1 | //===-- Listener.cpp ------------------------------------------------------===// |
---|---|
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "lldb/Utility/Listener.h" |
10 | #include "lldb/Utility/Broadcaster.h" |
11 | #include "lldb/Utility/Event.h" |
12 | #include "lldb/Utility/LLDBLog.h" |
13 | |
14 | #include <algorithm> |
15 | #include <memory> |
16 | #include <utility> |
17 | |
18 | using namespace lldb; |
19 | using namespace lldb_private; |
20 | |
21 | Listener::Listener(const char *name) : m_name(name) { |
22 | LLDB_LOGF(GetLog(LLDBLog::Object), "%p Listener::Listener('%s')", |
23 | static_cast<void *>(this), m_name.c_str()); |
24 | } |
25 | |
26 | Listener::~Listener() { |
27 | // Don't call Clear() from here as that can cause races. See #96750. |
28 | |
29 | LLDB_LOGF(GetLog(LLDBLog::Object), "%p Listener::%s('%s')", |
30 | static_cast<void *>(this), __FUNCTION__, m_name.c_str()); |
31 | } |
32 | |
33 | void Listener::Clear() { |
34 | Log *log = GetLog(mask: LLDBLog::Object); |
35 | std::lock_guard<std::mutex> broadcasters_guard(m_broadcasters_mutex); |
36 | broadcaster_collection::iterator pos, end = m_broadcasters.end(); |
37 | for (pos = m_broadcasters.begin(); pos != end; ++pos) { |
38 | Broadcaster::BroadcasterImplSP broadcaster_sp(pos->first.lock()); |
39 | if (broadcaster_sp) |
40 | broadcaster_sp->RemoveListener(listener: this, event_mask: pos->second.event_mask); |
41 | } |
42 | m_broadcasters.clear(); |
43 | |
44 | std::lock_guard<std::mutex> events_guard(m_events_mutex); |
45 | m_events.clear(); |
46 | size_t num_managers = m_broadcaster_managers.size(); |
47 | |
48 | for (size_t i = 0; i < num_managers; i++) { |
49 | BroadcasterManagerSP manager_sp(m_broadcaster_managers[i].lock()); |
50 | if (manager_sp) |
51 | manager_sp->RemoveListener(listener: this); |
52 | } |
53 | |
54 | LLDB_LOGF(log, "%p Listener::%s('%s')", static_cast<void *>(this), |
55 | __FUNCTION__, m_name.c_str()); |
56 | } |
57 | |
58 | uint32_t Listener::StartListeningForEvents(Broadcaster *broadcaster, |
59 | uint32_t event_mask) { |
60 | if (broadcaster) { |
61 | // Scope for "locker" |
62 | // Tell the broadcaster to add this object as a listener |
63 | { |
64 | std::lock_guard<std::mutex> broadcasters_guard(m_broadcasters_mutex); |
65 | Broadcaster::BroadcasterImplWP impl_wp(broadcaster->GetBroadcasterImpl()); |
66 | m_broadcasters.insert( |
67 | x: std::make_pair(x&: impl_wp, y: BroadcasterInfo(event_mask))); |
68 | } |
69 | |
70 | uint32_t acquired_mask = |
71 | broadcaster->AddListener(listener_sp: this->shared_from_this(), event_mask); |
72 | |
73 | Log *log = GetLog(mask: LLDBLog::Events); |
74 | if (log != nullptr) |
75 | LLDB_LOGF(log, |
76 | "%p Listener::StartListeningForEvents (broadcaster = %p, " |
77 | "mask = 0x%8.8x) acquired_mask = 0x%8.8x for %s", |
78 | static_cast<void *>(this), static_cast<void *>(broadcaster), |
79 | event_mask, acquired_mask, m_name.c_str()); |
80 | |
81 | return acquired_mask; |
82 | } |
83 | return 0; |
84 | } |
85 | |
86 | uint32_t Listener::StartListeningForEvents(Broadcaster *broadcaster, |
87 | uint32_t event_mask, |
88 | HandleBroadcastCallback callback, |
89 | void *callback_user_data) { |
90 | if (broadcaster) { |
91 | // Scope for "locker" |
92 | // Tell the broadcaster to add this object as a listener |
93 | { |
94 | std::lock_guard<std::mutex> broadcasters_guard(m_broadcasters_mutex); |
95 | Broadcaster::BroadcasterImplWP impl_wp(broadcaster->GetBroadcasterImpl()); |
96 | m_broadcasters.insert(x: std::make_pair( |
97 | x&: impl_wp, y: BroadcasterInfo(event_mask, callback, callback_user_data))); |
98 | } |
99 | |
100 | uint32_t acquired_mask = |
101 | broadcaster->AddListener(listener_sp: this->shared_from_this(), event_mask); |
102 | |
103 | Log *log = GetLog(mask: LLDBLog::Events); |
104 | if (log != nullptr) { |
105 | void **pointer = reinterpret_cast<void **>(&callback); |
106 | LLDB_LOGF(log, |
107 | "%p Listener::StartListeningForEvents (broadcaster = %p, " |
108 | "mask = 0x%8.8x, callback = %p, user_data = %p) " |
109 | "acquired_mask = 0x%8.8x for %s", |
110 | static_cast<void *>(this), static_cast<void *>(broadcaster), |
111 | event_mask, *pointer, static_cast<void *>(callback_user_data), |
112 | acquired_mask, m_name.c_str()); |
113 | } |
114 | |
115 | return acquired_mask; |
116 | } |
117 | return 0; |
118 | } |
119 | |
120 | bool Listener::StopListeningForEvents(Broadcaster *broadcaster, |
121 | uint32_t event_mask) { |
122 | if (broadcaster) { |
123 | // Scope for "locker" |
124 | { |
125 | std::lock_guard<std::mutex> broadcasters_guard(m_broadcasters_mutex); |
126 | m_broadcasters.erase(x: broadcaster->GetBroadcasterImpl()); |
127 | } |
128 | // Remove the broadcaster from our set of broadcasters |
129 | return broadcaster->RemoveListener(listener_sp: this->shared_from_this(), event_mask); |
130 | } |
131 | |
132 | return false; |
133 | } |
134 | |
135 | // Called when a Broadcaster is in its destructor. We need to remove all |
136 | // knowledge of this broadcaster and any events that it may have queued up |
137 | void Listener::BroadcasterWillDestruct(Broadcaster *broadcaster) { |
138 | // Scope for "broadcasters_locker" |
139 | { |
140 | std::lock_guard<std::mutex> broadcasters_guard(m_broadcasters_mutex); |
141 | m_broadcasters.erase(x: broadcaster->GetBroadcasterImpl()); |
142 | } |
143 | |
144 | // Scope for "event_locker" |
145 | { |
146 | std::lock_guard<std::mutex> events_guard(m_events_mutex); |
147 | // Remove all events for this broadcaster object. |
148 | event_collection::iterator pos = m_events.begin(); |
149 | while (pos != m_events.end()) { |
150 | if ((*pos)->GetBroadcaster() == broadcaster) |
151 | pos = m_events.erase(position: pos); |
152 | else |
153 | ++pos; |
154 | } |
155 | } |
156 | } |
157 | |
158 | void Listener::BroadcasterManagerWillDestruct(BroadcasterManagerSP manager_sp) { |
159 | const auto manager_matcher = |
160 | [&manager_sp](const BroadcasterManagerWP &input_wp) -> bool { |
161 | BroadcasterManagerSP input_sp = input_wp.lock(); |
162 | return (input_sp && input_sp == manager_sp); |
163 | }; |
164 | llvm::erase_if(C&: m_broadcaster_managers, P: manager_matcher); |
165 | } |
166 | |
167 | void Listener::AddEvent(EventSP &event_sp) { |
168 | Log *log = GetLog(mask: LLDBLog::Events); |
169 | if (log != nullptr) |
170 | LLDB_LOGF(log, "%p Listener('%s')::AddEvent (event_sp = {%p})", |
171 | static_cast<void *>(this), m_name.c_str(), |
172 | static_cast<void *>(event_sp.get())); |
173 | |
174 | std::lock_guard<std::mutex> guard(m_events_mutex); |
175 | m_events.push_back(x: event_sp); |
176 | m_events_condition.notify_all(); |
177 | } |
178 | |
179 | bool Listener::FindNextEventInternal( |
180 | std::unique_lock<std::mutex> &lock, |
181 | Broadcaster *broadcaster, // nullptr for any broadcaster |
182 | uint32_t event_type_mask, EventSP &event_sp, bool remove) { |
183 | // NOTE: callers of this function must lock m_events_mutex using a |
184 | // Mutex::Locker |
185 | // and pass the locker as the first argument. m_events_mutex is no longer |
186 | // recursive. |
187 | Log *log = GetLog(mask: LLDBLog::Events); |
188 | |
189 | if (m_events.empty()) |
190 | return false; |
191 | |
192 | const auto event_matcher = |
193 | [broadcaster, event_type_mask](const EventSP &event_sp) -> bool { |
194 | if (broadcaster && !event_sp->BroadcasterIs(broadcaster)) |
195 | return false; |
196 | return event_type_mask == 0 || event_type_mask & event_sp->GetType(); |
197 | }; |
198 | Listener::event_collection::iterator pos = m_events.end(); |
199 | |
200 | if (broadcaster == nullptr && event_type_mask == 0) |
201 | pos = m_events.begin(); |
202 | else |
203 | pos = llvm::find_if(Range&: m_events, P: event_matcher); |
204 | |
205 | if (pos != m_events.end()) { |
206 | event_sp = *pos; |
207 | |
208 | if (log != nullptr) |
209 | LLDB_LOGF(log, |
210 | "%p '%s' Listener::FindNextEventInternal(broadcaster=%p, " |
211 | "event_type_mask=0x%8.8x, " |
212 | "remove=%i) event %p", |
213 | static_cast<void *>(this), GetName(), |
214 | static_cast<void *>(broadcaster), event_type_mask, remove, |
215 | static_cast<void *>(event_sp.get())); |
216 | |
217 | if (remove) { |
218 | m_events.erase(position: pos); |
219 | // Unlock the event queue here. We've removed this event and are about |
220 | // to return it so it should be okay to get the next event off the queue |
221 | // here - and it might be useful to do that in the "DoOnRemoval". |
222 | lock.unlock(); |
223 | event_sp->DoOnRemoval(); |
224 | } |
225 | return true; |
226 | } |
227 | |
228 | event_sp.reset(); |
229 | return false; |
230 | } |
231 | |
232 | Event *Listener::PeekAtNextEvent() { |
233 | std::unique_lock<std::mutex> guard(m_events_mutex); |
234 | EventSP event_sp; |
235 | if (FindNextEventInternal(lock&: guard, broadcaster: nullptr, event_type_mask: 0, event_sp, remove: false)) |
236 | return event_sp.get(); |
237 | return nullptr; |
238 | } |
239 | |
240 | Event *Listener::PeekAtNextEventForBroadcaster(Broadcaster *broadcaster) { |
241 | std::unique_lock<std::mutex> guard(m_events_mutex); |
242 | EventSP event_sp; |
243 | if (FindNextEventInternal(lock&: guard, broadcaster, event_type_mask: 0, event_sp, remove: false)) |
244 | return event_sp.get(); |
245 | return nullptr; |
246 | } |
247 | |
248 | Event * |
249 | Listener::PeekAtNextEventForBroadcasterWithType(Broadcaster *broadcaster, |
250 | uint32_t event_type_mask) { |
251 | std::unique_lock<std::mutex> guard(m_events_mutex); |
252 | EventSP event_sp; |
253 | if (FindNextEventInternal(lock&: guard, broadcaster, event_type_mask, event_sp, |
254 | remove: false)) |
255 | return event_sp.get(); |
256 | return nullptr; |
257 | } |
258 | |
259 | bool Listener::GetEventInternal( |
260 | const Timeout<std::micro> &timeout, |
261 | Broadcaster *broadcaster, // nullptr for any broadcaster |
262 | uint32_t event_type_mask, EventSP &event_sp) { |
263 | Log *log = GetLog(mask: LLDBLog::Events); |
264 | LLDB_LOG(log, "this = {0}, timeout = {1} for {2}", this, timeout, m_name); |
265 | |
266 | std::unique_lock<std::mutex> lock(m_events_mutex); |
267 | |
268 | while (true) { |
269 | if (FindNextEventInternal(lock, broadcaster, event_type_mask, event_sp, |
270 | remove: true)) { |
271 | return true; |
272 | } else { |
273 | std::cv_status result = std::cv_status::no_timeout; |
274 | if (!timeout) |
275 | m_events_condition.wait(lock&: lock); |
276 | else |
277 | result = m_events_condition.wait_for(lock&: lock, rtime: *timeout); |
278 | |
279 | if (result == std::cv_status::timeout) { |
280 | log = GetLog(mask: LLDBLog::Events); |
281 | LLDB_LOGF(log, "%p Listener::GetEventInternal() timed out for %s", |
282 | static_cast<void *>(this), m_name.c_str()); |
283 | return false; |
284 | } else if (result != std::cv_status::no_timeout) { |
285 | log = GetLog(mask: LLDBLog::Events); |
286 | LLDB_LOGF(log, "%p Listener::GetEventInternal() unknown error for %s", |
287 | static_cast<void *>(this), m_name.c_str()); |
288 | return false; |
289 | } |
290 | } |
291 | } |
292 | |
293 | return false; |
294 | } |
295 | |
296 | bool Listener::GetEventForBroadcasterWithType( |
297 | Broadcaster *broadcaster, uint32_t event_type_mask, EventSP &event_sp, |
298 | const Timeout<std::micro> &timeout) { |
299 | return GetEventInternal(timeout, broadcaster, event_type_mask, event_sp); |
300 | } |
301 | |
302 | bool Listener::GetEventForBroadcaster(Broadcaster *broadcaster, |
303 | EventSP &event_sp, |
304 | const Timeout<std::micro> &timeout) { |
305 | return GetEventInternal(timeout, broadcaster, event_type_mask: 0, event_sp); |
306 | } |
307 | |
308 | bool Listener::GetEvent(EventSP &event_sp, const Timeout<std::micro> &timeout) { |
309 | return GetEventInternal(timeout, broadcaster: nullptr, event_type_mask: 0, event_sp); |
310 | } |
311 | |
312 | size_t Listener::HandleBroadcastEvent(EventSP &event_sp) { |
313 | size_t num_handled = 0; |
314 | std::lock_guard<std::mutex> guard(m_broadcasters_mutex); |
315 | Broadcaster *broadcaster = event_sp->GetBroadcaster(); |
316 | if (!broadcaster) |
317 | return 0; |
318 | broadcaster_collection::iterator pos; |
319 | broadcaster_collection::iterator end = m_broadcasters.end(); |
320 | Broadcaster::BroadcasterImplSP broadcaster_impl_sp( |
321 | broadcaster->GetBroadcasterImpl()); |
322 | for (pos = m_broadcasters.find(x: broadcaster_impl_sp); |
323 | pos != end && pos->first.lock() == broadcaster_impl_sp; ++pos) { |
324 | BroadcasterInfo info = pos->second; |
325 | if (event_sp->GetType() & info.event_mask) { |
326 | if (info.callback != nullptr) { |
327 | info.callback(event_sp, info.callback_user_data); |
328 | ++num_handled; |
329 | } |
330 | } |
331 | } |
332 | return num_handled; |
333 | } |
334 | |
335 | uint32_t |
336 | Listener::StartListeningForEventSpec(const BroadcasterManagerSP &manager_sp, |
337 | const BroadcastEventSpec &event_spec) { |
338 | if (!manager_sp) |
339 | return 0; |
340 | |
341 | const auto manager_matcher = |
342 | [&manager_sp](const BroadcasterManagerWP &input_wp) -> bool { |
343 | BroadcasterManagerSP input_sp = input_wp.lock(); |
344 | return (input_sp && input_sp == manager_sp); |
345 | }; |
346 | // The BroadcasterManager mutex must be locked before m_broadcasters_mutex to |
347 | // avoid violating the lock hierarchy (manager before broadcasters). |
348 | std::lock_guard<std::mutex> manager_guard(manager_sp->m_manager_mutex); |
349 | std::lock_guard<std::mutex> guard(m_broadcasters_mutex); |
350 | |
351 | uint32_t bits_acquired = manager_sp->RegisterListenerForEventsNoLock( |
352 | listener_sp: this->shared_from_this(), event_spec); |
353 | if (bits_acquired) { |
354 | BroadcasterManagerWP manager_wp(manager_sp); |
355 | if (llvm::none_of(Range&: m_broadcaster_managers, P: manager_matcher)) |
356 | m_broadcaster_managers.push_back(x: manager_wp); |
357 | } |
358 | |
359 | return bits_acquired; |
360 | } |
361 | |
362 | bool Listener::StopListeningForEventSpec(const BroadcasterManagerSP &manager_sp, |
363 | const BroadcastEventSpec &event_spec) { |
364 | if (!manager_sp) |
365 | return false; |
366 | |
367 | // The BroadcasterManager mutex must be locked before m_broadcasters_mutex to |
368 | // avoid violating the lock hierarchy (manager before broadcasters). |
369 | std::lock_guard<std::mutex> manager_guard(manager_sp->m_manager_mutex); |
370 | std::lock_guard<std::mutex> guard(m_broadcasters_mutex); |
371 | return manager_sp->UnregisterListenerForEventsNoLock(listener_sp: this->shared_from_this(), |
372 | event_spec); |
373 | } |
374 | |
375 | ListenerSP Listener::MakeListener(const char *name) { |
376 | return ListenerSP(new Listener(name)); |
377 | } |
378 |
Definitions
- Listener
- ~Listener
- Clear
- StartListeningForEvents
- StartListeningForEvents
- StopListeningForEvents
- BroadcasterWillDestruct
- BroadcasterManagerWillDestruct
- AddEvent
- FindNextEventInternal
- PeekAtNextEvent
- PeekAtNextEventForBroadcaster
- PeekAtNextEventForBroadcasterWithType
- GetEventInternal
- GetEventForBroadcasterWithType
- GetEventForBroadcaster
- GetEvent
- HandleBroadcastEvent
- StartListeningForEventSpec
- StopListeningForEventSpec
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more