//===-- Listener.cpp --------------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "lldb/Utility/Listener.h" #include "lldb/Utility/Broadcaster.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/Event.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Logging.h" #include "llvm/ADT/Optional.h" #include #include #include using namespace lldb; using namespace lldb_private; namespace { class BroadcasterManagerWPMatcher { public: BroadcasterManagerWPMatcher(BroadcasterManagerSP manager_sp) : m_manager_sp(std::move(manager_sp)) {} bool operator()(const BroadcasterManagerWP &input_wp) const { BroadcasterManagerSP input_sp = input_wp.lock(); return (input_sp && input_sp == m_manager_sp); } BroadcasterManagerSP m_manager_sp; }; } // anonymous namespace Listener::Listener(const char *name) : m_name(name), m_broadcasters(), m_broadcasters_mutex(), m_events(), m_events_mutex() { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); if (log != nullptr) LLDB_LOGF(log, "%p Listener::Listener('%s')", static_cast(this), m_name.c_str()); } Listener::~Listener() { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); Clear(); LLDB_LOGF(log, "%p Listener::%s('%s')", static_cast(this), __FUNCTION__, m_name.c_str()); } void Listener::Clear() { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); std::lock_guard broadcasters_guard( m_broadcasters_mutex); broadcaster_collection::iterator pos, end = m_broadcasters.end(); for (pos = m_broadcasters.begin(); pos != end; ++pos) { Broadcaster::BroadcasterImplSP broadcaster_sp(pos->first.lock()); if (broadcaster_sp) broadcaster_sp->RemoveListener(this, pos->second.event_mask); } m_broadcasters.clear(); std::lock_guard events_guard(m_events_mutex); m_events.clear(); size_t num_managers = m_broadcaster_managers.size(); for (size_t i = 0; i < num_managers; i++) { BroadcasterManagerSP manager_sp(m_broadcaster_managers[i].lock()); if (manager_sp) manager_sp->RemoveListener(this); } LLDB_LOGF(log, "%p Listener::%s('%s')", static_cast(this), __FUNCTION__, m_name.c_str()); } uint32_t Listener::StartListeningForEvents(Broadcaster *broadcaster, uint32_t event_mask) { if (broadcaster) { // Scope for "locker" // Tell the broadcaster to add this object as a listener { std::lock_guard broadcasters_guard( m_broadcasters_mutex); Broadcaster::BroadcasterImplWP impl_wp(broadcaster->GetBroadcasterImpl()); m_broadcasters.insert( std::make_pair(impl_wp, BroadcasterInfo(event_mask))); } uint32_t acquired_mask = broadcaster->AddListener(this->shared_from_this(), event_mask); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS)); if (log != nullptr) LLDB_LOGF(log, "%p Listener::StartListeningForEvents (broadcaster = %p, " "mask = 0x%8.8x) acquired_mask = 0x%8.8x for %s", static_cast(this), static_cast(broadcaster), event_mask, acquired_mask, m_name.c_str()); return acquired_mask; } return 0; } uint32_t Listener::StartListeningForEvents(Broadcaster *broadcaster, uint32_t event_mask, HandleBroadcastCallback callback, void *callback_user_data) { if (broadcaster) { // Scope for "locker" // Tell the broadcaster to add this object as a listener { std::lock_guard broadcasters_guard( m_broadcasters_mutex); Broadcaster::BroadcasterImplWP impl_wp(broadcaster->GetBroadcasterImpl()); m_broadcasters.insert(std::make_pair( impl_wp, BroadcasterInfo(event_mask, callback, callback_user_data))); } uint32_t acquired_mask = broadcaster->AddListener(this->shared_from_this(), event_mask); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS)); if (log != nullptr) { void **pointer = reinterpret_cast(&callback); LLDB_LOGF(log, "%p Listener::StartListeningForEvents (broadcaster = %p, " "mask = 0x%8.8x, callback = %p, user_data = %p) " "acquired_mask = 0x%8.8x for %s", static_cast(this), static_cast(broadcaster), event_mask, *pointer, static_cast(callback_user_data), acquired_mask, m_name.c_str()); } return acquired_mask; } return 0; } bool Listener::StopListeningForEvents(Broadcaster *broadcaster, uint32_t event_mask) { if (broadcaster) { // Scope for "locker" { std::lock_guard broadcasters_guard( m_broadcasters_mutex); m_broadcasters.erase(broadcaster->GetBroadcasterImpl()); } // Remove the broadcaster from our set of broadcasters return broadcaster->RemoveListener(this->shared_from_this(), event_mask); } return false; } // Called when a Broadcaster is in its destructor. We need to remove all // knowledge of this broadcaster and any events that it may have queued up void Listener::BroadcasterWillDestruct(Broadcaster *broadcaster) { // Scope for "broadcasters_locker" { std::lock_guard broadcasters_guard( m_broadcasters_mutex); m_broadcasters.erase(broadcaster->GetBroadcasterImpl()); } // Scope for "event_locker" { std::lock_guard events_guard(m_events_mutex); // Remove all events for this broadcaster object. event_collection::iterator pos = m_events.begin(); while (pos != m_events.end()) { if ((*pos)->GetBroadcaster() == broadcaster) pos = m_events.erase(pos); else ++pos; } } } void Listener::BroadcasterManagerWillDestruct(BroadcasterManagerSP manager_sp) { // Just need to remove this broadcast manager from the list of managers: broadcaster_manager_collection::iterator iter, end_iter = m_broadcaster_managers.end(); BroadcasterManagerWP manager_wp; BroadcasterManagerWPMatcher matcher(std::move(manager_sp)); iter = std::find_if( m_broadcaster_managers.begin(), end_iter, matcher); if (iter != end_iter) m_broadcaster_managers.erase(iter); } void Listener::AddEvent(EventSP &event_sp) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS)); if (log != nullptr) LLDB_LOGF(log, "%p Listener('%s')::AddEvent (event_sp = {%p})", static_cast(this), m_name.c_str(), static_cast(event_sp.get())); std::lock_guard guard(m_events_mutex); m_events.push_back(event_sp); m_events_condition.notify_all(); } class EventBroadcasterMatches { public: EventBroadcasterMatches(Broadcaster *broadcaster) : m_broadcaster(broadcaster) {} bool operator()(const EventSP &event_sp) const { return event_sp->BroadcasterIs(m_broadcaster); } private: Broadcaster *m_broadcaster; }; class EventMatcher { public: EventMatcher(Broadcaster *broadcaster, const ConstString *broadcaster_names, uint32_t num_broadcaster_names, uint32_t event_type_mask) : m_broadcaster(broadcaster), m_broadcaster_names(broadcaster_names), m_num_broadcaster_names(num_broadcaster_names), m_event_type_mask(event_type_mask) {} bool operator()(const EventSP &event_sp) const { if (m_broadcaster && !event_sp->BroadcasterIs(m_broadcaster)) return false; if (m_broadcaster_names) { bool found_source = false; ConstString event_broadcaster_name = event_sp->GetBroadcaster()->GetBroadcasterName(); for (uint32_t i = 0; i < m_num_broadcaster_names; ++i) { if (m_broadcaster_names[i] == event_broadcaster_name) { found_source = true; break; } } if (!found_source) return false; } return m_event_type_mask == 0 || m_event_type_mask & event_sp->GetType(); } private: Broadcaster *m_broadcaster; const ConstString *m_broadcaster_names; const uint32_t m_num_broadcaster_names; const uint32_t m_event_type_mask; }; bool Listener::FindNextEventInternal( std::unique_lock &lock, Broadcaster *broadcaster, // nullptr for any broadcaster const ConstString *broadcaster_names, // nullptr for any event uint32_t num_broadcaster_names, uint32_t event_type_mask, EventSP &event_sp, bool remove) { // NOTE: callers of this function must lock m_events_mutex using a // Mutex::Locker // and pass the locker as the first argument. m_events_mutex is no longer // recursive. Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS)); if (m_events.empty()) return false; Listener::event_collection::iterator pos = m_events.end(); if (broadcaster == nullptr && broadcaster_names == nullptr && event_type_mask == 0) { pos = m_events.begin(); } else { pos = std::find_if(m_events.begin(), m_events.end(), EventMatcher(broadcaster, broadcaster_names, num_broadcaster_names, event_type_mask)); } if (pos != m_events.end()) { event_sp = *pos; if (log != nullptr) LLDB_LOGF(log, "%p '%s' Listener::FindNextEventInternal(broadcaster=%p, " "broadcaster_names=%p[%u], event_type_mask=0x%8.8x, " "remove=%i) event %p", static_cast(this), GetName(), static_cast(broadcaster), static_cast(broadcaster_names), num_broadcaster_names, event_type_mask, remove, static_cast(event_sp.get())); if (remove) { m_events.erase(pos); // Unlock the event queue here. We've removed this event and are about // to return it so it should be okay to get the next event off the queue // here - and it might be useful to do that in the "DoOnRemoval". lock.unlock(); event_sp->DoOnRemoval(); } return true; } event_sp.reset(); return false; } Event *Listener::PeekAtNextEvent() { std::unique_lock guard(m_events_mutex); EventSP event_sp; if (FindNextEventInternal(guard, nullptr, nullptr, 0, 0, event_sp, false)) return event_sp.get(); return nullptr; } Event *Listener::PeekAtNextEventForBroadcaster(Broadcaster *broadcaster) { std::unique_lock guard(m_events_mutex); EventSP event_sp; if (FindNextEventInternal(guard, broadcaster, nullptr, 0, 0, event_sp, false)) return event_sp.get(); return nullptr; } Event * Listener::PeekAtNextEventForBroadcasterWithType(Broadcaster *broadcaster, uint32_t event_type_mask) { std::unique_lock guard(m_events_mutex); EventSP event_sp; if (FindNextEventInternal(guard, broadcaster, nullptr, 0, event_type_mask, event_sp, false)) return event_sp.get(); return nullptr; } bool Listener::GetEventInternal( const Timeout &timeout, Broadcaster *broadcaster, // nullptr for any broadcaster const ConstString *broadcaster_names, // nullptr for any event uint32_t num_broadcaster_names, uint32_t event_type_mask, EventSP &event_sp) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS)); LLDB_LOG(log, "this = {0}, timeout = {1} for {2}", this, timeout, m_name); std::unique_lock lock(m_events_mutex); while (true) { if (FindNextEventInternal(lock, broadcaster, broadcaster_names, num_broadcaster_names, event_type_mask, event_sp, true)) { return true; } else { std::cv_status result = std::cv_status::no_timeout; if (!timeout) m_events_condition.wait(lock); else result = m_events_condition.wait_for(lock, *timeout); if (result == std::cv_status::timeout) { log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS); LLDB_LOGF(log, "%p Listener::GetEventInternal() timed out for %s", static_cast(this), m_name.c_str()); return false; } else if (result != std::cv_status::no_timeout) { log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS); LLDB_LOGF(log, "%p Listener::GetEventInternal() unknown error for %s", static_cast(this), m_name.c_str()); return false; } } } return false; } bool Listener::GetEventForBroadcasterWithType( Broadcaster *broadcaster, uint32_t event_type_mask, EventSP &event_sp, const Timeout &timeout) { return GetEventInternal(timeout, broadcaster, nullptr, 0, event_type_mask, event_sp); } bool Listener::GetEventForBroadcaster(Broadcaster *broadcaster, EventSP &event_sp, const Timeout &timeout) { return GetEventInternal(timeout, broadcaster, nullptr, 0, 0, event_sp); } bool Listener::GetEvent(EventSP &event_sp, const Timeout &timeout) { return GetEventInternal(timeout, nullptr, nullptr, 0, 0, event_sp); } size_t Listener::HandleBroadcastEvent(EventSP &event_sp) { size_t num_handled = 0; std::lock_guard guard(m_broadcasters_mutex); Broadcaster *broadcaster = event_sp->GetBroadcaster(); if (!broadcaster) return 0; broadcaster_collection::iterator pos; broadcaster_collection::iterator end = m_broadcasters.end(); Broadcaster::BroadcasterImplSP broadcaster_impl_sp( broadcaster->GetBroadcasterImpl()); for (pos = m_broadcasters.find(broadcaster_impl_sp); pos != end && pos->first.lock() == broadcaster_impl_sp; ++pos) { BroadcasterInfo info = pos->second; if (event_sp->GetType() & info.event_mask) { if (info.callback != nullptr) { info.callback(event_sp, info.callback_user_data); ++num_handled; } } } return num_handled; } uint32_t Listener::StartListeningForEventSpec(const BroadcasterManagerSP &manager_sp, const BroadcastEventSpec &event_spec) { if (!manager_sp) return 0; // The BroadcasterManager mutex must be locked before m_broadcasters_mutex to // avoid violating the lock hierarchy (manager before broadcasters). std::lock_guard manager_guard( manager_sp->m_manager_mutex); std::lock_guard guard(m_broadcasters_mutex); uint32_t bits_acquired = manager_sp->RegisterListenerForEvents( this->shared_from_this(), event_spec); if (bits_acquired) { broadcaster_manager_collection::iterator iter, end_iter = m_broadcaster_managers.end(); BroadcasterManagerWP manager_wp(manager_sp); BroadcasterManagerWPMatcher matcher(manager_sp); iter = std::find_if( m_broadcaster_managers.begin(), end_iter, matcher); if (iter == end_iter) m_broadcaster_managers.push_back(manager_wp); } return bits_acquired; } bool Listener::StopListeningForEventSpec(const BroadcasterManagerSP &manager_sp, const BroadcastEventSpec &event_spec) { if (!manager_sp) return false; std::lock_guard guard(m_broadcasters_mutex); return manager_sp->UnregisterListenerForEvents(this->shared_from_this(), event_spec); } ListenerSP Listener::MakeListener(const char *name) { return ListenerSP(new Listener(name)); }