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
18using namespace lldb;
19using namespace lldb_private;
20
21Listener::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
26Listener::~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
33void 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
58uint32_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
86uint32_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
120bool 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
137void 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
158void 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
167void 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
179bool 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
232Event *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
240Event *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
248Event *
249Listener::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
259bool 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
296bool 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
302bool 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
308bool Listener::GetEvent(EventSP &event_sp, const Timeout<std::micro> &timeout) {
309 return GetEventInternal(timeout, broadcaster: nullptr, event_type_mask: 0, event_sp);
310}
311
312size_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
335uint32_t
336Listener::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
362bool 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
375ListenerSP Listener::MakeListener(const char *name) {
376 return ListenerSP(new Listener(name));
377}
378

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

source code of lldb/source/Utility/Listener.cpp