[lldb][NFC] Fix all formatting errors in .cpp file headers
Summary:
A *.cpp file header in LLDB (and in LLDB) should like this:
```
//===-- TestUtilities.cpp -------------------------------------------------===//
```
However in LLDB most of our source files have arbitrary changes to this format and
these changes are spreading through LLDB as folks usually just use the existing
source files as templates for their new files (most notably the unnecessary
editor language indicator `-*- C++ -*-` is spreading and in every review
someone is pointing out that this is wrong, resulting in people pointing out that this
is done in the same way in other files).
This patch removes most of these inconsistencies including the editor language indicators,
all the different missing/additional '-' characters, files that center the file name, missing
trailing `===//` (mostly caused by clang-format breaking the line).
Reviewers: aprantl, espindola, jfb, shafik, JDevlieghere
Reviewed By: JDevlieghere
Subscribers: dexonsmith, wuzish, emaste, sdardis, nemanjai, kbarton, MaskRay, atanasyan, arphaman, jfb, abidh, jsji, JDevlieghere, usaxena95, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D73258
2020-01-24 15:23:27 +08:00
|
|
|
//===-- Broadcaster.cpp ---------------------------------------------------===//
|
2010-06-09 00:52:24 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// 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
|
2010-06-09 00:52:24 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2018-12-14 23:59:49 +08:00
|
|
|
#include "lldb/Utility/Broadcaster.h"
|
2010-06-09 00:52:24 +08:00
|
|
|
|
2018-12-14 23:59:49 +08:00
|
|
|
#include "lldb/Utility/Event.h"
|
|
|
|
#include "lldb/Utility/Listener.h"
|
2017-03-04 04:56:28 +08:00
|
|
|
#include "lldb/Utility/Log.h"
|
2018-11-12 07:16:43 +08:00
|
|
|
#include "lldb/Utility/Logging.h"
|
|
|
|
#include "lldb/Utility/Stream.h"
|
2017-02-03 05:39:50 +08:00
|
|
|
#include "lldb/Utility/StreamString.h"
|
2010-06-09 00:52:24 +08:00
|
|
|
|
2018-11-12 07:16:43 +08:00
|
|
|
#include <algorithm>
|
|
|
|
#include <memory>
|
2019-05-24 04:05:21 +08:00
|
|
|
#include <utility>
|
2017-04-07 05:28:29 +08:00
|
|
|
|
2021-05-26 18:19:37 +08:00
|
|
|
#include <cassert>
|
|
|
|
#include <cstddef>
|
2017-04-07 05:28:29 +08:00
|
|
|
|
2010-06-09 00:52:24 +08:00
|
|
|
using namespace lldb;
|
|
|
|
using namespace lldb_private;
|
|
|
|
|
2016-03-08 05:50:25 +08:00
|
|
|
Broadcaster::Broadcaster(BroadcasterManagerSP manager_sp, const char *name)
|
2017-04-07 05:28:29 +08:00
|
|
|
: m_broadcaster_sp(std::make_shared<BroadcasterImpl>(*this)),
|
2019-05-24 04:05:21 +08:00
|
|
|
m_manager_sp(std::move(manager_sp)), m_broadcaster_name(name) {
|
2016-03-08 21:33:14 +08:00
|
|
|
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT));
|
2019-05-24 12:41:47 +08:00
|
|
|
LLDB_LOG(log, "{0} Broadcaster::Broadcaster(\"{1}\")",
|
2020-02-11 16:05:37 +08:00
|
|
|
static_cast<void *>(this), GetBroadcasterName());
|
2016-03-08 05:50:25 +08:00
|
|
|
}
|
|
|
|
|
2016-05-18 09:59:10 +08:00
|
|
|
Broadcaster::BroadcasterImpl::BroadcasterImpl(Broadcaster &broadcaster)
|
|
|
|
: m_broadcaster(broadcaster), m_listeners(), m_listeners_mutex(),
|
|
|
|
m_hijacking_listeners(), m_hijacking_masks() {}
|
2010-06-09 00:52:24 +08:00
|
|
|
|
|
|
|
Broadcaster::~Broadcaster() {
|
2013-03-28 07:08:40 +08:00
|
|
|
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT));
|
2019-05-24 12:41:47 +08:00
|
|
|
LLDB_LOG(log, "{0} Broadcaster::~Broadcaster(\"{1}\")",
|
2020-02-11 16:05:37 +08:00
|
|
|
static_cast<void *>(this), GetBroadcasterName());
|
2010-06-09 00:52:24 +08:00
|
|
|
|
2011-10-01 08:45:15 +08:00
|
|
|
Clear();
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
|
2012-02-16 14:50:00 +08:00
|
|
|
void Broadcaster::CheckInWithManager() {
|
2016-03-08 05:50:25 +08:00
|
|
|
if (m_manager_sp) {
|
|
|
|
m_manager_sp->SignUpListenersForBroadcaster(*this);
|
2012-02-16 14:50:00 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Fix a race in Broadcaster/Listener interaction
Summary:
The following problem was occuring:
- broadcaster B had two listeners: L1 and L2 (thread T1)
- (T1) B has started to broadcast an event, it has locked a shared_ptr to L1 (in
ListenerIterator())
- on another thread T2 the penultimate reference to L1 was destroyed (the transient object in B is
now the last reference)
- (T2) the last reference to L2 was destroyed as well
- (T1) B has finished broadcasting the event to L1 and destroyed the last shared_ptr
- (T1) this triggered the destructor, which called into B->RemoveListener()
- (T1) all pointers in the m_listeners list were now stale, so RemoveListener emptied the list
- (T1) Eventually control returned to the ListenerIterator() for doing broadcasting, which was
still in the middle of iterating through the list
- (T1) Only now, it was holding onto a dangling iterator. BOOM.
I fix this issue by making sure nothing can interfere with the
iterate-and-remove-expired-pointers loop, by moving this logic into a single function, which
first locks (or clears) the whole list and then returns the list of valid and locked Listeners
for further processing. Instead of std::list I use an llvm::SmallVector which should hopefully
offset the fact that we create a copy of the list for the common case where we have only a few
listeners (no heap allocations).
A slight difference in behaviour is that now RemoveListener does not remove an element from the
list -- it only sets it's mask to 0, which means it will be removed during the next iteration of
GetListeners(). This is purely an implementation detail and it should not be externally
noticable.
I was not able to reproduce this bug reliably without inserting sleep statements into the code,
so I do not add a test for it. Instead, I add some unit tests for the functions that I do modify.
Reviewers: clayborg, jingham
Subscribers: tberghammer, lldb-commits
Differential Revision: https://reviews.llvm.org/D23406
llvm-svn: 278664
2016-08-15 17:53:08 +08:00
|
|
|
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());
|
2016-09-07 04:57:50 +08:00
|
|
|
|
Fix a race in Broadcaster/Listener interaction
Summary:
The following problem was occuring:
- broadcaster B had two listeners: L1 and L2 (thread T1)
- (T1) B has started to broadcast an event, it has locked a shared_ptr to L1 (in
ListenerIterator())
- on another thread T2 the penultimate reference to L1 was destroyed (the transient object in B is
now the last reference)
- (T2) the last reference to L2 was destroyed as well
- (T1) B has finished broadcasting the event to L1 and destroyed the last shared_ptr
- (T1) this triggered the destructor, which called into B->RemoveListener()
- (T1) all pointers in the m_listeners list were now stale, so RemoveListener emptied the list
- (T1) Eventually control returned to the ListenerIterator() for doing broadcasting, which was
still in the middle of iterating through the list
- (T1) Only now, it was holding onto a dangling iterator. BOOM.
I fix this issue by making sure nothing can interfere with the
iterate-and-remove-expired-pointers loop, by moving this logic into a single function, which
first locks (or clears) the whole list and then returns the list of valid and locked Listeners
for further processing. Instead of std::list I use an llvm::SmallVector which should hopefully
offset the fact that we create a copy of the list for the common case where we have only a few
listeners (no heap allocations).
A slight difference in behaviour is that now RemoveListener does not remove an element from the
list -- it only sets it's mask to 0, which means it will be removed during the next iteration of
GetListeners(). This is purely an implementation detail and it should not be externally
noticable.
I was not able to reproduce this bug reliably without inserting sleep statements into the code,
so I do not add a test for it. Instead, I add some unit tests for the functions that I do modify.
Reviewers: clayborg, jingham
Subscribers: tberghammer, lldb-commits
Differential Revision: https://reviews.llvm.org/D23406
llvm-svn: 278664
2016-08-15 17:53:08 +08:00
|
|
|
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;
|
2016-09-07 04:57:50 +08:00
|
|
|
} else
|
Fix a race in Broadcaster/Listener interaction
Summary:
The following problem was occuring:
- broadcaster B had two listeners: L1 and L2 (thread T1)
- (T1) B has started to broadcast an event, it has locked a shared_ptr to L1 (in
ListenerIterator())
- on another thread T2 the penultimate reference to L1 was destroyed (the transient object in B is
now the last reference)
- (T2) the last reference to L2 was destroyed as well
- (T1) B has finished broadcasting the event to L1 and destroyed the last shared_ptr
- (T1) this triggered the destructor, which called into B->RemoveListener()
- (T1) all pointers in the m_listeners list were now stale, so RemoveListener emptied the list
- (T1) Eventually control returned to the ListenerIterator() for doing broadcasting, which was
still in the middle of iterating through the list
- (T1) Only now, it was holding onto a dangling iterator. BOOM.
I fix this issue by making sure nothing can interfere with the
iterate-and-remove-expired-pointers loop, by moving this logic into a single function, which
first locks (or clears) the whole list and then returns the list of valid and locked Listeners
for further processing. Instead of std::list I use an llvm::SmallVector which should hopefully
offset the fact that we create a copy of the list for the common case where we have only a few
listeners (no heap allocations).
A slight difference in behaviour is that now RemoveListener does not remove an element from the
list -- it only sets it's mask to 0, which means it will be removed during the next iteration of
GetListeners(). This is purely an implementation detail and it should not be externally
noticable.
I was not able to reproduce this bug reliably without inserting sleep statements into the code,
so I do not add a test for it. Instead, I add some unit tests for the functions that I do modify.
Reviewers: clayborg, jingham
Subscribers: tberghammer, lldb-commits
Differential Revision: https://reviews.llvm.org/D23406
llvm-svn: 278664
2016-08-15 17:53:08 +08:00
|
|
|
it = m_listeners.erase(it);
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
Fix a race in Broadcaster/Listener interaction
Summary:
The following problem was occuring:
- broadcaster B had two listeners: L1 and L2 (thread T1)
- (T1) B has started to broadcast an event, it has locked a shared_ptr to L1 (in
ListenerIterator())
- on another thread T2 the penultimate reference to L1 was destroyed (the transient object in B is
now the last reference)
- (T2) the last reference to L2 was destroyed as well
- (T1) B has finished broadcasting the event to L1 and destroyed the last shared_ptr
- (T1) this triggered the destructor, which called into B->RemoveListener()
- (T1) all pointers in the m_listeners list were now stale, so RemoveListener emptied the list
- (T1) Eventually control returned to the ListenerIterator() for doing broadcasting, which was
still in the middle of iterating through the list
- (T1) Only now, it was holding onto a dangling iterator. BOOM.
I fix this issue by making sure nothing can interfere with the
iterate-and-remove-expired-pointers loop, by moving this logic into a single function, which
first locks (or clears) the whole list and then returns the list of valid and locked Listeners
for further processing. Instead of std::list I use an llvm::SmallVector which should hopefully
offset the fact that we create a copy of the list for the common case where we have only a few
listeners (no heap allocations).
A slight difference in behaviour is that now RemoveListener does not remove an element from the
list -- it only sets it's mask to 0, which means it will be removed during the next iteration of
GetListeners(). This is purely an implementation detail and it should not be externally
noticable.
I was not able to reproduce this bug reliably without inserting sleep statements into the code,
so I do not add a test for it. Instead, I add some unit tests for the functions that I do modify.
Reviewers: clayborg, jingham
Subscribers: tberghammer, lldb-commits
Differential Revision: https://reviews.llvm.org/D23406
llvm-svn: 278664
2016-08-15 17:53:08 +08:00
|
|
|
return listeners;
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2016-03-08 05:50:25 +08:00
|
|
|
void Broadcaster::BroadcasterImpl::Clear() {
|
2016-05-18 09:59:10 +08:00
|
|
|
std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2018-05-01 00:49:04 +08:00
|
|
|
// Make sure the listener forgets about this broadcaster. We do this in the
|
|
|
|
// broadcaster in case the broadcaster object initiates the removal.
|
Fix a race in Broadcaster/Listener interaction
Summary:
The following problem was occuring:
- broadcaster B had two listeners: L1 and L2 (thread T1)
- (T1) B has started to broadcast an event, it has locked a shared_ptr to L1 (in
ListenerIterator())
- on another thread T2 the penultimate reference to L1 was destroyed (the transient object in B is
now the last reference)
- (T2) the last reference to L2 was destroyed as well
- (T1) B has finished broadcasting the event to L1 and destroyed the last shared_ptr
- (T1) this triggered the destructor, which called into B->RemoveListener()
- (T1) all pointers in the m_listeners list were now stale, so RemoveListener emptied the list
- (T1) Eventually control returned to the ListenerIterator() for doing broadcasting, which was
still in the middle of iterating through the list
- (T1) Only now, it was holding onto a dangling iterator. BOOM.
I fix this issue by making sure nothing can interfere with the
iterate-and-remove-expired-pointers loop, by moving this logic into a single function, which
first locks (or clears) the whole list and then returns the list of valid and locked Listeners
for further processing. Instead of std::list I use an llvm::SmallVector which should hopefully
offset the fact that we create a copy of the list for the common case where we have only a few
listeners (no heap allocations).
A slight difference in behaviour is that now RemoveListener does not remove an element from the
list -- it only sets it's mask to 0, which means it will be removed during the next iteration of
GetListeners(). This is purely an implementation detail and it should not be externally
noticable.
I was not able to reproduce this bug reliably without inserting sleep statements into the code,
so I do not add a test for it. Instead, I add some unit tests for the functions that I do modify.
Reviewers: clayborg, jingham
Subscribers: tberghammer, lldb-commits
Differential Revision: https://reviews.llvm.org/D23406
llvm-svn: 278664
2016-08-15 17:53:08 +08:00
|
|
|
for (auto &pair : GetListeners())
|
|
|
|
pair.first->BroadcasterWillDestruct(&m_broadcaster);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2011-10-01 08:45:15 +08:00
|
|
|
m_listeners.clear();
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2016-05-18 09:59:10 +08:00
|
|
|
Broadcaster *Broadcaster::BroadcasterImpl::GetBroadcaster() {
|
2016-03-08 05:50:25 +08:00
|
|
|
return &m_broadcaster;
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2016-03-08 05:50:25 +08:00
|
|
|
bool Broadcaster::BroadcasterImpl::GetEventNames(
|
|
|
|
Stream &s, uint32_t event_mask, bool prefix_with_broadcaster_name) const {
|
2010-10-31 11:01:06 +08:00
|
|
|
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(", ");
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2010-10-31 11:01:06 +08:00
|
|
|
if (prefix_with_broadcaster_name) {
|
2016-03-08 05:50:25 +08:00
|
|
|
s.PutCString(GetBroadcasterName());
|
2010-10-31 11:01:06 +08:00
|
|
|
s.PutChar('.');
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2016-11-03 04:34:10 +08:00
|
|
|
s.PutCString(pos->second);
|
2010-10-31 11:01:06 +08:00
|
|
|
++num_names_added;
|
2016-05-13 06:58:52 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2016-05-13 06:58:52 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
Fix a race in Broadcaster/Listener interaction
Summary:
The following problem was occuring:
- broadcaster B had two listeners: L1 and L2 (thread T1)
- (T1) B has started to broadcast an event, it has locked a shared_ptr to L1 (in
ListenerIterator())
- on another thread T2 the penultimate reference to L1 was destroyed (the transient object in B is
now the last reference)
- (T2) the last reference to L2 was destroyed as well
- (T1) B has finished broadcasting the event to L1 and destroyed the last shared_ptr
- (T1) this triggered the destructor, which called into B->RemoveListener()
- (T1) all pointers in the m_listeners list were now stale, so RemoveListener emptied the list
- (T1) Eventually control returned to the ListenerIterator() for doing broadcasting, which was
still in the middle of iterating through the list
- (T1) Only now, it was holding onto a dangling iterator. BOOM.
I fix this issue by making sure nothing can interfere with the
iterate-and-remove-expired-pointers loop, by moving this logic into a single function, which
first locks (or clears) the whole list and then returns the list of valid and locked Listeners
for further processing. Instead of std::list I use an llvm::SmallVector which should hopefully
offset the fact that we create a copy of the list for the common case where we have only a few
listeners (no heap allocations).
A slight difference in behaviour is that now RemoveListener does not remove an element from the
list -- it only sets it's mask to 0, which means it will be removed during the next iteration of
GetListeners(). This is purely an implementation detail and it should not be externally
noticable.
I was not able to reproduce this bug reliably without inserting sleep statements into the code,
so I do not add a test for it. Instead, I add some unit tests for the functions that I do modify.
Reviewers: clayborg, jingham
Subscribers: tberghammer, lldb-commits
Differential Revision: https://reviews.llvm.org/D23406
llvm-svn: 278664
2016-08-15 17:53:08 +08:00
|
|
|
return num_names_added > 0;
|
2016-05-13 06:58:52 +08:00
|
|
|
}
|
|
|
|
|
2011-10-01 08:45:15 +08:00
|
|
|
void Broadcaster::AddInitialEventsToListener(
|
Fix a race in Broadcaster/Listener interaction
Summary:
The following problem was occuring:
- broadcaster B had two listeners: L1 and L2 (thread T1)
- (T1) B has started to broadcast an event, it has locked a shared_ptr to L1 (in
ListenerIterator())
- on another thread T2 the penultimate reference to L1 was destroyed (the transient object in B is
now the last reference)
- (T2) the last reference to L2 was destroyed as well
- (T1) B has finished broadcasting the event to L1 and destroyed the last shared_ptr
- (T1) this triggered the destructor, which called into B->RemoveListener()
- (T1) all pointers in the m_listeners list were now stale, so RemoveListener emptied the list
- (T1) Eventually control returned to the ListenerIterator() for doing broadcasting, which was
still in the middle of iterating through the list
- (T1) Only now, it was holding onto a dangling iterator. BOOM.
I fix this issue by making sure nothing can interfere with the
iterate-and-remove-expired-pointers loop, by moving this logic into a single function, which
first locks (or clears) the whole list and then returns the list of valid and locked Listeners
for further processing. Instead of std::list I use an llvm::SmallVector which should hopefully
offset the fact that we create a copy of the list for the common case where we have only a few
listeners (no heap allocations).
A slight difference in behaviour is that now RemoveListener does not remove an element from the
list -- it only sets it's mask to 0, which means it will be removed during the next iteration of
GetListeners(). This is purely an implementation detail and it should not be externally
noticable.
I was not able to reproduce this bug reliably without inserting sleep statements into the code,
so I do not add a test for it. Instead, I add some unit tests for the functions that I do modify.
Reviewers: clayborg, jingham
Subscribers: tberghammer, lldb-commits
Differential Revision: https://reviews.llvm.org/D23406
llvm-svn: 278664
2016-08-15 17:53:08 +08:00
|
|
|
const lldb::ListenerSP &listener_sp, uint32_t requested_events) {}
|
2016-03-02 09:09:03 +08:00
|
|
|
|
2016-09-07 04:57:50 +08:00
|
|
|
uint32_t
|
2016-03-08 05:50:25 +08:00
|
|
|
Broadcaster::BroadcasterImpl::AddListener(const lldb::ListenerSP &listener_sp,
|
2010-06-09 00:52:24 +08:00
|
|
|
uint32_t event_mask) {
|
2016-03-08 05:50:25 +08:00
|
|
|
if (!listener_sp)
|
|
|
|
return 0;
|
2010-06-09 00:52:24 +08:00
|
|
|
|
2010-10-31 11:01:06 +08:00
|
|
|
std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex);
|
|
|
|
|
2016-05-13 06:58:52 +08:00
|
|
|
// See if we already have this listener, and if so, update its mask
|
2010-06-09 00:52:24 +08:00
|
|
|
|
2016-05-13 06:58:52 +08:00
|
|
|
bool handled = false;
|
2010-12-23 03:29:31 +08:00
|
|
|
|
2016-05-18 09:59:10 +08:00
|
|
|
for (auto &pair : GetListeners()) {
|
|
|
|
if (pair.first == listener_sp) {
|
2016-05-13 06:58:52 +08:00
|
|
|
handled = true;
|
2016-05-18 09:59:10 +08:00
|
|
|
pair.second |= event_mask;
|
|
|
|
m_broadcaster.AddInitialEventsToListener(listener_sp, event_mask);
|
|
|
|
break;
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
|
|
|
|
if (!handled) {
|
|
|
|
// Grant a new listener the available event bits
|
|
|
|
m_listeners.push_back(
|
|
|
|
std::make_pair(lldb::ListenerWP(listener_sp), event_mask));
|
|
|
|
|
2016-05-13 06:58:52 +08:00
|
|
|
// 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);
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
|
2016-05-13 06:58:52 +08:00
|
|
|
// Return the event bits that were granted to the listener
|
|
|
|
return event_mask;
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
2016-05-13 06:58:52 +08:00
|
|
|
|
|
|
|
bool Broadcaster::BroadcasterImpl::EventTypeHasListeners(uint32_t event_type) {
|
|
|
|
std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex);
|
2010-06-09 00:52:24 +08:00
|
|
|
|
2016-05-13 06:58:52 +08:00
|
|
|
if (!m_hijacking_listeners.empty() && event_type & m_hijacking_masks.back())
|
|
|
|
return true;
|
2010-06-09 00:52:24 +08:00
|
|
|
|
|
|
|
for (auto &pair : GetListeners()) {
|
|
|
|
if (pair.second & event_type)
|
|
|
|
return true;
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2016-05-13 06:58:52 +08:00
|
|
|
return false;
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
|
2016-03-08 05:50:25 +08:00
|
|
|
bool Broadcaster::BroadcasterImpl::RemoveListener(
|
2016-03-02 09:09:03 +08:00
|
|
|
lldb_private::Listener *listener, uint32_t event_mask) {
|
Fix a race in Broadcaster/Listener interaction
Summary:
The following problem was occuring:
- broadcaster B had two listeners: L1 and L2 (thread T1)
- (T1) B has started to broadcast an event, it has locked a shared_ptr to L1 (in
ListenerIterator())
- on another thread T2 the penultimate reference to L1 was destroyed (the transient object in B is
now the last reference)
- (T2) the last reference to L2 was destroyed as well
- (T1) B has finished broadcasting the event to L1 and destroyed the last shared_ptr
- (T1) this triggered the destructor, which called into B->RemoveListener()
- (T1) all pointers in the m_listeners list were now stale, so RemoveListener emptied the list
- (T1) Eventually control returned to the ListenerIterator() for doing broadcasting, which was
still in the middle of iterating through the list
- (T1) Only now, it was holding onto a dangling iterator. BOOM.
I fix this issue by making sure nothing can interfere with the
iterate-and-remove-expired-pointers loop, by moving this logic into a single function, which
first locks (or clears) the whole list and then returns the list of valid and locked Listeners
for further processing. Instead of std::list I use an llvm::SmallVector which should hopefully
offset the fact that we create a copy of the list for the common case where we have only a few
listeners (no heap allocations).
A slight difference in behaviour is that now RemoveListener does not remove an element from the
list -- it only sets it's mask to 0, which means it will be removed during the next iteration of
GetListeners(). This is purely an implementation detail and it should not be externally
noticable.
I was not able to reproduce this bug reliably without inserting sleep statements into the code,
so I do not add a test for it. Instead, I add some unit tests for the functions that I do modify.
Reviewers: clayborg, jingham
Subscribers: tberghammer, lldb-commits
Differential Revision: https://reviews.llvm.org/D23406
llvm-svn: 278664
2016-08-15 17:53:08 +08:00
|
|
|
if (!listener)
|
|
|
|
return false;
|
2010-06-09 00:52:24 +08:00
|
|
|
|
Fix a race in Broadcaster/Listener interaction
Summary:
The following problem was occuring:
- broadcaster B had two listeners: L1 and L2 (thread T1)
- (T1) B has started to broadcast an event, it has locked a shared_ptr to L1 (in
ListenerIterator())
- on another thread T2 the penultimate reference to L1 was destroyed (the transient object in B is
now the last reference)
- (T2) the last reference to L2 was destroyed as well
- (T1) B has finished broadcasting the event to L1 and destroyed the last shared_ptr
- (T1) this triggered the destructor, which called into B->RemoveListener()
- (T1) all pointers in the m_listeners list were now stale, so RemoveListener emptied the list
- (T1) Eventually control returned to the ListenerIterator() for doing broadcasting, which was
still in the middle of iterating through the list
- (T1) Only now, it was holding onto a dangling iterator. BOOM.
I fix this issue by making sure nothing can interfere with the
iterate-and-remove-expired-pointers loop, by moving this logic into a single function, which
first locks (or clears) the whole list and then returns the list of valid and locked Listeners
for further processing. Instead of std::list I use an llvm::SmallVector which should hopefully
offset the fact that we create a copy of the list for the common case where we have only a few
listeners (no heap allocations).
A slight difference in behaviour is that now RemoveListener does not remove an element from the
list -- it only sets it's mask to 0, which means it will be removed during the next iteration of
GetListeners(). This is purely an implementation detail and it should not be externally
noticable.
I was not able to reproduce this bug reliably without inserting sleep statements into the code,
so I do not add a test for it. Instead, I add some unit tests for the functions that I do modify.
Reviewers: clayborg, jingham
Subscribers: tberghammer, lldb-commits
Differential Revision: https://reviews.llvm.org/D23406
llvm-svn: 278664
2016-08-15 17:53:08 +08:00
|
|
|
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;
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-05-13 06:58:52 +08:00
|
|
|
bool Broadcaster::BroadcasterImpl::RemoveListener(
|
|
|
|
const lldb::ListenerSP &listener_sp, uint32_t event_mask) {
|
|
|
|
return RemoveListener(listener_sp.get(), event_mask);
|
|
|
|
}
|
|
|
|
|
2016-03-08 05:50:25 +08:00
|
|
|
void Broadcaster::BroadcasterImpl::BroadcastEvent(EventSP &event_sp) {
|
2010-06-09 00:52:24 +08:00
|
|
|
return PrivateBroadcastEvent(event_sp, false);
|
|
|
|
}
|
|
|
|
|
2016-03-08 05:50:25 +08:00
|
|
|
void Broadcaster::BroadcasterImpl::BroadcastEventIfUnique(EventSP &event_sp) {
|
2010-06-09 00:52:24 +08:00
|
|
|
return PrivateBroadcastEvent(event_sp, true);
|
|
|
|
}
|
|
|
|
|
2016-03-08 05:50:25 +08:00
|
|
|
void Broadcaster::BroadcasterImpl::PrivateBroadcastEvent(EventSP &event_sp,
|
|
|
|
bool unique) {
|
2016-03-02 09:09:03 +08:00
|
|
|
// Can't add a nullptr event...
|
|
|
|
if (!event_sp)
|
2010-06-09 00:52:24 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Update the broadcaster on this event
|
2016-03-08 05:50:25 +08:00
|
|
|
event_sp->SetBroadcaster(&m_broadcaster);
|
2010-06-09 00:52:24 +08:00
|
|
|
|
|
|
|
const uint32_t event_type = event_sp->GetType();
|
|
|
|
|
2016-05-18 09:59:10 +08:00
|
|
|
std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex);
|
2014-04-04 12:06:10 +08:00
|
|
|
|
2016-03-08 05:50:25 +08:00
|
|
|
ListenerSP hijacking_listener_sp;
|
|
|
|
|
2011-02-10 14:51:22 +08:00
|
|
|
if (!m_hijacking_listeners.empty()) {
|
|
|
|
assert(!m_hijacking_masks.empty());
|
2016-03-08 05:50:25 +08:00
|
|
|
hijacking_listener_sp = m_hijacking_listeners.back();
|
2011-02-10 14:51:22 +08:00
|
|
|
if ((event_type & m_hijacking_masks.back()) == 0)
|
2016-03-08 05:50:25 +08:00
|
|
|
hijacking_listener_sp.reset();
|
2011-02-10 14:51:22 +08:00
|
|
|
}
|
|
|
|
|
2019-05-24 12:41:47 +08:00
|
|
|
if (Log *log = lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EVENTS)) {
|
2010-06-09 00:52:24 +08:00
|
|
|
StreamString event_description;
|
|
|
|
event_sp->Dump(&event_description);
|
2019-07-25 01:56:10 +08:00
|
|
|
LLDB_LOGF(log,
|
|
|
|
"%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()));
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
|
2016-03-08 05:50:25 +08:00
|
|
|
if (hijacking_listener_sp) {
|
2019-05-24 12:41:47 +08:00
|
|
|
if (unique && hijacking_listener_sp->PeekAtNextEventForBroadcasterWithType(
|
|
|
|
&m_broadcaster, event_type))
|
2010-10-12 07:53:14 +08:00
|
|
|
return;
|
2016-03-08 05:50:25 +08:00
|
|
|
hijacking_listener_sp->AddEvent(event_sp);
|
2010-10-12 07:53:14 +08:00
|
|
|
} else {
|
Fix a race in Broadcaster/Listener interaction
Summary:
The following problem was occuring:
- broadcaster B had two listeners: L1 and L2 (thread T1)
- (T1) B has started to broadcast an event, it has locked a shared_ptr to L1 (in
ListenerIterator())
- on another thread T2 the penultimate reference to L1 was destroyed (the transient object in B is
now the last reference)
- (T2) the last reference to L2 was destroyed as well
- (T1) B has finished broadcasting the event to L1 and destroyed the last shared_ptr
- (T1) this triggered the destructor, which called into B->RemoveListener()
- (T1) all pointers in the m_listeners list were now stale, so RemoveListener emptied the list
- (T1) Eventually control returned to the ListenerIterator() for doing broadcasting, which was
still in the middle of iterating through the list
- (T1) Only now, it was holding onto a dangling iterator. BOOM.
I fix this issue by making sure nothing can interfere with the
iterate-and-remove-expired-pointers loop, by moving this logic into a single function, which
first locks (or clears) the whole list and then returns the list of valid and locked Listeners
for further processing. Instead of std::list I use an llvm::SmallVector which should hopefully
offset the fact that we create a copy of the list for the common case where we have only a few
listeners (no heap allocations).
A slight difference in behaviour is that now RemoveListener does not remove an element from the
list -- it only sets it's mask to 0, which means it will be removed during the next iteration of
GetListeners(). This is purely an implementation detail and it should not be externally
noticable.
I was not able to reproduce this bug reliably without inserting sleep statements into the code,
so I do not add a test for it. Instead, I add some unit tests for the functions that I do modify.
Reviewers: clayborg, jingham
Subscribers: tberghammer, lldb-commits
Differential Revision: https://reviews.llvm.org/D23406
llvm-svn: 278664
2016-08-15 17:53:08 +08:00
|
|
|
for (auto &pair : GetListeners()) {
|
|
|
|
if (!(pair.second & event_type))
|
|
|
|
continue;
|
2019-05-24 12:41:47 +08:00
|
|
|
if (unique && pair.first->PeekAtNextEventForBroadcasterWithType(
|
|
|
|
&m_broadcaster, event_type))
|
Fix a race in Broadcaster/Listener interaction
Summary:
The following problem was occuring:
- broadcaster B had two listeners: L1 and L2 (thread T1)
- (T1) B has started to broadcast an event, it has locked a shared_ptr to L1 (in
ListenerIterator())
- on another thread T2 the penultimate reference to L1 was destroyed (the transient object in B is
now the last reference)
- (T2) the last reference to L2 was destroyed as well
- (T1) B has finished broadcasting the event to L1 and destroyed the last shared_ptr
- (T1) this triggered the destructor, which called into B->RemoveListener()
- (T1) all pointers in the m_listeners list were now stale, so RemoveListener emptied the list
- (T1) Eventually control returned to the ListenerIterator() for doing broadcasting, which was
still in the middle of iterating through the list
- (T1) Only now, it was holding onto a dangling iterator. BOOM.
I fix this issue by making sure nothing can interfere with the
iterate-and-remove-expired-pointers loop, by moving this logic into a single function, which
first locks (or clears) the whole list and then returns the list of valid and locked Listeners
for further processing. Instead of std::list I use an llvm::SmallVector which should hopefully
offset the fact that we create a copy of the list for the common case where we have only a few
listeners (no heap allocations).
A slight difference in behaviour is that now RemoveListener does not remove an element from the
list -- it only sets it's mask to 0, which means it will be removed during the next iteration of
GetListeners(). This is purely an implementation detail and it should not be externally
noticable.
I was not able to reproduce this bug reliably without inserting sleep statements into the code,
so I do not add a test for it. Instead, I add some unit tests for the functions that I do modify.
Reviewers: clayborg, jingham
Subscribers: tberghammer, lldb-commits
Differential Revision: https://reviews.llvm.org/D23406
llvm-svn: 278664
2016-08-15 17:53:08 +08:00
|
|
|
continue;
|
2016-09-07 04:57:50 +08:00
|
|
|
|
Fix a race in Broadcaster/Listener interaction
Summary:
The following problem was occuring:
- broadcaster B had two listeners: L1 and L2 (thread T1)
- (T1) B has started to broadcast an event, it has locked a shared_ptr to L1 (in
ListenerIterator())
- on another thread T2 the penultimate reference to L1 was destroyed (the transient object in B is
now the last reference)
- (T2) the last reference to L2 was destroyed as well
- (T1) B has finished broadcasting the event to L1 and destroyed the last shared_ptr
- (T1) this triggered the destructor, which called into B->RemoveListener()
- (T1) all pointers in the m_listeners list were now stale, so RemoveListener emptied the list
- (T1) Eventually control returned to the ListenerIterator() for doing broadcasting, which was
still in the middle of iterating through the list
- (T1) Only now, it was holding onto a dangling iterator. BOOM.
I fix this issue by making sure nothing can interfere with the
iterate-and-remove-expired-pointers loop, by moving this logic into a single function, which
first locks (or clears) the whole list and then returns the list of valid and locked Listeners
for further processing. Instead of std::list I use an llvm::SmallVector which should hopefully
offset the fact that we create a copy of the list for the common case where we have only a few
listeners (no heap allocations).
A slight difference in behaviour is that now RemoveListener does not remove an element from the
list -- it only sets it's mask to 0, which means it will be removed during the next iteration of
GetListeners(). This is purely an implementation detail and it should not be externally
noticable.
I was not able to reproduce this bug reliably without inserting sleep statements into the code,
so I do not add a test for it. Instead, I add some unit tests for the functions that I do modify.
Reviewers: clayborg, jingham
Subscribers: tberghammer, lldb-commits
Differential Revision: https://reviews.llvm.org/D23406
llvm-svn: 278664
2016-08-15 17:53:08 +08:00
|
|
|
pair.first->AddEvent(event_sp);
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
|
2016-03-08 05:50:25 +08:00
|
|
|
void Broadcaster::BroadcasterImpl::BroadcastEvent(uint32_t event_type,
|
|
|
|
EventData *event_data) {
|
2017-04-07 05:28:29 +08:00
|
|
|
auto event_sp = std::make_shared<Event>(event_type, event_data);
|
2010-06-09 00:52:24 +08:00
|
|
|
PrivateBroadcastEvent(event_sp, false);
|
|
|
|
}
|
|
|
|
|
2016-05-13 06:58:52 +08:00
|
|
|
void Broadcaster::BroadcasterImpl::BroadcastEvent(
|
|
|
|
uint32_t event_type, const lldb::EventDataSP &event_data_sp) {
|
2017-04-07 05:28:29 +08:00
|
|
|
auto event_sp = std::make_shared<Event>(event_type, event_data_sp);
|
2016-05-13 06:58:52 +08:00
|
|
|
PrivateBroadcastEvent(event_sp, false);
|
|
|
|
}
|
|
|
|
|
2016-03-08 05:50:25 +08:00
|
|
|
void Broadcaster::BroadcasterImpl::BroadcastEventIfUnique(
|
|
|
|
uint32_t event_type, EventData *event_data) {
|
2017-04-07 05:28:29 +08:00
|
|
|
auto event_sp = std::make_shared<Event>(event_type, event_data);
|
2010-06-09 00:52:24 +08:00
|
|
|
PrivateBroadcastEvent(event_sp, true);
|
|
|
|
}
|
|
|
|
|
2016-05-13 06:58:52 +08:00
|
|
|
bool Broadcaster::BroadcasterImpl::HijackBroadcaster(
|
|
|
|
const lldb::ListenerSP &listener_sp, uint32_t event_mask) {
|
2016-05-18 09:59:10 +08:00
|
|
|
std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2013-03-28 07:08:40 +08:00
|
|
|
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EVENTS));
|
2019-05-24 12:41:47 +08:00
|
|
|
LLDB_LOG(
|
|
|
|
log,
|
|
|
|
"{0} Broadcaster(\"{1}\")::HijackBroadcaster (listener(\"{2}\")={3})",
|
|
|
|
static_cast<void *>(this), GetBroadcasterName(),
|
|
|
|
listener_sp->m_name.c_str(), static_cast<void *>(listener_sp.get()));
|
2016-03-08 05:50:25 +08:00
|
|
|
m_hijacking_listeners.push_back(listener_sp);
|
2011-02-08 13:16:50 +08:00
|
|
|
m_hijacking_masks.push_back(event_mask);
|
2010-10-12 07:53:14 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-03-08 05:50:25 +08:00
|
|
|
bool Broadcaster::BroadcasterImpl::IsHijackedForEvent(uint32_t event_mask) {
|
2016-05-18 09:59:10 +08:00
|
|
|
std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex);
|
2015-02-05 03:42:32 +08:00
|
|
|
|
|
|
|
if (!m_hijacking_listeners.empty())
|
|
|
|
return (event_mask & m_hijacking_masks.back()) != 0;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-03-08 05:50:25 +08:00
|
|
|
const char *Broadcaster::BroadcasterImpl::GetHijackingListenerName() {
|
|
|
|
if (m_hijacking_listeners.size()) {
|
|
|
|
return m_hijacking_listeners.back()->GetName();
|
|
|
|
}
|
2019-05-24 12:41:47 +08:00
|
|
|
return nullptr;
|
2016-03-08 05:50:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Broadcaster::BroadcasterImpl::RestoreBroadcaster() {
|
2016-05-18 09:59:10 +08:00
|
|
|
std::lock_guard<std::recursive_mutex> guard(m_listeners_mutex);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2014-01-28 07:43:24 +08:00
|
|
|
if (!m_hijacking_listeners.empty()) {
|
2019-05-24 12:41:47 +08:00
|
|
|
ListenerSP listener_sp = m_hijacking_listeners.back();
|
2014-02-05 02:51:11 +08:00
|
|
|
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EVENTS));
|
2019-05-24 12:41:47 +08:00
|
|
|
LLDB_LOG(log,
|
|
|
|
"{0} Broadcaster(\"{1}\")::RestoreBroadcaster (about to pop "
|
|
|
|
"listener(\"{2}\")={3})",
|
|
|
|
static_cast<void *>(this), GetBroadcasterName(),
|
|
|
|
listener_sp->m_name.c_str(),
|
|
|
|
static_cast<void *>(listener_sp.get()));
|
2014-01-28 07:43:24 +08:00
|
|
|
m_hijacking_listeners.pop_back();
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2014-01-28 07:43:24 +08:00
|
|
|
if (!m_hijacking_masks.empty())
|
|
|
|
m_hijacking_masks.pop_back();
|
2010-10-12 07:53:14 +08:00
|
|
|
}
|
|
|
|
|
2012-02-16 14:50:00 +08:00
|
|
|
ConstString &Broadcaster::GetBroadcasterClass() const {
|
|
|
|
static ConstString class_name("lldb.anonymous");
|
|
|
|
return class_name;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool BroadcastEventSpec::operator<(const BroadcastEventSpec &rhs) const {
|
|
|
|
if (GetBroadcasterClass() == rhs.GetBroadcasterClass()) {
|
|
|
|
return GetEventBits() < rhs.GetEventBits();
|
|
|
|
}
|
2019-05-24 12:41:47 +08:00
|
|
|
return GetBroadcasterClass() < rhs.GetBroadcasterClass();
|
2012-02-16 14:50:00 +08:00
|
|
|
}
|
|
|
|
|
2016-03-02 09:09:03 +08:00
|
|
|
BroadcasterManager::BroadcasterManager() : m_manager_mutex() {}
|
2012-02-16 14:50:00 +08:00
|
|
|
|
2016-05-18 09:59:10 +08:00
|
|
|
lldb::BroadcasterManagerSP BroadcasterManager::MakeBroadcasterManager() {
|
2017-04-07 05:28:29 +08:00
|
|
|
return lldb::BroadcasterManagerSP(new BroadcasterManager());
|
2012-02-16 14:50:00 +08:00
|
|
|
}
|
|
|
|
|
2016-03-08 05:50:25 +08:00
|
|
|
uint32_t BroadcasterManager::RegisterListenerForEvents(
|
2019-05-24 04:05:21 +08:00
|
|
|
const lldb::ListenerSP &listener_sp, const BroadcastEventSpec &event_spec) {
|
2016-03-08 05:50:25 +08:00
|
|
|
std::lock_guard<std::recursive_mutex> guard(m_manager_mutex);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2012-02-16 14:50:00 +08:00
|
|
|
collection::iterator iter = m_event_map.begin(), end_iter = m_event_map.end();
|
|
|
|
uint32_t available_bits = event_spec.GetEventBits();
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2012-02-16 14:50:00 +08:00
|
|
|
while (iter != end_iter &&
|
|
|
|
(iter = find_if(iter, end_iter,
|
2016-03-08 05:50:25 +08:00
|
|
|
BroadcasterClassMatches(
|
2012-02-16 14:50:00 +08:00
|
|
|
event_spec.GetBroadcasterClass()))) != end_iter) {
|
2016-03-08 05:50:25 +08:00
|
|
|
available_bits &= ~((*iter).first.GetEventBits());
|
2016-09-07 04:57:50 +08:00
|
|
|
iter++;
|
|
|
|
}
|
|
|
|
|
2012-02-16 14:50:00 +08:00
|
|
|
if (available_bits != 0) {
|
2016-03-08 05:50:25 +08:00
|
|
|
m_event_map.insert(event_listener_key(
|
|
|
|
BroadcastEventSpec(event_spec.GetBroadcasterClass(), available_bits),
|
|
|
|
listener_sp));
|
|
|
|
m_listeners.insert(listener_sp);
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2016-03-08 05:50:25 +08:00
|
|
|
return available_bits;
|
|
|
|
}
|
|
|
|
|
2016-05-13 06:58:52 +08:00
|
|
|
bool BroadcasterManager::UnregisterListenerForEvents(
|
2019-05-24 04:05:21 +08:00
|
|
|
const lldb::ListenerSP &listener_sp, const BroadcastEventSpec &event_spec) {
|
2016-05-18 09:59:10 +08:00
|
|
|
std::lock_guard<std::recursive_mutex> guard(m_manager_mutex);
|
2012-02-16 14:50:00 +08:00
|
|
|
bool removed_some = false;
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2012-02-16 14:50:00 +08:00
|
|
|
if (m_listeners.erase(listener_sp) == 0)
|
|
|
|
return false;
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2012-02-16 14:50:00 +08:00
|
|
|
ListenerMatchesAndSharedBits predicate(event_spec, listener_sp);
|
|
|
|
std::vector<BroadcastEventSpec> to_be_readded;
|
|
|
|
uint32_t event_bits_to_remove = event_spec.GetEventBits();
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2012-02-16 14:50:00 +08:00
|
|
|
// Go through the map and delete the exact matches, and build a list of
|
|
|
|
// matches that weren't exact to re-add:
|
2016-03-02 09:09:03 +08:00
|
|
|
while (true) {
|
2012-02-16 14:50:00 +08:00
|
|
|
collection::iterator iter, end_iter = m_event_map.end();
|
|
|
|
iter = find_if(m_event_map.begin(), end_iter, predicate);
|
|
|
|
if (iter == end_iter) {
|
|
|
|
break;
|
|
|
|
}
|
2019-05-24 12:41:47 +08:00
|
|
|
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;
|
2020-03-03 07:53:59 +08:00
|
|
|
to_be_readded.emplace_back(event_spec.GetBroadcasterClass(),
|
|
|
|
new_event_bits);
|
2019-05-24 12:41:47 +08:00
|
|
|
}
|
|
|
|
m_event_map.erase(iter);
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2012-02-16 14:50:00 +08:00
|
|
|
// 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));
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
|
2012-02-16 14:50:00 +08:00
|
|
|
return removed_some;
|
|
|
|
}
|
|
|
|
|
2016-05-13 06:58:52 +08:00
|
|
|
ListenerSP BroadcasterManager::GetListenerForEventSpec(
|
2019-05-24 04:05:21 +08:00
|
|
|
const BroadcastEventSpec &event_spec) const {
|
2016-05-18 09:59:10 +08:00
|
|
|
std::lock_guard<std::recursive_mutex> guard(m_manager_mutex);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2012-02-16 14:50:00 +08:00
|
|
|
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;
|
2019-05-24 12:41:47 +08:00
|
|
|
|
|
|
|
return nullptr;
|
2012-02-16 14:50:00 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2012-02-16 14:50:00 +08:00
|
|
|
void BroadcasterManager::RemoveListener(Listener *listener) {
|
2016-05-18 09:59:10 +08:00
|
|
|
std::lock_guard<std::recursive_mutex> guard(m_manager_mutex);
|
2016-03-08 05:50:25 +08:00
|
|
|
ListenerMatchesPointer predicate(listener);
|
2012-02-16 14:50:00 +08:00
|
|
|
listener_collection::iterator iter = m_listeners.begin(),
|
2016-03-08 05:50:25 +08:00
|
|
|
end_iter = m_listeners.end();
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2020-02-05 07:56:51 +08:00
|
|
|
iter = std::find_if(iter, end_iter, predicate);
|
2012-02-16 14:50:00 +08:00
|
|
|
if (iter != end_iter)
|
2016-03-08 05:50:25 +08:00
|
|
|
m_listeners.erase(iter);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2016-03-02 09:09:03 +08:00
|
|
|
while (true) {
|
2012-02-16 14:50:00 +08:00
|
|
|
collection::iterator iter, end_iter = m_event_map.end();
|
|
|
|
iter = find_if(m_event_map.begin(), end_iter, predicate);
|
|
|
|
if (iter == end_iter)
|
|
|
|
break;
|
2019-05-24 12:41:47 +08:00
|
|
|
|
|
|
|
m_event_map.erase(iter);
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
2012-02-16 14:50:00 +08:00
|
|
|
}
|
|
|
|
|
2016-03-08 05:50:25 +08:00
|
|
|
void BroadcasterManager::RemoveListener(const lldb::ListenerSP &listener_sp) {
|
2016-05-18 09:59:10 +08:00
|
|
|
std::lock_guard<std::recursive_mutex> guard(m_manager_mutex);
|
2016-03-08 05:50:25 +08:00
|
|
|
ListenerMatches predicate(listener_sp);
|
|
|
|
|
|
|
|
if (m_listeners.erase(listener_sp) == 0)
|
2012-02-16 14:50:00 +08:00
|
|
|
return;
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2016-03-02 09:09:03 +08:00
|
|
|
while (true) {
|
2012-02-16 14:50:00 +08:00
|
|
|
collection::iterator iter, end_iter = m_event_map.end();
|
|
|
|
iter = find_if(m_event_map.begin(), end_iter, predicate);
|
|
|
|
if (iter == end_iter)
|
|
|
|
break;
|
2019-05-24 12:41:47 +08:00
|
|
|
|
|
|
|
m_event_map.erase(iter);
|
2012-02-16 14:50:00 +08:00
|
|
|
}
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2012-02-16 14:50:00 +08:00
|
|
|
void BroadcasterManager::SignUpListenersForBroadcaster(
|
|
|
|
Broadcaster &broadcaster) {
|
2016-05-18 09:59:10 +08:00
|
|
|
std::lock_guard<std::recursive_mutex> guard(m_manager_mutex);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2012-02-16 14:50:00 +08:00
|
|
|
collection::iterator iter = m_event_map.begin(), end_iter = m_event_map.end();
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2012-02-16 14:50:00 +08:00
|
|
|
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() {
|
2016-05-18 09:59:10 +08:00
|
|
|
std::lock_guard<std::recursive_mutex> guard(m_manager_mutex);
|
2012-02-16 14:50:00 +08:00
|
|
|
listener_collection::iterator end_iter = m_listeners.end();
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2012-02-16 14:50:00 +08:00
|
|
|
for (listener_collection::iterator iter = m_listeners.begin();
|
|
|
|
iter != end_iter; iter++)
|
2016-03-08 05:50:25 +08:00
|
|
|
(*iter)->BroadcasterManagerWillDestruct(this->shared_from_this());
|
2012-02-16 14:50:00 +08:00
|
|
|
m_listeners.clear();
|
|
|
|
m_event_map.clear();
|
|
|
|
}
|