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