[Lldb-commits] [lldb] r218559 - thread state coordinator: added thread death support and more tests.

Todd Fiala todd.fiala at gmail.com
Fri Sep 26 18:58:13 PDT 2014


Author: tfiala
Date: Fri Sep 26 20:58:13 2014
New Revision: 218559

URL: http://llvm.org/viewvc/llvm-project?rev=218559&view=rev
Log:
thread state coordinator: added thread death support and more tests.

Tested two pending stops before notification, where one of the pending stop
requirements was already known to be stopped.

Tested pending thread stop before notification, then reporting thread with
pending stop died and verifies pending notification is made.

Modified:
    lldb/trunk/gtest/unittest/Plugins/Process/Linux/ThreadStateCoordinatorTest.cpp
    lldb/trunk/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp
    lldb/trunk/source/Plugins/Process/Linux/ThreadStateCoordinator.h

Modified: lldb/trunk/gtest/unittest/Plugins/Process/Linux/ThreadStateCoordinatorTest.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/gtest/unittest/Plugins/Process/Linux/ThreadStateCoordinatorTest.cpp?rev=218559&r1=218558&r2=218559&view=diff
==============================================================================
--- lldb/trunk/gtest/unittest/Plugins/Process/Linux/ThreadStateCoordinatorTest.cpp (original)
+++ lldb/trunk/gtest/unittest/Plugins/Process/Linux/ThreadStateCoordinatorTest.cpp Fri Sep 26 20:58:13 2014
@@ -220,3 +220,118 @@ TEST(ThreadStateCoordinatorTest, CallAft
     ASSERT_EQ (true, call_after_fired);
     ASSERT_EQ (TRIGGERING_TID, reported_firing_tid);
 }
+
+TEST(ThreadStateCoordinatorTest, CallAfterThreadsStopFiresWhenTwoPendingOneAlreadyStopped)
+{
+    ThreadStateCoordinator coordinator(NOPLogger);
+
+    const lldb::tid_t TRIGGERING_TID = 4105;
+    const lldb::tid_t PENDING_STOP_TID = 3;
+    const lldb::tid_t PENDING_STOP_TID_02 = 29016;
+
+    ThreadStateCoordinator::ThreadIDSet pending_stop_tids { PENDING_STOP_TID, PENDING_STOP_TID_02 };
+
+    // 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;
+
+    int request_thread_stop_calls = 0;
+    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_calls;
+                                          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 (0, request_thread_stop_calls);
+
+    // Process next event.
+    ASSERT_EQ (true, coordinator.ProcessNextEvent ());
+
+    // The pending stop should only fire for one of the threads, the one that wasn't already stopped.
+    ASSERT_EQ (1, request_thread_stop_calls);
+    ASSERT_EQ (PENDING_STOP_TID_02, request_thread_stop_tid);
+
+    // The deferred signal notification should not yet have fired since all pending thread stops have not yet occurred.
+    ASSERT_EQ (false, call_after_fired);
+
+    // Notify final thread has stopped.
+    coordinator.NotifyThreadStop (PENDING_STOP_TID_02);
+    ASSERT_EQ (true, coordinator.ProcessNextEvent ());
+
+    // 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);
+}
+
+TEST(ThreadStateCoordinatorTest, CallAfterThreadsStopFiresWhenOnePendingThreadDies)
+{
+    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;
+
+    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 ());
+
+    // Now the request thread stop should have been called for the pending stop.
+    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.
+    ASSERT_EQ (false, call_after_fired);
+
+    // Now report the that the thread with pending stop dies.
+    coordinator.NotifyThreadDeath (PENDING_STOP_TID);
+
+    // Shouldn't take effect until after next processing step.
+    ASSERT_EQ (false, call_after_fired);
+
+    // Process next event.
+    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);
+}
+

Modified: lldb/trunk/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp?rev=218559&r1=218558&r2=218559&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp Fri Sep 26 20:58:13 2014
@@ -133,14 +133,34 @@ public:
         return true;
     }
 
+    // Return true if still pending thread stops waiting; false if no more stops.
+    // If no more pending stops, signal.
+    bool
+    RemoveThreadStopRequirementAndMaybeSignal (lldb::tid_t tid)
+    {
+        // Remove this tid if it was in it.
+        m_wait_for_stop_tids.erase (tid);
+
+        // Fire pending notification if no pending thread stops remain.
+        if (m_wait_for_stop_tids.empty ())
+        {
+            // Fire the pending notification now.
+            NotifyNow ();
+            return false;
+        }
+
+        // Still have pending thread stops.
+        return true;
+    }
+
+private:
+
     void
     NotifyNow ()
     {
         m_call_after_func (m_triggering_tid);
     }
 
