brintos

brintos / llvm-project-archived public Read only

0
0
Text · 17.9 KiB · c6b2606 Raw
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