summaryrefslogtreecommitdiffstats
path: root/lldb/source
diff options
context:
space:
mode:
authorTodd Fiala <todd.fiala@gmail.com>2014-10-02 19:03:06 +0000
committerTodd Fiala <todd.fiala@gmail.com>2014-10-02 19:03:06 +0000
commit325111bcc6ee751e16faeeca405ed4b103b2ffce (patch)
tree3055cbd4e49abda4c12181d84b2f48aa0afe1384 /lldb/source
parent2b60cd1b6831d7e95578eb8901495480e9aa301b (diff)
downloadbcm5719-llvm-325111bcc6ee751e16faeeca405ed4b103b2ffce.tar.gz
bcm5719-llvm-325111bcc6ee751e16faeeca405ed4b103b2ffce.zip
thread state coordinator: added simpler deferred stop notification method.
Now that ThreadStateCoordinator errors out on threads in unexpected states, it has enough information to know which threads need stop requests fired when we want to do a deferred callback on a thread's behalf. This change adds a new method, CallAfterRunningThreadsStop(...), which no longer takes a set of thread ids that require stop requests. It's much harder to misuse this method and (with newer error logic) it's harder to correctly use the original method. Expect the original method that takes the set of thread ids to stop to disappear in the near future. Adds several tests for CallAfterRunningThreadsStop(). llvm-svn: 218897
Diffstat (limited to 'lldb/source')
-rw-r--r--lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp137
-rw-r--r--lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.h10
2 files changed, 114 insertions, 33 deletions
diff --git a/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp b/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp
index 7f20717f3bf..b6b9412db15 100644
--- a/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp
+++ b/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp
@@ -73,7 +73,23 @@ public:
m_original_wait_for_stop_tids (wait_for_stop_tids),
m_request_thread_stop_function (request_thread_stop_function),
m_call_after_function (call_after_function),
- m_error_function (error_function)
+ m_error_function (error_function),
+ m_request_stop_on_all_unstopped_threads (false)
+ {
+ }
+
+ EventCallAfterThreadsStop (lldb::tid_t triggering_tid,
+ const ThreadIDFunction &request_thread_stop_function,
+ const ThreadIDFunction &call_after_function,
+ const ErrorFunction &error_function) :
+ EventBase (),
+ m_triggering_tid (triggering_tid),
+ m_wait_for_stop_tids (),
+ m_original_wait_for_stop_tids (),
+ m_request_thread_stop_function (request_thread_stop_function),
+ m_call_after_function (call_after_function),
+ m_error_function (error_function),
+ m_request_stop_on_all_unstopped_threads (true)
{
}
@@ -116,42 +132,16 @@ public:
return eventLoopResultContinue;
}
- // Request a stop for all the thread stops that need to be stopped
- // and are not already known to be stopped. Keep a list of all the
- // threads from which we still need to hear a stop reply.
-
- ThreadIDSet sent_tids;
- for (auto tid : m_wait_for_stop_tids)
+ if (m_request_stop_on_all_unstopped_threads)
{
- // Validate we know about all tids for which we must first receive a stop before
- // triggering the deferred stop notification.
- auto find_it = coordinator.m_tid_stop_map.find (tid);
- if (find_it == coordinator.m_tid_stop_map.end ())
- {
- // This is an error. We shouldn't be asking for waiting pids that aren't known.
- // NOTE: we may be stripping out the specification of wait tids and handle this
- // automatically, in which case this state can never occur.
- std::ostringstream error_message;
- error_message << "error: deferred notification for tid " << m_triggering_tid << " specified an unknown/untracked pending stop tid " << m_triggering_tid;
- m_error_function (error_message.str ());
-
- // Bail out here.
+ RequestStopOnAllRunningThreads (coordinator);
+ }
+ else
+ {
+ if (!RequestStopOnAllSpecifiedThreads (coordinator))
return eventLoopResultContinue;
- }
-
- // If the pending stop thread is currently running, we need to send it a stop request.
- if (!find_it->second)
- {
- m_request_thread_stop_function (tid);
- sent_tids.insert (tid);
- }
}
- // We only need to wait for the sent_tids - so swap our wait set
- // to the sent tids. The rest are already stopped and we won't
- // be receiving stop notifications for them.
- m_wait_for_stop_tids.swap (sent_tids);
-
if (m_wait_for_stop_tids.empty ())
{
// We're not waiting for any threads. Fire off the deferred signal delivery event.
@@ -208,12 +198,81 @@ private:
m_call_after_function (m_triggering_tid);
}
+ bool
+ RequestStopOnAllSpecifiedThreads (const ThreadStateCoordinator &coordinator)
+ {
+ // Request a stop for all the thread stops that need to be stopped
+ // and are not already known to be stopped. Keep a list of all the
+ // threads from which we still need to hear a stop reply.
+
+ ThreadIDSet sent_tids;
+ for (auto tid : m_wait_for_stop_tids)
+ {
+ // Validate we know about all tids for which we must first receive a stop before
+ // triggering the deferred stop notification.
+ auto find_it = coordinator.m_tid_stop_map.find (tid);
+ if (find_it == coordinator.m_tid_stop_map.end ())
+ {
+ // This is an error. We shouldn't be asking for waiting pids that aren't known.
+ // NOTE: we may be stripping out the specification of wait tids and handle this
+ // automatically, in which case this state can never occur.
+ std::ostringstream error_message;
+ error_message << "error: deferred notification for tid " << m_triggering_tid << " specified an unknown/untracked pending stop tid " << m_triggering_tid;
+ m_error_function (error_message.str ());
+
+ // Bail out here.
+ return false;
+ }
+
+ // If the pending stop thread is currently running, we need to send it a stop request.
+ if (!find_it->second)
+ {
+ m_request_thread_stop_function (tid);
+ sent_tids.insert (tid);
+ }
+ }
+
+ // We only need to wait for the sent_tids - so swap our wait set
+ // to the sent tids. The rest are already stopped and we won't
+ // be receiving stop notifications for them.
+ m_wait_for_stop_tids.swap (sent_tids);
+
+ // Succeeded, keep running.
+ return true;
+ }
+
+ void
+ RequestStopOnAllRunningThreads (const ThreadStateCoordinator &coordinator)
+ {
+ // Request a stop for all the thread stops that need to be stopped
+ // and are not already known to be stopped. Keep a list of all the
+ // threads from which we still need to hear a stop reply.
+
+ ThreadIDSet sent_tids;
+ for (auto it = coordinator.m_tid_stop_map.begin(); it != coordinator.m_tid_stop_map.end(); ++it)
+ {
+ // We only care about threads not stopped.
+ const bool running = !it->second;
+ if (running)
+ {
+ // Request this thread stop.
+ const lldb::tid_t tid = it->first;
+ m_request_thread_stop_function (tid);
+ sent_tids.insert (tid);
+ }
+ }
+
+ // Set the wait list to the set of tids for which we requested stops.
+ m_wait_for_stop_tids.swap (sent_tids);
+ }
+
const lldb::tid_t m_triggering_tid;
ThreadIDSet m_wait_for_stop_tids;
const ThreadIDSet m_original_wait_for_stop_tids;
ThreadIDFunction m_request_thread_stop_function;
ThreadIDFunction m_call_after_function;
ErrorFunction m_error_function;
+ const bool m_request_stop_on_all_unstopped_threads;
};
//===----------------------------------------------------------------------===//
@@ -467,6 +526,18 @@ ThreadStateCoordinator::CallAfterThreadsStop (const lldb::tid_t triggering_tid,
}
void
+ThreadStateCoordinator::CallAfterRunningThreadsStop (const lldb::tid_t triggering_tid,
+ const ThreadIDFunction &request_thread_stop_function,
+ const ThreadIDFunction &call_after_function,
+ const ErrorFunction &error_function)
+{
+ EnqueueEvent (EventBaseSP (new EventCallAfterThreadsStop (triggering_tid,
+ request_thread_stop_function,
+ call_after_function,
+ error_function)));
+}
+
+void
ThreadStateCoordinator::ThreadDidStop (lldb::tid_t tid, ErrorFunction &error_function)
{
// Ensure we know about the thread.
diff --git a/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.h b/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.h
index 3d2ed946163..4e318b53d6e 100644
--- a/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.h
+++ b/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.h
@@ -71,6 +71,16 @@ namespace lldb_private
const ThreadIDFunction &call_after_function,
const ErrorFunction &error_function);
+ // This method is the main purpose of the class: triggering a deferred
+ // action after all non-stopped threads stop. The triggering_tid is the
+ // thread id passed to the call_after_function. The error_function will
+ // be fired if the triggering tid is unknown at the time of execution.
+ void
+ CallAfterRunningThreadsStop (lldb::tid_t triggering_tid,
+ const ThreadIDFunction &request_thread_stop_function,
+ const ThreadIDFunction &call_after_function,
+ const ErrorFunction &error_function);
+
// Notify the thread stopped. Will trigger error at time of execution if we
// already think it is stopped.
void
OpenPOWER on IntegriCloud