summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp
diff options
context:
space:
mode:
authorTodd Fiala <todd.fiala@gmail.com>2014-09-30 16:56:28 +0000
committerTodd Fiala <todd.fiala@gmail.com>2014-09-30 16:56:28 +0000
commitf8d929dc827000d109a5c619648fa239b79a18e9 (patch)
tree8e4b8a4dfc86d7dd47a9c303a3c7d43f8dfbaf1a /lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp
parent7a770755305f19426e5748195035a26e6e673077 (diff)
downloadbcm5719-llvm-f8d929dc827000d109a5c619648fa239b79a18e9.tar.gz
bcm5719-llvm-f8d929dc827000d109a5c619648fa239b79a18e9.zip
thread state coordinator: add test to be explicit about resume behavior in presence of deferred stop notification still pending.
There is a state transition that seems potentially buggy that I am capturing and logging here, and including an explicit test to demonstrate expected behavior. See new test for detailed description. Added logging around this area since, if we hit it, we may have a usage bug, or a new state transition we really need to investigate. This is around this scenario: Thread C deferred stop notification awaiting thread A and thread B to stop. Thread A stops. Thread A requests resume. Thread B stops. Here we will explicitly signal the deferred stop notification after thread B stops even though thread A is now resumed. Copious logging happens here. llvm-svn: 218683
Diffstat (limited to 'lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp')
-rw-r--r--lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp65
1 files changed, 56 insertions, 9 deletions
diff --git a/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp b/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp
index cd5ad6df3da..532d67ea905 100644
--- a/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp
+++ b/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp
@@ -68,6 +68,7 @@ public:
EventBase (),
m_triggering_tid (triggering_tid),
m_wait_for_stop_tids (wait_for_stop_tids),
+ m_original_wait_for_stop_tids (wait_for_stop_tids),
m_request_thread_stop_func (request_thread_stop_func),
m_call_after_func (call_after_func)
{
@@ -84,6 +85,19 @@ public:
return m_wait_for_stop_tids;
}
+ const ThreadIDSet &
+ GetRemainingWaitTIDs () const
+ {
+ return m_wait_for_stop_tids;
+ }
+
+
+ const ThreadIDSet &
+ GetInitialWaitTIDs () const
+ {
+ return m_original_wait_for_stop_tids;
+ }
+
bool
ProcessEvent(ThreadStateCoordinator &coordinator) override
{
@@ -167,6 +181,7 @@ private:
const lldb::tid_t m_triggering_tid;
ThreadIDSet m_wait_for_stop_tids;
+ const ThreadIDSet m_original_wait_for_stop_tids;
ThreadIDFunc m_request_thread_stop_func;
ThreadIDFunc m_call_after_func;
};
@@ -288,9 +303,36 @@ public:
return true;
}
+ // Before we do the resume below, first check if we have a pending
+ // stop notification this is currently or was previously waiting for
+ // this thread to stop. This is potentially a buggy situation since
+ // we're ostensibly waiting for threads to stop before we send out the
+ // pending notification, and here we are resuming one before we send
+ // out the pending stop notification.
+ const EventCallAfterThreadsStop *const pending_stop_notification = coordinator.GetPendingThreadStopNotification ();
+ if (pending_stop_notification)
+ {
+ if (pending_stop_notification->GetRemainingWaitTIDs ().count (m_tid) > 0)
+ {
+ coordinator.Log ("EventRequestResume::%s about to resume tid %" PRIu64 " per explicit request but we have a pending stop notification (tid %" PRIu64 ") that is actively waiting for this thread to stop. Valid sequence of events?", __FUNCTION__, m_tid, pending_stop_notification->GetTriggeringTID ());
+ }
+ else if (pending_stop_notification->GetInitialWaitTIDs ().count (m_tid) > 0)
+ {
+ coordinator.Log ("EventRequestResume::%s about to resume tid %" PRIu64 " per explicit request but we have a pending stop notification (tid %" PRIu64 ") that hasn't fired yet and this is one of the threads we had been waiting on (and already marked satisfied for this tid). Valid sequence of events?", __FUNCTION__, m_tid, pending_stop_notification->GetTriggeringTID ());
+ for (auto tid : pending_stop_notification->GetRemainingWaitTIDs ())
+ {
+ coordinator.Log ("EventRequestResume::%s tid %" PRIu64 " deferred stop notification still waiting on tid %" PRIu64,
+ __FUNCTION__,
+ pending_stop_notification->GetTriggeringTID (),
+ tid);
+ }
+ }
+ }
+
// Request a resume. We expect this to be synchronous and the system
// to reflect it is running after this completes.
m_request_thread_resume_func (m_tid);
+
return true;
}
@@ -343,10 +385,9 @@ ThreadStateCoordinator::SetPendingNotification (const EventBaseSP &event_sp)
const EventCallAfterThreadsStop *new_call_after_event = static_cast<EventCallAfterThreadsStop*> (event_sp.get ());
- if (m_pending_notification_sp)
+ EventCallAfterThreadsStop *const prev_call_after_event = GetPendingThreadStopNotification ();
+ if (prev_call_after_event)
{
- const EventCallAfterThreadsStop *prev_call_after_event = static_cast<EventCallAfterThreadsStop*> (m_pending_notification_sp.get ());
-
// Yikes - we've already got a pending signal notification in progress.
// Log this info. We lose the pending notification here.
Log ("ThreadStateCoordinator::%s dropping existing pending signal notification for tid %" PRIu64 ", to be replaced with signal for tid %" PRIu64,
@@ -377,9 +418,9 @@ ThreadStateCoordinator::ThreadDidStop (lldb::tid_t tid)
m_tid_stop_map[tid] = true;
// If we have a pending notification, remove this from the set.
- if (m_pending_notification_sp)
+ EventCallAfterThreadsStop *const call_after_event = GetPendingThreadStopNotification ();
+ if (call_after_event)
{
- 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)
{
@@ -396,11 +437,11 @@ ThreadStateCoordinator::ThreadWasCreated (lldb::tid_t tid)
// We assume a created thread is not stopped.
m_tid_stop_map[tid] = false;
- if (m_pending_notification_sp)
+ EventCallAfterThreadsStop *const call_after_event = GetPendingThreadStopNotification ();
+ if (call_after_event)
{
// 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);
}
}
@@ -414,9 +455,9 @@ ThreadStateCoordinator::ThreadDidDie (lldb::tid_t tid)
m_tid_stop_map.erase (tid);
// If we have a pending notification, remove this from the set.
- if (m_pending_notification_sp)
+ EventCallAfterThreadsStop *const call_after_event = GetPendingThreadStopNotification ();
+ if (call_after_event)
{
- 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)
{
@@ -505,3 +546,9 @@ ThreadStateCoordinator::ProcessNextEvent ()
{
return DequeueEventWithWait()->ProcessEvent (*this);
}
+
+ThreadStateCoordinator::EventCallAfterThreadsStop *
+ThreadStateCoordinator::GetPendingThreadStopNotification ()
+{
+ return static_cast<EventCallAfterThreadsStop*> (m_pending_notification_sp.get ());
+}
OpenPOWER on IntegriCloud