diff options
3 files changed, 133 insertions, 1 deletions
diff --git a/lldb/gtest/unittest/Plugins/Process/Linux/ThreadStateCoordinatorTest.cpp b/lldb/gtest/unittest/Plugins/Process/Linux/ThreadStateCoordinatorTest.cpp index b08c2c2e3a8..6835b110d73 100644 --- a/lldb/gtest/unittest/Plugins/Process/Linux/ThreadStateCoordinatorTest.cpp +++ b/lldb/gtest/unittest/Plugins/Process/Linux/ThreadStateCoordinatorTest.cpp @@ -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); +} + diff --git a/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp b/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp index 354dcc2bcc6..a3c9491457a 100644 --- a/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp +++ b/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp @@ -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: @@ -311,6 +349,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) { // Update the global list of known thread states. While this one is stopped, it is also dead. @@ -349,6 +403,12 @@ ThreadStateCoordinator::NotifyThreadStop (lldb::tid_t tid) } void +ThreadStateCoordinator::NotifyThreadCreate (lldb::tid_t tid) +{ + EnqueueEvent (EventBaseSP (new EventThreadCreate (tid))); +} + +void ThreadStateCoordinator::NotifyThreadDeath (lldb::tid_t tid) { EnqueueEvent (EventBaseSP (new EventThreadDeath (tid))); diff --git a/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.h b/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.h index 6fecb1ce90a..14399abfe08 100644 --- a/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.h +++ b/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.h @@ -79,6 +79,7 @@ namespace lldb_private class EventCallAfterThreadsStop; class EventStopCoordinator; class EventThreadStopped; + class EventThreadCreate; class EventThreadDeath; typedef std::shared_ptr<EventBase> EventBaseSP; @@ -102,6 +103,9 @@ namespace lldb_private ThreadDidStop (lldb::tid_t tid); void + ThreadWasCreated (lldb::tid_t tid); + + void ThreadDidDie (lldb::tid_t tid); void |