-private:
-
     const lldb::tid_t m_triggering_tid;
     ThreadIDSet m_wait_for_stop_tids;
     ThreadIDFunc m_request_thread_stop_func;
@@ -176,6 +196,33 @@ private:
 
 //===----------------------------------------------------------------------===//
 
+class ThreadStateCoordinator::EventThreadDeath : public ThreadStateCoordinator::EventBase
+{
+public:
+    EventThreadDeath (lldb::tid_t tid):
+    EventBase (),
+    m_tid (tid)
+    {
+    }
+
+    ~EventThreadDeath () override
+    {
+    }
+
+    bool
+    ProcessEvent(ThreadStateCoordinator &coordinator) override
+    {
+        coordinator.ThreadDidDie (m_tid);
+        return true;
+    }
+
+private:
+
+    const lldb::tid_t m_tid;
+};
+
+//===----------------------------------------------------------------------===//
+
 ThreadStateCoordinator::ThreadStateCoordinator (const LogFunc &log_func) :
     m_log_func (log_func),
     m_event_queue (),
@@ -253,17 +300,31 @@ ThreadStateCoordinator::ThreadDidStop (l
     // If we have a pending notification, remove this from the set.
     if (m_pending_notification_sp)
     {
-        EventCallAfterThreadsStop *call_after_event = static_cast<EventCallAfterThreadsStop*> (m_pending_notification_sp.get ());
+        EventCallAfterThreadsStop *const call_after_event = static_cast<EventCallAfterThreadsStop*> (m_pending_notification_sp.get ());
+        const bool pending_stops_remain = call_after_event->RemoveThreadStopRequirementAndMaybeSignal (tid);
+        if (!pending_stops_remain)
+        {
+            // Clear the pending notification now.
+            m_pending_notification_sp.reset ();
+        }
+    }
+}
 
-        ThreadIDSet &remaining_stop_tids = call_after_event->GetRemainingWaitTIDs ();
+void
+ThreadStateCoordinator::ThreadDidDie (lldb::tid_t tid)
+{
+    // Update the global list of known thread states.  While this one is stopped, it is also dead.
+    // So stop tracking it.  We assume the user of this coordinator will not keep trying to add
+    // dependencies on a thread after it is known to be dead.
+    m_tid_stop_map.erase (tid);
 
-        // Remove this tid if it was in it.
-        remaining_stop_tids.erase (tid);
-        if (remaining_stop_tids.empty ())
+    // If we have a pending notification, remove this from the set.
+    if (m_pending_notification_sp)
+    {
+        EventCallAfterThreadsStop *const call_after_event = static_cast<EventCallAfterThreadsStop*> (m_pending_notification_sp.get ());
+        const bool pending_stops_remain = call_after_event->RemoveThreadStopRequirementAndMaybeSignal (tid);
+        if (!pending_stops_remain)
         {
-            // Fire the pending notification now.
-            call_after_event->NotifyNow ();
-
             // Clear the pending notification now.
             m_pending_notification_sp.reset ();
         }
@@ -288,6 +349,12 @@ ThreadStateCoordinator::NotifyThreadStop
 }
 
 void
+ThreadStateCoordinator::NotifyThreadDeath (lldb::tid_t tid)
+{
+    EnqueueEvent (EventBaseSP (new EventThreadDeath (tid)));
+}
+
+void
 ThreadStateCoordinator::StopCoordinator ()
 {
     EnqueueEvent (EventBaseSP (new EventStopCoordinator ()));

Modified: lldb/trunk/source/Plugins/Process/Linux/ThreadStateCoordinator.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ThreadStateCoordinator.h?rev=218559&r1=218558&r2=218559&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/ThreadStateCoordinator.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/ThreadStateCoordinator.h Fri Sep 26 20:58:13 2014
@@ -79,6 +79,7 @@ namespace lldb_private
         class EventCallAfterThreadsStop;
         class EventStopCoordinator;
         class EventThreadStopped;
+        class EventThreadDeath;
 
         typedef std::shared_ptr<EventBase> EventBaseSP;
 
@@ -101,6 +102,9 @@ namespace lldb_private
         ThreadDidStop (lldb::tid_t tid);
 
         void
+        ThreadDidDie (lldb::tid_t tid);
+
+        void
         Log (const char *format, ...);
 
         // Member variables.





More information about the lldb-commits mailing list