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:
Todd Fiala 2014-09-26 23:42:53 +00:00
parent d20d44fbe6
commit e9c9e7070e
2 changed files with 69 additions and 5 deletions

View File

@ -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);
}

View File

@ -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 ())
{