thread state coordinator: added new thread support.

A new thread arriving while a pending signal notification
is outstanding will (1) add the new thread to the list of
stops expected before the deferred signal notification is
fired, (2) send a stop request for the new thread, and
(3) track the new thread as currently running.

llvm-svn: 218578
This commit is contained in:
Todd Fiala
2014-09-28 06:50:47 +00:00
parent bb51300970
commit 55a02a7478
3 changed files with 133 additions and 1 deletions

View File

@@ -318,7 +318,7 @@ TEST(ThreadStateCoordinatorTest, CallAfterThreadsStopFiresWhenOnePendingThreadDi
ASSERT_EQ (true, request_thread_stop_called);
ASSERT_EQ (PENDING_STOP_TID, request_thread_stop_tid);
// But we still shouldn't have the deferred signal call go off yet. Need to wait for the stop to be reported.
// But we still shouldn't have the deferred signal call go off yet. Need to wait for the death to be reported.
ASSERT_EQ (false, call_after_fired);
// Now report the that the thread with pending stop dies.
@@ -335,3 +335,71 @@ TEST(ThreadStateCoordinatorTest, CallAfterThreadsStopFiresWhenOnePendingThreadDi
ASSERT_EQ (TRIGGERING_TID, reported_firing_tid);
}
TEST(ThreadStateCoordinatorTest, ExistingPendingNotificationRequiresStopFromNewThread)
{
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 };
bool call_after_fired = false;
lldb::tid_t reported_firing_tid = 0;
int request_thread_stop_calls = 0;
ThreadStateCoordinator::ThreadIDSet request_thread_stop_tids;
// 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_calls;
request_thread_stop_tids.insert (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 (0, request_thread_stop_calls);
// Process next event.
ASSERT_EQ (true, coordinator.ProcessNextEvent ());
// Now the request thread stop should have been called for the pending stop.
ASSERT_EQ (1, request_thread_stop_calls);
ASSERT_EQ (true, request_thread_stop_tids.count (PENDING_STOP_TID));
// But we still shouldn't have the deferred signal call go off yet.
ASSERT_EQ (false, call_after_fired);
// Indicate a new thread has just been created.
const lldb::tid_t NEW_THREAD_TID = 1234;
coordinator.NotifyThreadCreate (NEW_THREAD_TID);
ASSERT_EQ (true, coordinator.ProcessNextEvent ());
// We should have just received a stop request for the new thread id.
ASSERT_EQ (2, request_thread_stop_calls);
ASSERT_EQ (true, request_thread_stop_tids.count (NEW_THREAD_TID));
// Now report the original pending tid stopped. This should no longer
// trigger the pending notification because we should now require the
// new thread to stop too.
coordinator.NotifyThreadStop (PENDING_STOP_TID);
ASSERT_EQ (true, coordinator.ProcessNextEvent ());
ASSERT_EQ (false, call_after_fired);
// Now notify the new thread stopped.
coordinator.NotifyThreadStop (NEW_THREAD_TID);
ASSERT_EQ (true, coordinator.ProcessNextEvent ());
// Deferred signal notification should have fired now.
ASSERT_EQ (true, call_after_fired);
ASSERT_EQ (TRIGGERING_TID, reported_firing_tid);
}

View File

@@ -153,6 +153,17 @@ public:
return true;
}
void
AddThreadStopRequirement (lldb::tid_t tid)
{
// Add this tid.
auto insert_result = m_wait_for_stop_tids.insert (tid);
// If it was really added, send the stop request to it.
if (insert_result.second)
m_request_thread_stop_func (tid);
}
private:
void
@@ -196,6 +207,33 @@ private:
//===----------------------------------------------------------------------===//
class ThreadStateCoordinator::EventThreadCreate : public ThreadStateCoordinator::EventBase
{
public:
EventThreadCreate (lldb::tid_t tid):
EventBase (),
m_tid (tid)
{
}
~EventThreadCreate () override
{
}
bool
ProcessEvent(ThreadStateCoordinator &coordinator) override
{
coordinator.ThreadWasCreated (m_tid);
return true;
}
private:
const lldb::tid_t m_tid;
};
//===----------------------------------------------------------------------===//
class ThreadStateCoordinator::EventThreadDeath : public ThreadStateCoordinator::EventBase
{
public:
@@ -310,6 +348,22 @@ ThreadStateCoordinator::ThreadDidStop (lldb::tid_t tid)
}
}
void
ThreadStateCoordinator::ThreadWasCreated (lldb::tid_t tid)
{
// Add the new thread to the stop map.
// We assume a created thread is not stopped.
m_tid_stop_map[tid] = false;
if (m_pending_notification_sp)
{
// Tell the pending notification that we need to wait
// for this new thread to stop.
EventCallAfterThreadsStop *const call_after_event = static_cast<EventCallAfterThreadsStop*> (m_pending_notification_sp.get ());
call_after_event->AddThreadStopRequirement (tid);
}
}
void
ThreadStateCoordinator::ThreadDidDie (lldb::tid_t tid)
{
@@ -348,6 +402,12 @@ ThreadStateCoordinator::NotifyThreadStop (lldb::tid_t tid)
EnqueueEvent (EventBaseSP (new EventThreadStopped (tid)));
}
void
ThreadStateCoordinator::NotifyThreadCreate (lldb::tid_t tid)
{
EnqueueEvent (EventBaseSP (new EventThreadCreate (tid)));
}
void
ThreadStateCoordinator::NotifyThreadDeath (lldb::tid_t tid)
{

View File

@@ -79,6 +79,7 @@ namespace lldb_private
class EventCallAfterThreadsStop;
class EventStopCoordinator;
class EventThreadStopped;
class EventThreadCreate;
class EventThreadDeath;
typedef std::shared_ptr<EventBase> EventBaseSP;
@@ -101,6 +102,9 @@ namespace lldb_private
void
ThreadDidStop (lldb::tid_t tid);
void
ThreadWasCreated (lldb::tid_t tid);
void
ThreadDidDie (lldb::tid_t tid);