//===-- 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 #include #include #include #include #include #include #include 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 { 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 event_listener_key; typedef std::map collection; typedef std::set 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, 4> collection; typedef std::map event_names_map; llvm::SmallVector, 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 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 m_hijacking_masks; private: DISALLOW_COPY_AND_ASSIGN(BroadcasterImpl); }; typedef std::shared_ptr BroadcasterImplSP; typedef std::weak_ptr 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