551 lines · cpp
1//===-- Broadcaster.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-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Utility/Broadcaster.h"10#include "lldb/Utility/Event.h"11#include "lldb/Utility/LLDBLog.h"12#include "lldb/Utility/Listener.h"13#include "lldb/Utility/Stream.h"14#include "lldb/Utility/StreamString.h"15 16#include <algorithm>17#include <memory>18#include <utility>19 20#include <cassert>21#include <cstddef>22 23using namespace lldb;24using namespace lldb_private;25 26Broadcaster::Broadcaster(BroadcasterManagerSP manager_sp, std::string name)27 : m_broadcaster_sp(std::make_shared<BroadcasterImpl>(*this)),28 m_manager_sp(std::move(manager_sp)), m_broadcaster_name(std::move(name)) {29 Log *log = GetLog(LLDBLog::Object);30 LLDB_LOG(log, "{0} Broadcaster::Broadcaster(\"{1}\")",31 static_cast<void *>(this), GetBroadcasterName());32}33 34Broadcaster::BroadcasterImpl::BroadcasterImpl(Broadcaster &broadcaster)35 : m_broadcaster(broadcaster), m_listeners(), m_listeners_mutex(),36 m_hijacking_listeners(), m_hijacking_masks() {}37 38Broadcaster::~Broadcaster() {39 Log *log = GetLog(LLDBLog::Object);40 LLDB_LOG(log, "{0} Broadcaster::~Broadcaster(\"{1}\")",41 static_cast<void *>(this), GetBroadcasterName());42 43 Clear();44}45 46void Broadcaster::CheckInWithManager() {47 if (m_manager_sp) {48 m_manager_sp->SignUpListenersForBroadcaster(*this);49 }50}51 52llvm::SmallVector<std::pair<ListenerSP, uint32_t &>, 4>53Broadcaster::BroadcasterImpl::GetListeners(uint32_t event_mask,54 bool include_primary) {55 llvm::SmallVector<std::pair<ListenerSP, uint32_t &>, 4> listeners;56 size_t max_count = m_listeners.size();57 if (include_primary)58 max_count++;59 listeners.reserve(max_count);60 61 for (auto it = m_listeners.begin(); it != m_listeners.end();) {62 lldb::ListenerSP curr_listener_sp(it->first.lock());63 if (curr_listener_sp) {64 if (it->second & event_mask)65 listeners.emplace_back(std::move(curr_listener_sp), it->second);66 ++it;67 } else68 // If our listener_wp didn't resolve, then we should remove this entry.69 it = m_listeners.erase(it);70 }71 if (include_primary && m_primary_listener_sp)72 listeners.emplace_back(m_primary_listener_sp, m_primary_listener_mask);73 74 return listeners;75}76 77bool Broadcaster::BroadcasterImpl::HasListeners(uint32_t event_mask) {78 if (m_primary_listener_sp)79 return true;80 for (auto it = m_listeners.begin(); it != m_listeners.end(); it++) {81 // Don't return a listener if the other end of the WP is gone:82 lldb::ListenerSP curr_listener_sp(it->first.lock());83 if (curr_listener_sp && (it->second & event_mask))84 return true;85 }86 return false;87}88 89void Broadcaster::BroadcasterImpl::Clear() {90 std::lock_guard<std::mutex> guard(m_listeners_mutex);91 92 // Make sure the listener forgets about this broadcaster. We do this in the93 // broadcaster in case the broadcaster object initiates the removal.94 for (auto &pair : GetListeners())95 pair.first->BroadcasterWillDestruct(&m_broadcaster);96 97 m_listeners.clear();98 m_primary_listener_sp.reset();99}100 101Broadcaster *Broadcaster::BroadcasterImpl::GetBroadcaster() {102 return &m_broadcaster;103}104 105bool Broadcaster::BroadcasterImpl::GetEventNames(106 Stream &s, uint32_t event_mask, bool prefix_with_broadcaster_name) const {107 uint32_t num_names_added = 0;108 if (event_mask && !m_event_names.empty()) {109 event_names_map::const_iterator end = m_event_names.end();110 for (uint32_t bit = 1u, mask = event_mask; mask != 0 && bit != 0;111 bit <<= 1, mask >>= 1) {112 if (mask & 1) {113 event_names_map::const_iterator pos = m_event_names.find(bit);114 if (pos != end) {115 if (num_names_added > 0)116 s.PutCString(", ");117 118 if (prefix_with_broadcaster_name) {119 s.PutCString(GetBroadcasterName());120 s.PutChar('.');121 }122 s.PutCString(pos->second);123 ++num_names_added;124 }125 }126 }127 }128 return num_names_added > 0;129}130 131void Broadcaster::AddInitialEventsToListener(132 const lldb::ListenerSP &listener_sp, uint32_t requested_events) {}133 134uint32_t135Broadcaster::BroadcasterImpl::AddListener(const lldb::ListenerSP &listener_sp,136 uint32_t event_mask) {137 if (!listener_sp)138 return 0;139 140 std::lock_guard<std::mutex> guard(m_listeners_mutex);141 142 // See if we already have this listener, and if so, update its mask143 144 bool handled = false;145 146 if (listener_sp == m_primary_listener_sp)147 // This already handles all bits so just return the mask:148 return event_mask;149 150 for (auto &pair : GetListeners(UINT32_MAX, false)) {151 if (pair.first == listener_sp) {152 handled = true;153 pair.second |= event_mask;154 m_broadcaster.AddInitialEventsToListener(listener_sp, event_mask);155 break;156 }157 }158 159 if (!handled) {160 // Grant a new listener the available event bits161 m_listeners.push_back(162 std::make_pair(lldb::ListenerWP(listener_sp), event_mask));163 164 // Individual broadcasters decide whether they have outstanding data when a165 // listener attaches, and insert it into the listener with this method.166 m_broadcaster.AddInitialEventsToListener(listener_sp, event_mask);167 }168 169 // Return the event bits that were granted to the listener170 return event_mask;171}172 173bool Broadcaster::BroadcasterImpl::EventTypeHasListeners(uint32_t event_type) {174 std::lock_guard<std::mutex> guard(m_listeners_mutex);175 176 if (!m_hijacking_listeners.empty() && event_type & m_hijacking_masks.back())177 return true;178 179 // The primary listener listens for all event bits:180 if (m_primary_listener_sp)181 return true;182 183 return HasListeners(event_type);184}185 186bool Broadcaster::BroadcasterImpl::RemoveListener(187 lldb_private::Listener *listener, uint32_t event_mask) {188 if (!listener)189 return false;190 191 if (listener == m_primary_listener_sp.get()) {192 // Primary listeners listen for all the event bits for their broadcaster,193 // so remove this altogether if asked:194 m_primary_listener_sp.reset();195 return true;196 }197 198 std::lock_guard<std::mutex> guard(m_listeners_mutex);199 for (auto it = m_listeners.begin(); it != m_listeners.end();) {200 lldb::ListenerSP curr_listener_sp(it->first.lock());201 202 if (!curr_listener_sp) {203 // The weak pointer for this listener didn't resolve, lets' prune it204 // as we go.205 it = m_listeners.erase(it);206 continue;207 }208 209 if (curr_listener_sp.get() == listener) {210 it->second &= ~event_mask;211 // If we removed all the event bits from a listener, remove it from212 // the list as well.213 if (!it->second)214 m_listeners.erase(it);215 return true;216 }217 it++;218 }219 return false;220}221 222bool Broadcaster::BroadcasterImpl::RemoveListener(223 const lldb::ListenerSP &listener_sp, uint32_t event_mask) {224 return RemoveListener(listener_sp.get(), event_mask);225}226 227void Broadcaster::BroadcasterImpl::BroadcastEvent(EventSP &event_sp) {228 return PrivateBroadcastEvent(event_sp, false);229}230 231void Broadcaster::BroadcasterImpl::BroadcastEventIfUnique(EventSP &event_sp) {232 return PrivateBroadcastEvent(event_sp, true);233}234 235void Broadcaster::BroadcasterImpl::PrivateBroadcastEvent(EventSP &event_sp,236 bool unique) {237 // Can't add a nullptr event...238 if (!event_sp)239 return;240 241 // Update the broadcaster on this event242 event_sp->SetBroadcaster(&m_broadcaster);243 244 const uint32_t event_type = event_sp->GetType();245 246 std::lock_guard<std::mutex> guard(m_listeners_mutex);247 248 ListenerSP hijacking_listener_sp;249 250 if (!m_hijacking_listeners.empty()) {251 assert(!m_hijacking_masks.empty());252 hijacking_listener_sp = m_hijacking_listeners.back();253 if ((event_type & m_hijacking_masks.back()) == 0)254 hijacking_listener_sp.reset();255 }256 257 Log *log = GetLog(LLDBLog::Events);258 if (!log && event_sp->GetData())259 log = event_sp->GetData()->GetLogChannel();260 261 if (log) {262 StreamString event_description;263 event_sp->Dump(&event_description);264 LLDB_LOG(log,265 "{0:x} Broadcaster(\"{1}\")::BroadcastEvent (event_sp = {2}, "266 "unique={3}) hijack = {4:x}",267 static_cast<void *>(this), GetBroadcasterName(),268 event_description.GetData(), unique,269 static_cast<void *>(hijacking_listener_sp.get()));270 }271 ListenerSP primary_listener_sp272 = hijacking_listener_sp ? hijacking_listener_sp : m_primary_listener_sp;273 274 if (primary_listener_sp) {275 if (unique && primary_listener_sp->PeekAtNextEventForBroadcasterWithType(276 &m_broadcaster, event_type))277 return;278 // Add the pending listeners but not if the event is hijacked, since that279 // is given sole access to the event stream it is hijacking.280 // Make sure to do this before adding the event to the primary or it might281 // start handling the event before we're done adding all the pending282 // listeners.283 // Also, don't redo the check for unique here, since otherwise that could284 // be racy, and if we send the event to the primary listener then we SHOULD 285 // send it to the secondary listeners or they will get out of sync with the286 // primary listener.287 if (!hijacking_listener_sp) {288 for (auto &pair : GetListeners(event_type, false))289 event_sp->AddPendingListener(pair.first);290 }291 primary_listener_sp->AddEvent(event_sp);292 } else {293 for (auto &pair : GetListeners(event_type)) {294 if (unique && pair.first->PeekAtNextEventForBroadcasterWithType(295 &m_broadcaster, event_type))296 continue;297 298 pair.first->AddEvent(event_sp);299 }300 }301}302 303void Broadcaster::BroadcasterImpl::BroadcastEvent(uint32_t event_type) {304 auto event_sp = std::make_shared<Event>(event_type, /*data = */ nullptr);305 PrivateBroadcastEvent(event_sp, false);306}307 308void Broadcaster::BroadcasterImpl::BroadcastEvent(309 uint32_t event_type, const lldb::EventDataSP &event_data_sp) {310 auto event_sp = std::make_shared<Event>(event_type, event_data_sp);311 PrivateBroadcastEvent(event_sp, false);312}313 314void Broadcaster::BroadcasterImpl::BroadcastEventIfUnique(uint32_t event_type) {315 auto event_sp = std::make_shared<Event>(event_type, /*data = */ nullptr);316 PrivateBroadcastEvent(event_sp, true);317}318 319void Broadcaster::BroadcasterImpl::SetPrimaryListener(lldb::ListenerSP320 listener_sp) {321 // This might have already been added as a normal listener, make sure we322 // don't hold two copies.323 RemoveListener(listener_sp.get(), UINT32_MAX);324 m_primary_listener_sp = listener_sp;325 326}327 328bool Broadcaster::BroadcasterImpl::HijackBroadcaster(329 const lldb::ListenerSP &listener_sp, uint32_t event_mask) {330 std::lock_guard<std::mutex> guard(m_listeners_mutex);331 332 Log *log = GetLog(LLDBLog::Events);333 LLDB_LOG(334 log,335 "{0} Broadcaster(\"{1}\")::HijackBroadcaster (listener(\"{2}\")={3})",336 static_cast<void *>(this), GetBroadcasterName(),337 listener_sp->m_name.c_str(), static_cast<void *>(listener_sp.get()));338 m_hijacking_listeners.push_back(listener_sp);339 m_hijacking_masks.push_back(event_mask);340 return true;341}342 343bool Broadcaster::BroadcasterImpl::IsHijackedForEvent(uint32_t event_mask) {344 std::lock_guard<std::mutex> guard(m_listeners_mutex);345 346 if (!m_hijacking_listeners.empty())347 return (event_mask & m_hijacking_masks.back()) != 0;348 return false;349}350 351const char *Broadcaster::BroadcasterImpl::GetHijackingListenerName() {352 if (m_hijacking_listeners.size()) {353 return m_hijacking_listeners.back()->GetName();354 }355 return nullptr;356}357 358void Broadcaster::BroadcasterImpl::RestoreBroadcaster() {359 std::lock_guard<std::mutex> guard(m_listeners_mutex);360 361 if (!m_hijacking_listeners.empty()) {362 ListenerSP listener_sp = m_hijacking_listeners.back();363 Log *log = GetLog(LLDBLog::Events);364 LLDB_LOG(log,365 "{0} Broadcaster(\"{1}\")::RestoreBroadcaster (about to pop "366 "listener(\"{2}\")={3})",367 static_cast<void *>(this), GetBroadcasterName(),368 listener_sp->m_name.c_str(),369 static_cast<void *>(listener_sp.get()));370 m_hijacking_listeners.pop_back();371 }372 if (!m_hijacking_masks.empty())373 m_hijacking_masks.pop_back();374}375 376llvm::StringRef Broadcaster::GetBroadcasterClass() const {377 static constexpr llvm::StringLiteral class_name("lldb.anonymous");378 return class_name;379}380 381bool BroadcastEventSpec::operator<(const BroadcastEventSpec &rhs) const {382 if (GetBroadcasterClass() == rhs.GetBroadcasterClass()) {383 return GetEventBits() < rhs.GetEventBits();384 }385 return GetBroadcasterClass() < rhs.GetBroadcasterClass();386}387 388BroadcasterManager::BroadcasterManager() : m_manager_mutex() {}389 390lldb::BroadcasterManagerSP BroadcasterManager::MakeBroadcasterManager() {391 return lldb::BroadcasterManagerSP(new BroadcasterManager());392}393 394uint32_t BroadcasterManager::RegisterListenerForEventsNoLock(395 const lldb::ListenerSP &listener_sp, const BroadcastEventSpec &event_spec) {396 collection::iterator iter = m_event_map.begin(), end_iter = m_event_map.end();397 uint32_t available_bits = event_spec.GetEventBits();398 399 auto class_matches = [&event_spec](const event_listener_key &input) -> bool {400 return input.first.GetBroadcasterClass() ==401 event_spec.GetBroadcasterClass();402 };403 404 while (iter != end_iter &&405 (iter = find_if(iter, end_iter, class_matches)) != end_iter) {406 available_bits &= ~((*iter).first.GetEventBits());407 iter++;408 }409 410 if (available_bits != 0) {411 m_event_map.insert(event_listener_key(412 BroadcastEventSpec(event_spec.GetBroadcasterClass(), available_bits),413 listener_sp));414 m_listeners.insert(listener_sp);415 }416 417 return available_bits;418}419 420bool BroadcasterManager::UnregisterListenerForEventsNoLock(421 const lldb::ListenerSP &listener_sp, const BroadcastEventSpec &event_spec) {422 bool removed_some = false;423 424 if (m_listeners.erase(listener_sp) == 0)425 return false;426 427 auto listener_matches_and_shared_bits =428 [&listener_sp, &event_spec](const event_listener_key &input) -> bool {429 return input.first.GetBroadcasterClass() ==430 event_spec.GetBroadcasterClass() &&431 (input.first.GetEventBits() & event_spec.GetEventBits()) != 0 &&432 input.second == listener_sp;433 };434 std::vector<BroadcastEventSpec> to_be_readded;435 uint32_t event_bits_to_remove = event_spec.GetEventBits();436 437 // Go through the map and delete the exact matches, and build a list of438 // matches that weren't exact to re-add:439 for (auto iter = m_event_map.begin(), end = m_event_map.end();;) {440 iter = find_if(iter, end, listener_matches_and_shared_bits);441 if (iter == end)442 break;443 uint32_t iter_event_bits = (*iter).first.GetEventBits();444 removed_some = true;445 446 if (event_bits_to_remove != iter_event_bits) {447 uint32_t new_event_bits = iter_event_bits & ~event_bits_to_remove;448 to_be_readded.emplace_back(event_spec.GetBroadcasterClass(),449 new_event_bits);450 }451 iter = m_event_map.erase(iter);452 }453 454 // Okay now add back the bits that weren't completely removed:455 for (const auto &event : to_be_readded) {456 m_event_map.insert(event_listener_key(event, listener_sp));457 }458 459 return removed_some;460}461 462ListenerSP BroadcasterManager::GetListenerForEventSpec(463 const BroadcastEventSpec &event_spec) const {464 std::lock_guard<std::mutex> guard(m_manager_mutex);465 466 auto event_spec_matches =467 [&event_spec](const event_listener_key &input) -> bool {468 return input.first.IsContainedIn(event_spec);469 };470 471 auto iter = llvm::find_if(m_event_map, event_spec_matches);472 if (iter != m_event_map.end())473 return (*iter).second;474 475 return nullptr;476}477 478void BroadcasterManager::RemoveListener(Listener *listener) {479 std::lock_guard<std::mutex> guard(m_manager_mutex);480 auto listeners_predicate =481 [&listener](const lldb::ListenerSP &input) -> bool {482 return input.get() == listener;483 };484 485 if (auto iter = llvm::find_if(m_listeners, listeners_predicate);486 iter != m_listeners.end())487 m_listeners.erase(iter);488 489 auto events_predicate = [listener](const event_listener_key &input) -> bool {490 return input.second.get() == listener;491 };492 493 // TODO: use 'std::map::erase_if' when moving to c++20.494 for (auto iter = m_event_map.begin(), end = m_event_map.end();;) {495 iter = find_if(iter, end, events_predicate);496 if (iter == end)497 break;498 499 iter = m_event_map.erase(iter);500 }501}502 503void BroadcasterManager::RemoveListener(const lldb::ListenerSP &listener_sp) {504 std::lock_guard<std::mutex> guard(m_manager_mutex);505 506 auto listener_matches =507 [&listener_sp](const event_listener_key &input) -> bool {508 return input.second == listener_sp;509 };510 511 if (m_listeners.erase(listener_sp) == 0)512 return;513 514 // TODO: use 'std::map::erase_if' when moving to c++20.515 for (auto iter = m_event_map.begin(), end_iter = m_event_map.end();;) {516 iter = find_if(iter, end_iter, listener_matches);517 if (iter == end_iter)518 break;519 520 iter = m_event_map.erase(iter);521 }522}523 524void BroadcasterManager::SignUpListenersForBroadcaster(525 Broadcaster &broadcaster) {526 std::lock_guard<std::mutex> guard(m_manager_mutex);527 528 collection::iterator iter = m_event_map.begin(), end_iter = m_event_map.end();529 530 auto class_matches = [&broadcaster](const event_listener_key &input) -> bool {531 return input.first.GetBroadcasterClass() ==532 broadcaster.GetBroadcasterClass();533 };534 535 while (iter != end_iter &&536 (iter = find_if(iter, end_iter, class_matches)) != end_iter) {537 (*iter).second->StartListeningForEvents(&broadcaster,538 (*iter).first.GetEventBits());539 iter++;540 }541}542 543void BroadcasterManager::Clear() {544 std::lock_guard<std::mutex> guard(m_manager_mutex);545 546 for (auto &listener : m_listeners)547 listener->BroadcasterManagerWillDestruct(this->shared_from_this());548 m_listeners.clear();549 m_event_map.clear();550}551