xref: /freebsd/contrib/llvm-project/lldb/source/Utility/Listener.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
Listener(const char * name)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 
~Listener()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 
Clear()33 void Listener::Clear() {
34   Log *log = GetLog(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(this, 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(this);
52   }
53 
54   LLDB_LOGF(log, "%p Listener::%s('%s')", static_cast<void *>(this),
55             __FUNCTION__, m_name.c_str());
56 }
57 
StartListeningForEvents(Broadcaster * broadcaster,uint32_t event_mask)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           std::make_pair(impl_wp, BroadcasterInfo(event_mask)));
68     }
69 
70     uint32_t acquired_mask =
71         broadcaster->AddListener(this->shared_from_this(), event_mask);
72 
73     Log *log = GetLog(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 
StartListeningForEvents(Broadcaster * broadcaster,uint32_t event_mask,HandleBroadcastCallback callback,void * callback_user_data)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(std::make_pair(
97           impl_wp, BroadcasterInfo(event_mask, callback, callback_user_data)));
98     }
99 
100     uint32_t acquired_mask =
101         broadcaster->AddListener(this->shared_from_this(), event_mask);
102 
103     Log *log = GetLog(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 
StopListeningForEvents(Broadcaster * broadcaster,uint32_t event_mask)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(broadcaster->GetBroadcasterImpl());
127     }
128     // Remove the broadcaster from our set of broadcasters
129     return broadcaster->RemoveListener(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
BroadcasterWillDestruct(Broadcaster * broadcaster)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(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(pos);
152       else
153         ++pos;
154     }
155   }
156 }
157 
BroadcasterManagerWillDestruct(BroadcasterManagerSP manager_sp)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(m_broadcaster_managers, manager_matcher);
165 }
166 
AddEvent(EventSP & event_sp)167 void Listener::AddEvent(EventSP &event_sp) {
168   Log *log = GetLog(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(event_sp);
176   m_events_condition.notify_all();
177 }
178 
FindNextEventInternal(std::unique_lock<std::mutex> & lock,Broadcaster * broadcaster,uint32_t event_type_mask,EventSP & event_sp,bool remove)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(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(m_events, 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(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 
PeekAtNextEvent()232 Event *Listener::PeekAtNextEvent() {
233   std::unique_lock<std::mutex> guard(m_events_mutex);
234   EventSP event_sp;
235   if (FindNextEventInternal(guard, nullptr, 0, event_sp, false))
236     return event_sp.get();
237   return nullptr;
238 }
239 
PeekAtNextEventForBroadcaster(Broadcaster * broadcaster)240 Event *Listener::PeekAtNextEventForBroadcaster(Broadcaster *broadcaster) {
241   std::unique_lock<std::mutex> guard(m_events_mutex);
242   EventSP event_sp;
243   if (FindNextEventInternal(guard, broadcaster, 0, event_sp, false))
244     return event_sp.get();
245   return nullptr;
246 }
247 
248 Event *
PeekAtNextEventForBroadcasterWithType(Broadcaster * broadcaster,uint32_t event_type_mask)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(guard, broadcaster, event_type_mask, event_sp,
254                             false))
255     return event_sp.get();
256   return nullptr;
257 }
258 
GetEventInternal(const Timeout<std::micro> & timeout,Broadcaster * broadcaster,uint32_t event_type_mask,EventSP & event_sp)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(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                               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);
276       else
277         result = m_events_condition.wait_for(lock, *timeout);
278 
279       if (result == std::cv_status::timeout) {
280         log = GetLog(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(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 
GetEventForBroadcasterWithType(Broadcaster * broadcaster,uint32_t event_type_mask,EventSP & event_sp,const Timeout<std::micro> & timeout)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 
GetEventForBroadcaster(Broadcaster * broadcaster,EventSP & event_sp,const Timeout<std::micro> & timeout)302 bool Listener::GetEventForBroadcaster(Broadcaster *broadcaster,
303                                       EventSP &event_sp,
304                                       const Timeout<std::micro> &timeout) {
305   return GetEventInternal(timeout, broadcaster, 0, event_sp);
306 }
307 
GetEvent(EventSP & event_sp,const Timeout<std::micro> & timeout)308 bool Listener::GetEvent(EventSP &event_sp, const Timeout<std::micro> &timeout) {
309   return GetEventInternal(timeout, nullptr, 0, event_sp);
310 }
311 
HandleBroadcastEvent(EventSP & event_sp)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(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
StartListeningForEventSpec(const BroadcasterManagerSP & manager_sp,const BroadcastEventSpec & event_spec)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       this->shared_from_this(), event_spec);
353   if (bits_acquired) {
354     BroadcasterManagerWP manager_wp(manager_sp);
355     auto iter = llvm::find_if(m_broadcaster_managers, manager_matcher);
356     if (iter == m_broadcaster_managers.end())
357       m_broadcaster_managers.push_back(manager_wp);
358   }
359 
360   return bits_acquired;
361 }
362 
StopListeningForEventSpec(const BroadcasterManagerSP & manager_sp,const BroadcastEventSpec & event_spec)363 bool Listener::StopListeningForEventSpec(const BroadcasterManagerSP &manager_sp,
364                                          const BroadcastEventSpec &event_spec) {
365   if (!manager_sp)
366     return false;
367 
368   // The BroadcasterManager mutex must be locked before m_broadcasters_mutex to
369   // avoid violating the lock hierarchy (manager before broadcasters).
370   std::lock_guard<std::mutex> manager_guard(manager_sp->m_manager_mutex);
371   std::lock_guard<std::mutex> guard(m_broadcasters_mutex);
372   return manager_sp->UnregisterListenerForEventsNoLock(this->shared_from_this(),
373                                                        event_spec);
374 }
375 
MakeListener(const char * name)376 ListenerSP Listener::MakeListener(const char *name) {
377   return ListenerSP(new Listener(name));
378 }
379