blob: ead597d626d74396fc1f54f106d0d3518c8c684c [file] [log] [blame]
//===-- Broadcaster.h -------------------------------------------*- 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
//
//===----------------------------------------------------------------------===//
#ifndef LLDB_UTILITY_BROADCASTER_H
#define LLDB_UTILITY_BROADCASTER_H
#include "lldb/Utility/ConstString.h"
#include "lldb/lldb-defines.h"
#include "lldb/lldb-forward.h"
#include "llvm/ADT/SmallVector.h"
#include <cstdint>
#include <map>
#include <memory>
#include <mutex>
#include <set>
#include <string>
#include <utility>
#include <vector>
namespace lldb_private {
class Broadcaster;
class EventData;
class Listener;
class Stream;
} // namespace lldb_private
namespace lldb_private {
/// lldb::BroadcastEventSpec
///
/// This class is used to specify a kind of event to register for. The
/// Debugger maintains a list of BroadcastEventSpec's and when it is made
class BroadcastEventSpec {
public:
BroadcastEventSpec(ConstString broadcaster_class, uint32_t event_bits)
: m_broadcaster_class(broadcaster_class), m_event_bits(event_bits) {}
~BroadcastEventSpec() = default;
ConstString GetBroadcasterClass() const { return m_broadcaster_class; }
uint32_t GetEventBits() const { return m_event_bits; }
/// Tell whether this BroadcastEventSpec is contained in in_spec. That is:
/// (a) the two spec's share the same broadcaster class (b) the event bits of
/// this spec are wholly contained in those of in_spec.
bool IsContainedIn(const BroadcastEventSpec &in_spec) const {
if (m_broadcaster_class != in_spec.GetBroadcasterClass())
return false;
uint32_t in_bits = in_spec.GetEventBits();
if (in_bits == m_event_bits)
return true;
if ((m_event_bits & in_bits) != 0 && (m_event_bits & ~in_bits) == 0)
return true;
return false;
}
bool operator<(const BroadcastEventSpec &rhs) const;
private:
ConstString m_broadcaster_class;
uint32_t m_event_bits;
};
class BroadcasterManager
: public std::enable_shared_from_this<BroadcasterManager> {
public:
friend class Listener;
protected:
BroadcasterManager();
public:
/// Listeners hold onto weak pointers to their broadcaster managers. So they
/// must be made into shared pointers, which you do with
/// MakeBroadcasterManager.
static lldb::BroadcasterManagerSP MakeBroadcasterManager();
~BroadcasterManager() = default;
uint32_t RegisterListenerForEvents(const lldb::ListenerSP &listener_sp,
const BroadcastEventSpec &event_spec);
bool UnregisterListenerForEvents(const lldb::ListenerSP &listener_sp,
const BroadcastEventSpec &event_spec);
lldb::ListenerSP
GetListenerForEventSpec(const BroadcastEventSpec &event_spec) const;
void SignUpListenersForBroadcaster(Broadcaster &broadcaster);
void RemoveListener(const lldb::ListenerSP &listener_sp);
void RemoveListener(Listener *listener);
void Clear();
private:
typedef std::pair<BroadcastEventSpec, lldb::ListenerSP> event_listener_key;
typedef std::map<BroadcastEventSpec, lldb::ListenerSP> collection;
typedef std::set<lldb::ListenerSP> listener_collection;
collection m_event_map;
listener_collection m_listeners;
mutable std::recursive_mutex m_manager_mutex;
// A couple of comparator classes for find_if:
class BroadcasterClassMatches {
public:
BroadcasterClassMatches(ConstString broadcaster_class)
: m_broadcaster_class(broadcaster_class) {}
~BroadcasterClassMatches() = default;
bool operator()(const event_listener_key &input) const {
return (input.first.GetBroadcasterClass() == m_broadcaster_class);
}
private:
ConstString m_broadcaster_class;
};
class BroadcastEventSpecMatches {
public:
BroadcastEventSpecMatches(const BroadcastEventSpec &broadcaster_spec)
: m_broadcaster_spec(broadcaster_spec) {}
~BroadcastEventSpecMatches() = default;
bool operator()(const event_listener_key &input) const {
return (input.first.IsContainedIn(m_broadcaster_spec));
}
private:
BroadcastEventSpec m_broadcaster_spec;
};
class ListenerMatchesAndSharedBits {
public:
explicit ListenerMatchesAndSharedBits(
const BroadcastEventSpec &broadcaster_spec,
const lldb::ListenerSP &listener_sp)
: m_broadcaster_spec(broadcaster_spec), m_listener_sp(listener_sp) {}
~ListenerMatchesAndSharedBits() = default;
bool operator()(const event_listener_key &input) const {
return (input.first.GetBroadcasterClass() ==
m_broadcaster_spec.GetBroadcasterClass() &&
(input.first.GetEventBits() &
m_broadcaster_spec.GetEventBits()) != 0 &&
input.second == m_listener_sp);
}
private:
BroadcastEventSpec m_broadcaster_spec;
const lldb::ListenerSP m_listener_sp;
};
class ListenerMatches {
public:
explicit ListenerMatches(const lldb::ListenerSP &in_listener_sp)
: m_listener_sp(in_listener_sp) {}
~ListenerMatches() = default;
bool operator()(const event_listener_key &input) const {
if (input.second == m_listener_sp)
return true;
return false;
}
private:
const lldb::ListenerSP m_listener_sp;
};
class ListenerMatchesPointer {
public:
ListenerMatchesPointer(const Listener *in_listener)
: m_listener(in_listener) {}
~ListenerMatchesPointer() = default;
bool operator()(const event_listener_key &input) const {
if (input.second.get() == m_listener)
return true;
return false;
}
bool operator()(const lldb::ListenerSP &input) const {
if (input.get() == m_listener)
return true;
return false;
}
private:
const Listener *m_listener;
};
};
/// \class Broadcaster Broadcaster.h "lldb/Utility/Broadcaster.h" An event
/// broadcasting class.
///
/// The Broadcaster class is designed to be subclassed by objects that wish to
/// vend events in a multi-threaded environment. Broadcaster objects can each
/// vend 32 events. Each event is represented by a bit in a 32 bit value and
/// these bits can be set:
/// \see Broadcaster::SetEventBits(uint32_t)
/// or cleared:
/// \see Broadcaster::ResetEventBits(uint32_t)
/// When an event gets set the Broadcaster object will notify the Listener
/// object that is listening for the event (if there is one).
///
/// Subclasses should provide broadcast bit definitions for any events they
/// vend, typically using an enumeration:
/// \code
/// class Foo : public Broadcaster
/// {
/// public:
/// // Broadcaster event bits definitions.
/// enum
/// {
/// eBroadcastBitOne = (1 << 0),
/// eBroadcastBitTwo = (1 << 1),
/// eBroadcastBitThree = (1 << 2),
/// ...
/// };
/// \endcode
class Broadcaster {
friend class Listener;
friend class Event;
public:
/// Construct with a broadcaster with a name.
///
/// \param[in] name
/// A NULL terminated C string that contains the name of the
/// broadcaster object.
Broadcaster(lldb::BroadcasterManagerSP manager_sp, const char *name);
/// Destructor.
///
/// The destructor is virtual since this class gets subclassed.
virtual ~Broadcaster();
void CheckInWithManager();
/// Broadcast an event which has no associated data.
///
/// \param[in] event_type
/// The element from the enum defining this broadcaster's events
/// that is being broadcast.
///
/// \param[in] event_data
/// User event data that will be owned by the lldb::Event that
/// is created internally.
///
/// \param[in] unique
/// If true, then only add an event of this type if there isn't
/// one already in the queue.
///
void BroadcastEvent(lldb::EventSP &event_sp) {
m_broadcaster_sp->BroadcastEvent(event_sp);
}
void BroadcastEventIfUnique(lldb::EventSP &event_sp) {
m_broadcaster_sp->BroadcastEventIfUnique(event_sp);
}
void BroadcastEvent(uint32_t event_type,
const lldb::EventDataSP &event_data_sp) {
m_broadcaster_sp->BroadcastEvent(event_type, event_data_sp);
}
void BroadcastEvent(uint32_t event_type, EventData *event_data = nullptr) {
m_broadcaster_sp->BroadcastEvent(event_type, event_data);
}
void BroadcastEventIfUnique(uint32_t event_type,
EventData *event_data = nullptr) {
m_broadcaster_sp->BroadcastEventIfUnique(event_type, event_data);
}
void Clear() { m_broadcaster_sp->Clear(); }
virtual void AddInitialEventsToListener(const lldb::ListenerSP &listener_sp,
uint32_t requested_events);
/// Listen for any events specified by \a event_mask.
///
/// Only one listener can listen to each event bit in a given Broadcaster.
/// Once a listener has acquired an event bit, no other broadcaster will
/// have access to it until it is relinquished by the first listener that
/// gets it. The actual event bits that get acquired by \a listener may be
/// different from what is requested in \a event_mask, and to track this the
/// actual event bits that are acquired get returned.
///
/// \param[in] listener
/// The Listener object that wants to monitor the events that
/// get broadcast by this object.
///
/// \param[in] event_mask
/// A bit mask that indicates which events the listener is
/// asking to monitor.
///
/// \return
/// The actual event bits that were acquired by \a listener.
uint32_t AddListener(const lldb::ListenerSP &listener_sp,
uint32_t event_mask) {
return m_broadcaster_sp->AddListener(listener_sp, event_mask);
}
/// Get the NULL terminated C string name of this Broadcaster object.
///
/// \return
/// The NULL terminated C string name of this Broadcaster.
ConstString GetBroadcasterName() { return m_broadcaster_name; }
/// Get the event name(s) for one or more event bits.
///
/// \param[in] event_mask
/// A bit mask that indicates which events to get names for.
///
/// \return
/// The NULL terminated C string name of this Broadcaster.
bool GetEventNames(Stream &s, const uint32_t event_mask,
bool prefix_with_broadcaster_name) const {
return m_broadcaster_sp->GetEventNames(s, event_mask,
prefix_with_broadcaster_name);
}
/// Set the name for an event bit.
///
/// \param[in] event_mask
/// A bit mask that indicates which events the listener is
/// asking to monitor.
///
/// \return
/// The NULL terminated C string name of this Broadcaster.
void SetEventName(uint32_t event_mask, const char *name) {
m_broadcaster_sp->SetEventName(event_mask, name);
}
const char *GetEventName(uint32_t event_mask) const {
return m_broadcaster_sp->GetEventName(event_mask);
}
bool EventTypeHasListeners(uint32_t event_type) {
return m_broadcaster_sp->EventTypeHasListeners(event_type);
}
/// Removes a Listener from this broadcasters list and frees the event bits
/// specified by \a event_mask that were previously acquired by \a listener
/// (assuming \a listener was listening to this object) for other listener
/// objects to use.
///
/// \param[in] listener
/// A Listener object that previously called AddListener.
///
/// \param[in] event_mask
/// The event bits \a listener wishes to relinquish.
///
/// \return
/// \b True if the listener was listening to this broadcaster
/// and was removed, \b false otherwise.
///
/// \see uint32_t Broadcaster::AddListener (Listener*, uint32_t)
bool RemoveListener(const lldb::ListenerSP &listener_sp,
uint32_t event_mask = UINT32_MAX) {
return m_broadcaster_sp->RemoveListener(listener_sp, event_mask);
}
/// Provides a simple mechanism to temporarily redirect events from
/// broadcaster. When you call this function passing in a listener and
/// event type mask, all events from the broadcaster matching the mask will
/// now go to the hijacking listener. Only one hijack can occur at a time.
/// If we need more than this we will have to implement a Listener stack.
///
/// \param[in] listener
/// A Listener object. You do not need to call StartListeningForEvents
/// for this broadcaster (that would fail anyway since the event bits
/// would most likely be taken by the listener(s) you are usurping.
///
/// \param[in] event_mask
/// The event bits \a listener wishes to hijack.
///
/// \return
/// \b True if the event mask could be hijacked, \b false otherwise.
///
/// \see uint32_t Broadcaster::AddListener (Listener*, uint32_t)
bool HijackBroadcaster(const lldb::ListenerSP &listener_sp,
uint32_t event_mask = UINT32_MAX) {
return m_broadcaster_sp->HijackBroadcaster(listener_sp, event_mask);
}
bool IsHijackedForEvent(uint32_t event_mask) {
return m_broadcaster_sp->IsHijackedForEvent(event_mask);
}
/// Restore the state of the Broadcaster from a previous hijack attempt.
void RestoreBroadcaster() { m_broadcaster_sp->RestoreBroadcaster(); }
/// This needs to be filled in if you are going to register the broadcaster
/// with the broadcaster manager and do broadcaster class matching.
/// FIXME: Probably should make a ManagedBroadcaster subclass with all the
/// bits needed to work with the BroadcasterManager, so that it is clearer
/// how to add one.
virtual ConstString &GetBroadcasterClass() const;
lldb::BroadcasterManagerSP GetManager();
protected:
/// BroadcasterImpl contains the actual Broadcaster implementation. The
/// Broadcaster makes a BroadcasterImpl which lives as long as it does. The
/// Listeners & the Events hold a weak pointer to the BroadcasterImpl, so
/// that they can survive if a Broadcaster they were listening to is
/// destroyed w/o their being able to unregister from it (which can happen if
/// the Broadcasters & Listeners are being destroyed on separate threads
/// simultaneously. The Broadcaster itself can't be shared out as a weak
/// pointer, because some things that are broadcasters (e.g. the Target and
/// the Process) are shared in their own right.
///
/// For the most part, the Broadcaster functions dispatch to the
/// BroadcasterImpl, and are documented in the public Broadcaster API above.
class BroadcasterImpl {
friend class Listener;
friend class Broadcaster;
public:
BroadcasterImpl(Broadcaster &broadcaster);
~BroadcasterImpl() = default;
void BroadcastEvent(lldb::EventSP &event_sp);
void BroadcastEventIfUnique(lldb::EventSP &event_sp);
void BroadcastEvent(uint32_t event_type, EventData *event_data = nullptr);
void BroadcastEvent(uint32_t event_type,
const lldb::EventDataSP &event_data_sp);
void BroadcastEventIfUnique(uint32_t event_type,
EventData *event_data = nullptr);
void Clear();
uint32_t AddListener(const lldb::ListenerSP &listener_sp,
uint32_t event_mask);
const char *GetBroadcasterName() const {
return m_broadcaster.GetBroadcasterName().AsCString();
}
Broadcaster *GetBroadcaster();
bool GetEventNames(Stream &s, const uint32_t event_mask,
bool prefix_with_broadcaster_name) const;
void SetEventName(uint32_t event_mask, const char *name) {
m_event_names[event_mask] = name;
}
const char *GetEventName(uint32_t event_mask) const {
const auto pos = m_event_names.find(event_mask);
if (pos != m_event_names.end())
return pos->second.c_str();
return nullptr;
}
bool EventTypeHasListeners(uint32_t event_type);
bool RemoveListener(lldb_private::Listener *listener,
uint32_t event_mask = UINT32_MAX);
bool RemoveListener(const lldb::ListenerSP &listener_sp,
uint32_t event_mask = UINT32_MAX);
bool HijackBroadcaster(const lldb::ListenerSP &listener_sp,
uint32_t event_mask = UINT32_MAX);
bool IsHijackedForEvent(uint32_t event_mask);
void RestoreBroadcaster();
protected:
void PrivateBroadcastEvent(lldb::EventSP &event_sp, bool unique);
const char *GetHijackingListenerName();
typedef llvm::SmallVector<std::pair<lldb::ListenerWP, uint32_t>, 4>
collection;
typedef std::map<uint32_t, std::string> event_names_map;
llvm::SmallVector<std::pair<lldb::ListenerSP, uint32_t &>, 4>
GetListeners();
/// The broadcaster that this implements.
Broadcaster &m_broadcaster;
/// Optionally define event names for readability and logging for each
/// event bit.
event_names_map m_event_names;
/// A list of Listener / event_mask pairs that are listening to this
/// broadcaster.
collection m_listeners;
/// A mutex that protects \a m_listeners.
std::recursive_mutex m_listeners_mutex;
/// A simple mechanism to intercept events from a broadcaster
std::vector<lldb::ListenerSP> m_hijacking_listeners;
/// At some point we may want to have a stack or Listener collections, but
/// for now this is just for private hijacking.
std::vector<uint32_t> m_hijacking_masks;
private:
DISALLOW_COPY_AND_ASSIGN(BroadcasterImpl);
};
typedef std::shared_ptr<BroadcasterImpl> BroadcasterImplSP;
typedef std::weak_ptr<BroadcasterImpl> BroadcasterImplWP;
BroadcasterImplSP GetBroadcasterImpl() { return m_broadcaster_sp; }
const char *GetHijackingListenerName() {
return m_broadcaster_sp->GetHijackingListenerName();
}
private:
BroadcasterImplSP m_broadcaster_sp;
lldb::BroadcasterManagerSP m_manager_sp;
/// The name of this broadcaster object.
const ConstString m_broadcaster_name;
DISALLOW_COPY_AND_ASSIGN(Broadcaster);
};
} // namespace lldb_private
#endif // LLDB_UTILITY_BROADCASTER_H