diff options
Diffstat (limited to 'source/Utility/Broadcaster.cpp')
| -rw-r--r-- | source/Utility/Broadcaster.cpp | 479 |
1 files changed, 479 insertions, 0 deletions
diff --git a/source/Utility/Broadcaster.cpp b/source/Utility/Broadcaster.cpp new file mode 100644 index 000000000000..5b9b99801b22 --- /dev/null +++ b/source/Utility/Broadcaster.cpp @@ -0,0 +1,479 @@ +//===-- Broadcaster.cpp -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Utility/Broadcaster.h" + +#include "lldb/Utility/Event.h" +#include "lldb/Utility/Listener.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Logging.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/StreamString.h" + +#include <algorithm> +#include <memory> +#include <type_traits> + +#include <assert.h> +#include <stddef.h> + +using namespace lldb; +using namespace lldb_private; + +Broadcaster::Broadcaster(BroadcasterManagerSP manager_sp, const char *name) + : m_broadcaster_sp(std::make_shared<BroadcasterImpl>(*this)), + m_manager_sp(manager_sp), m_broadcaster_name(name) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + if (log) + log->Printf("%p Broadcaster::Broadcaster(\"%s\")", + static_cast<void *>(this), GetBroadcasterName().AsCString()); +} + +Broadcaster::BroadcasterImpl::BroadcasterImpl(Broadcaster &broadcaster) + : m_broadcaster(broadcaster), m_listeners(), m_listeners_mutex(), + m_hijacking_listeners(), m_hijacking_masks() {} + +Broadcaster::~Broadcaster() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + if (log) + log->Printf("%p Broadcaster::~Broadcaster(\"%s\")", + static_cast<void *>(this), m_broadcaster_name.AsCString()); + + Clear(); +} + +void Broadcaster::CheckInWithManager() { + if (m_manager_sp) { + m_manager_sp->SignUpListenersForBroadcaster(*this); + } +} + +llvm::SmallVector<std::pair<ListenerSP, uint32_t &>, 4> +Broadcaster::BroadcasterImpl::GetListeners() { + llvm::SmallVector<std::pair<ListenerSP, uint32_t &>, 4> listeners; + listeners.reserve(m_listeners.size()); + + for (auto it = m_listeners.begin(); it != m_listeners.end();) { + lldb::ListenerSP curr_listener_sp(it->first.lock()); + if (curr_listener_sp && it->second) { + listeners.emplace_back(std::move(curr_listener_sp), it->second); + ++it; + } else + it = m_listeners.erase(it); + } + + return listeners; +} + +void Broadcaster::BroadcasterImpl::Clear() { + std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + + // Make sure the listener forgets about this broadcaster. We do this in the + // broadcaster in case the broadcaster object initiates the removal. + for (auto &pair : GetListeners()) + pair.first->BroadcasterWillDestruct(&m_broadcaster); + + m_listeners.clear(); +} + +Broadcaster *Broadcaster::BroadcasterImpl::GetBroadcaster() { + return &m_broadcaster; +} + +bool Broadcaster::BroadcasterImpl::GetEventNames( + Stream &s, uint32_t event_mask, bool prefix_with_broadcaster_name) const { + uint32_t num_names_added = 0; + if (event_mask && !m_event_names.empty()) { + event_names_map::const_iterator end = m_event_names.end(); + for (uint32_t bit = 1u, mask = event_mask; mask != 0 && bit != 0; + bit <<= 1, mask >>= 1) { + if (mask & 1) { + event_names_map::const_iterator pos = m_event_names.find(bit); + if (pos != end) { + if (num_names_added > 0) + s.PutCString(", "); + + if (prefix_with_broadcaster_name) { + s.PutCString(GetBroadcasterName()); + s.PutChar('.'); + } + s.PutCString(pos->second); + ++num_names_added; + } + } + } + } + return num_names_added > 0; +} + +void Broadcaster::AddInitialEventsToListener( + const lldb::ListenerSP &listener_sp, uint32_t requested_events) {} + +uint32_t +Broadcaster::BroadcasterImpl::AddListener(const lldb::ListenerSP &listener_sp, + uint32_t event_mask) { + if (!listener_sp) + return 0; + + std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + + // See if we already have this listener, and if so, update its mask + + bool handled = false; + + for (auto &pair : GetListeners()) { + if (pair.first == listener_sp) { + handled = true; + pair.second |= event_mask; + m_broadcaster.AddInitialEventsToListener(listener_sp, event_mask); + break; + } + } + + if (!handled) { + // Grant a new listener the available event bits + m_listeners.push_back( + std::make_pair(lldb::ListenerWP(listener_sp), event_mask)); + + // Individual broadcasters decide whether they have outstanding data when a + // listener attaches, and insert it into the listener with this method. + m_broadcaster.AddInitialEventsToListener(listener_sp, event_mask); + } + + // Return the event bits that were granted to the listener + return event_mask; +} + +bool Broadcaster::BroadcasterImpl::EventTypeHasListeners(uint32_t event_type) { + std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + + if (!m_hijacking_listeners.empty() && event_type & m_hijacking_masks.back()) + return true; + + for (auto &pair : GetListeners()) { + if (pair.second & event_type) + return true; + } + return false; +} + +bool Broadcaster::BroadcasterImpl::RemoveListener( + lldb_private::Listener *listener, uint32_t event_mask) { + if (!listener) + return false; + + std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + for (auto &pair : GetListeners()) { + if (pair.first.get() == listener) { + pair.second &= ~event_mask; + return true; + } + } + return false; +} + +bool Broadcaster::BroadcasterImpl::RemoveListener( + const lldb::ListenerSP &listener_sp, uint32_t event_mask) { + return RemoveListener(listener_sp.get(), event_mask); +} + +void Broadcaster::BroadcasterImpl::BroadcastEvent(EventSP &event_sp) { + return PrivateBroadcastEvent(event_sp, false); +} + +void Broadcaster::BroadcasterImpl::BroadcastEventIfUnique(EventSP &event_sp) { + return PrivateBroadcastEvent(event_sp, true); +} + +void Broadcaster::BroadcasterImpl::PrivateBroadcastEvent(EventSP &event_sp, + bool unique) { + // Can't add a nullptr event... + if (!event_sp) + return; + + // Update the broadcaster on this event + event_sp->SetBroadcaster(&m_broadcaster); + + const uint32_t event_type = event_sp->GetType(); + + std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + + ListenerSP hijacking_listener_sp; + + if (!m_hijacking_listeners.empty()) { + assert(!m_hijacking_masks.empty()); + hijacking_listener_sp = m_hijacking_listeners.back(); + if ((event_type & m_hijacking_masks.back()) == 0) + hijacking_listener_sp.reset(); + } + + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EVENTS)); + if (log) { + StreamString event_description; + event_sp->Dump(&event_description); + log->Printf("%p Broadcaster(\"%s\")::BroadcastEvent (event_sp = {%s}, " + "unique =%i) hijack = %p", + static_cast<void *>(this), GetBroadcasterName(), + event_description.GetData(), unique, + static_cast<void *>(hijacking_listener_sp.get())); + } + + if (hijacking_listener_sp) { + if (unique && + hijacking_listener_sp->PeekAtNextEventForBroadcasterWithType( + &m_broadcaster, event_type)) + return; + hijacking_listener_sp->AddEvent(event_sp); + } else { + for (auto &pair : GetListeners()) { + if (!(pair.second & event_type)) + continue; + if (unique && + pair.first->PeekAtNextEventForBroadcasterWithType(&m_broadcaster, + event_type)) + continue; + + pair.first->AddEvent(event_sp); + } + } +} + +void Broadcaster::BroadcasterImpl::BroadcastEvent(uint32_t event_type, + EventData *event_data) { + auto event_sp = std::make_shared<Event>(event_type, event_data); + PrivateBroadcastEvent(event_sp, false); +} + +void Broadcaster::BroadcasterImpl::BroadcastEvent( + uint32_t event_type, const lldb::EventDataSP &event_data_sp) { + auto event_sp = std::make_shared<Event>(event_type, event_data_sp); + PrivateBroadcastEvent(event_sp, false); +} + +void Broadcaster::BroadcasterImpl::BroadcastEventIfUnique( + uint32_t event_type, EventData *event_data) { + auto event_sp = std::make_shared<Event>(event_type, event_data); + PrivateBroadcastEvent(event_sp, true); +} + +bool Broadcaster::BroadcasterImpl::HijackBroadcaster( + const lldb::ListenerSP &listener_sp, uint32_t event_mask) { + std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EVENTS)); + if (log) + log->Printf( + "%p Broadcaster(\"%s\")::HijackBroadcaster (listener(\"%s\")=%p)", + static_cast<void *>(this), GetBroadcasterName(), + listener_sp->m_name.c_str(), static_cast<void *>(listener_sp.get())); + m_hijacking_listeners.push_back(listener_sp); + m_hijacking_masks.push_back(event_mask); + return true; +} + +bool Broadcaster::BroadcasterImpl::IsHijackedForEvent(uint32_t event_mask) { + std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + + if (!m_hijacking_listeners.empty()) + return (event_mask & m_hijacking_masks.back()) != 0; + return false; +} + +const char *Broadcaster::BroadcasterImpl::GetHijackingListenerName() { + if (m_hijacking_listeners.size()) { + return m_hijacking_listeners.back()->GetName(); + } else { + return nullptr; + } +} + +void Broadcaster::BroadcasterImpl::RestoreBroadcaster() { + std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex); + + if (!m_hijacking_listeners.empty()) { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EVENTS)); + if (log) { + ListenerSP listener_sp = m_hijacking_listeners.back(); + log->Printf("%p Broadcaster(\"%s\")::RestoreBroadcaster (about to pop " + "listener(\"%s\")=%p)", + static_cast<void *>(this), GetBroadcasterName(), + listener_sp->m_name.c_str(), + static_cast<void *>(listener_sp.get())); + } + m_hijacking_listeners.pop_back(); + } + if (!m_hijacking_masks.empty()) + m_hijacking_masks.pop_back(); +} + +ConstString &Broadcaster::GetBroadcasterClass() const { + static ConstString class_name("lldb.anonymous"); + return class_name; +} + +BroadcastEventSpec::BroadcastEventSpec(const BroadcastEventSpec &rhs) = default; + +bool BroadcastEventSpec::operator<(const BroadcastEventSpec &rhs) const { + if (GetBroadcasterClass() == rhs.GetBroadcasterClass()) { + return GetEventBits() < rhs.GetEventBits(); + } else { + return GetBroadcasterClass() < rhs.GetBroadcasterClass(); + } +} + +BroadcastEventSpec &BroadcastEventSpec:: +operator=(const BroadcastEventSpec &rhs) = default; + +BroadcasterManager::BroadcasterManager() : m_manager_mutex() {} + +lldb::BroadcasterManagerSP BroadcasterManager::MakeBroadcasterManager() { + return lldb::BroadcasterManagerSP(new BroadcasterManager()); +} + +uint32_t BroadcasterManager::RegisterListenerForEvents( + const lldb::ListenerSP &listener_sp, BroadcastEventSpec event_spec) { + std::lock_guard<std::recursive_mutex> guard(m_manager_mutex); + + collection::iterator iter = m_event_map.begin(), end_iter = m_event_map.end(); + uint32_t available_bits = event_spec.GetEventBits(); + + while (iter != end_iter && + (iter = find_if(iter, end_iter, + BroadcasterClassMatches( + event_spec.GetBroadcasterClass()))) != end_iter) { + available_bits &= ~((*iter).first.GetEventBits()); + iter++; + } + + if (available_bits != 0) { + m_event_map.insert(event_listener_key( + BroadcastEventSpec(event_spec.GetBroadcasterClass(), available_bits), + listener_sp)); + m_listeners.insert(listener_sp); + } + + return available_bits; +} + +bool BroadcasterManager::UnregisterListenerForEvents( + const lldb::ListenerSP &listener_sp, BroadcastEventSpec event_spec) { + std::lock_guard<std::recursive_mutex> guard(m_manager_mutex); + bool removed_some = false; + + if (m_listeners.erase(listener_sp) == 0) + return false; + + ListenerMatchesAndSharedBits predicate(event_spec, listener_sp); + std::vector<BroadcastEventSpec> to_be_readded; + uint32_t event_bits_to_remove = event_spec.GetEventBits(); + + // Go through the map and delete the exact matches, and build a list of + // matches that weren't exact to re-add: + while (true) { + collection::iterator iter, end_iter = m_event_map.end(); + iter = find_if(m_event_map.begin(), end_iter, predicate); + if (iter == end_iter) { + break; + } else { + uint32_t iter_event_bits = (*iter).first.GetEventBits(); + removed_some = true; + + if (event_bits_to_remove != iter_event_bits) { + uint32_t new_event_bits = iter_event_bits & ~event_bits_to_remove; + to_be_readded.push_back(BroadcastEventSpec( + event_spec.GetBroadcasterClass(), new_event_bits)); + } + m_event_map.erase(iter); + } + } + + // Okay now add back the bits that weren't completely removed: + for (size_t i = 0; i < to_be_readded.size(); i++) { + m_event_map.insert(event_listener_key(to_be_readded[i], listener_sp)); + } + + return removed_some; +} + +ListenerSP BroadcasterManager::GetListenerForEventSpec( + BroadcastEventSpec event_spec) const { + std::lock_guard<std::recursive_mutex> guard(m_manager_mutex); + + collection::const_iterator iter, end_iter = m_event_map.end(); + iter = find_if(m_event_map.begin(), end_iter, + BroadcastEventSpecMatches(event_spec)); + if (iter != end_iter) + return (*iter).second; + else + return nullptr; +} + +void BroadcasterManager::RemoveListener(Listener *listener) { + std::lock_guard<std::recursive_mutex> guard(m_manager_mutex); + ListenerMatchesPointer predicate(listener); + listener_collection::iterator iter = m_listeners.begin(), + end_iter = m_listeners.end(); + + std::find_if(iter, end_iter, predicate); + if (iter != end_iter) + m_listeners.erase(iter); + + while (true) { + collection::iterator iter, end_iter = m_event_map.end(); + iter = find_if(m_event_map.begin(), end_iter, predicate); + if (iter == end_iter) + break; + else + m_event_map.erase(iter); + } +} + +void BroadcasterManager::RemoveListener(const lldb::ListenerSP &listener_sp) { + std::lock_guard<std::recursive_mutex> guard(m_manager_mutex); + ListenerMatches predicate(listener_sp); + + if (m_listeners.erase(listener_sp) == 0) + return; + + while (true) { + collection::iterator iter, end_iter = m_event_map.end(); + iter = find_if(m_event_map.begin(), end_iter, predicate); + if (iter == end_iter) + break; + else + m_event_map.erase(iter); + } +} + +void BroadcasterManager::SignUpListenersForBroadcaster( + Broadcaster &broadcaster) { + std::lock_guard<std::recursive_mutex> guard(m_manager_mutex); + + collection::iterator iter = m_event_map.begin(), end_iter = m_event_map.end(); + + while (iter != end_iter && + (iter = find_if(iter, end_iter, + BroadcasterClassMatches( + broadcaster.GetBroadcasterClass()))) != end_iter) { + (*iter).second->StartListeningForEvents(&broadcaster, + (*iter).first.GetEventBits()); + iter++; + } +} + +void BroadcasterManager::Clear() { + std::lock_guard<std::recursive_mutex> guard(m_manager_mutex); + listener_collection::iterator end_iter = m_listeners.end(); + + for (listener_collection::iterator iter = m_listeners.begin(); + iter != end_iter; iter++) + (*iter)->BroadcasterManagerWillDestruct(this->shared_from_this()); + m_listeners.clear(); + m_event_map.clear(); +} |
