mirror of
https://github.com/intel/llvm.git
synced 2026-01-19 09:31:59 +08:00
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:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user