forked from OSchip/llvm-project
thread state coordinator: handle when prerequisite pending stop is already stopped.
Change includes new gtest and functionality. llvm-svn: 218555
This commit is contained in:
parent
d20d44fbe6
commit
e9c9e7070e
|
@ -110,3 +110,52 @@ TEST(ThreadStateCoordinatorTest, CallAfterThreadsStopFiresWhenOnePendingStop)
|
|||
ASSERT_EQ (true, call_after_fired);
|
||||
ASSERT_EQ (TRIGGERING_TID, reported_firing_tid);
|
||||
}
|
||||
|
||||
TEST(ThreadStateCoordinatorTest, CallAfterThreadsStopFiresWhenPendingAlreadyStopped)
|
||||
{
|
||||
ThreadStateCoordinator coordinator(NOPLogger);
|
||||
|
||||
const lldb::tid_t TRIGGERING_TID = 4105;
|
||||
const lldb::tid_t PENDING_STOP_TID = 3;
|
||||
|
||||
ThreadStateCoordinator::ThreadIDSet pending_stop_tids { PENDING_STOP_TID };
|
||||
|
||||
// Tell coordinator the pending stop tid is already stopped.
|
||||
coordinator.NotifyThreadStop (PENDING_STOP_TID);
|
||||
ASSERT_EQ (true, coordinator.ProcessNextEvent ());
|
||||
|
||||
// Now fire the deferred thread stop notification, indicating that the pending thread
|
||||
// must be stopped before we notify.
|
||||
bool call_after_fired = false;
|
||||
lldb::tid_t reported_firing_tid = 0;
|
||||
|
||||
bool request_thread_stop_called = false;
|
||||
lldb::tid_t request_thread_stop_tid = 0;
|
||||
|
||||
// Notify we have a trigger that needs to be fired when all threads in the wait tid set have stopped.
|
||||
coordinator.CallAfterThreadsStop (TRIGGERING_TID,
|
||||
pending_stop_tids,
|
||||
[&](lldb::tid_t tid) {
|
||||
request_thread_stop_called = true;
|
||||
request_thread_stop_tid = tid;
|
||||
|
||||
},
|
||||
[&](lldb::tid_t tid) {
|
||||
call_after_fired = true;
|
||||
reported_firing_tid = tid;
|
||||
});
|
||||
|
||||
// Neither trigger should have gone off yet.
|
||||
ASSERT_EQ (false, call_after_fired);
|
||||
ASSERT_EQ (false, request_thread_stop_called);
|
||||
|
||||
// Process next event.
|
||||
ASSERT_EQ (true, coordinator.ProcessNextEvent ());
|
||||
|
||||
// The pending stop should *not* fire because the coordinator knows it has already stopped.
|
||||
ASSERT_EQ (false, request_thread_stop_called);
|
||||
|
||||
// The deferred signal notification should have fired since all requirements were met.
|
||||
ASSERT_EQ (true, call_after_fired);
|
||||
ASSERT_EQ (TRIGGERING_TID, reported_firing_tid);
|
||||
}
|
||||
|
|
|
@ -94,12 +94,27 @@ public:
|
|||
bool
|
||||
ProcessEvent(ThreadStateCoordinator &coordinator) override
|
||||
{
|
||||
// Request a stop for all the thread stops that are needed.
|
||||
// In the future, we can keep track of which stops we're
|
||||
// still waiting for, and can not re-issue for already
|
||||
// requested stops.
|
||||
// Request a stop for all the thread stops that need to be stopped
|
||||
// and are not already known to be stopped. Keep a list of all the
|
||||
// threads from which we still need to hear a stop reply.
|
||||
|
||||
ThreadIDSet sent_tids;
|
||||
for (auto tid : m_wait_for_stop_tids)
|
||||
m_request_thread_stop_func (tid);
|
||||
{
|
||||
// If we don't know about the thread's stop state or we
|
||||
// know it is not stopped, we need to send it a stop request.
|
||||
auto find_it = coordinator.m_tid_stop_map.find (tid);
|
||||
if ((find_it == coordinator.m_tid_stop_map.end ()) || !find_it->second)
|
||||
{
|
||||
m_request_thread_stop_func (tid);
|
||||
sent_tids.insert (tid);
|
||||
}
|
||||
}
|
||||
|
||||
// We only need to wait for the sent_tids - so swap our wait set
|
||||
// to the sent tids. The rest are already stopped and we won't
|
||||
// be receiving stop notifications for them.
|
||||
m_wait_for_stop_tids.swap (sent_tids);
|
||||
|
||||
if (m_wait_for_stop_tids.empty ())
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue