summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/gtest/unittest/Plugins/Process/Linux/ThreadStateCoordinatorTest.cpp66
-rw-r--r--lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp48
-rw-r--r--lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.h3
3 files changed, 116 insertions, 1 deletions
diff --git a/lldb/gtest/unittest/Plugins/Process/Linux/ThreadStateCoordinatorTest.cpp b/lldb/gtest/unittest/Plugins/Process/Linux/ThreadStateCoordinatorTest.cpp
index ddf82cc711a..f9ca339e4fa 100644
--- a/lldb/gtest/unittest/Plugins/Process/Linux/ThreadStateCoordinatorTest.cpp
+++ b/lldb/gtest/unittest/Plugins/Process/Linux/ThreadStateCoordinatorTest.cpp
@@ -14,6 +14,14 @@ namespace
{
// Do nothing.
}
+
+ void
+ StdoutLogger (const char *format, va_list args)
+ {
+ // Print to stdout.
+ vprintf (format, args);
+ printf ("\n");
+ }
}
TEST(ThreadStateCoordinatorTest, StopCoordinatorWorksNoPriorEvents)
@@ -433,3 +441,61 @@ TEST(ThreadStateCoordinatorTest, DeferredNotificationRemovedByResetForExec)
ASSERT_EQ (false, call_after_fired);
}
+
+TEST(ThreadStateCoordinatorTest, RequestThreadResumeCallsCallbackWhenThreadIsStopped)
+{
+ ThreadStateCoordinator coordinator(NOPLogger);
+
+ // Initialize thread to be in stopped state.
+ const lldb::tid_t TEST_TID = 1234;
+
+ coordinator.NotifyThreadStop (TEST_TID);
+ ASSERT_EQ (true, coordinator.ProcessNextEvent ());
+
+ // Request a resume.
+ lldb::tid_t resumed_tid = 0;
+ int resume_call_count = 0;
+
+ coordinator.RequestThreadResume (TEST_TID,
+ [&](lldb::tid_t tid)
+ {
+ ++resume_call_count;
+ resumed_tid = tid;
+ });
+
+ // Shouldn't be called yet.
+ ASSERT_EQ (0, resume_call_count);
+
+ // Process next event. After that, the resume request call should have fired.
+ ASSERT_EQ (true, coordinator.ProcessNextEvent ());
+ ASSERT_EQ (1, resume_call_count);
+ ASSERT_EQ (TEST_TID, resumed_tid);
+}
+
+TEST(ThreadStateCoordinatorTest, RequestThreadResumeIgnoresCallbackWhenThreadIsRunning)
+{
+ ThreadStateCoordinator coordinator(StdoutLogger);
+
+ // This thread will be assumed running (i.e. unknown, assumed running until marked stopped.)
+ const lldb::tid_t TEST_TID = 1234;
+
+ // Request a resume.
+ lldb::tid_t resumed_tid = 0;
+ int resume_call_count = 0;
+
+ coordinator.RequestThreadResume (TEST_TID,
+ [&](lldb::tid_t tid)
+ {
+ ++resume_call_count;
+ resumed_tid = tid;
+ });
+
+ // Shouldn't be called yet.
+ ASSERT_EQ (0, resume_call_count);
+
+ // Process next event.
+ ASSERT_EQ (true, coordinator.ProcessNextEvent ());
+
+ // The resume request should not have gone off because we think it is already running.
+ ASSERT_EQ (0, resume_call_count);
+}
diff --git a/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp b/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp
index b6d1382577d..cd5ad6df3da 100644
--- a/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp
+++ b/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.cpp
@@ -260,6 +260,48 @@ private:
//===----------------------------------------------------------------------===//
+class ThreadStateCoordinator::EventRequestResume : public ThreadStateCoordinator::EventBase
+{
+public:
+ EventRequestResume (lldb::tid_t tid, const ThreadIDFunc &request_thread_resume_func):
+ EventBase (),
+ m_tid (tid),
+ m_request_thread_resume_func (request_thread_resume_func)
+ {
+ }
+
+ bool
+ ProcessEvent(ThreadStateCoordinator &coordinator) override
+ {
+ // Tell the thread to resume if we don't already think it is running.
+ auto find_it = coordinator.m_tid_stop_map.find (m_tid);
+ if (find_it == coordinator.m_tid_stop_map.end ())
+ {
+ // Skip the resume call - we think it is already running because we don't know anything about the thread.
+ coordinator.Log ("EventRequestResume::%s skipping resume request because we don't know about tid %" PRIu64 " and we therefore assume it is running.", __FUNCTION__, m_tid);
+ return true;
+ }
+ else if (!find_it->second)
+ {
+ // Skip the resume call - we have tracked it to be running.
+ coordinator.Log ("EventRequestResume::%s skipping resume request because tid %" PRIu64 " is already running according to our state tracking.", __FUNCTION__, m_tid);
+ return true;
+ }
+
+ // 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;
+ }
+
+private:
+
+ const lldb::tid_t m_tid;
+ ThreadIDFunc m_request_thread_resume_func;
+};
+
+//===----------------------------------------------------------------------===//
+
ThreadStateCoordinator::ThreadStateCoordinator (const LogFunc &log_func) :
m_log_func (log_func),
m_event_queue (),
@@ -415,6 +457,12 @@ ThreadStateCoordinator::NotifyThreadStop (lldb::tid_t tid)
}
void
+ThreadStateCoordinator::RequestThreadResume (lldb::tid_t tid, const ThreadIDFunc &request_thread_resume_func)
+{
+ EnqueueEvent (EventBaseSP (new EventRequestResume (tid, request_thread_resume_func)));
+}
+
+void
ThreadStateCoordinator::NotifyThreadCreate (lldb::tid_t tid)
{
EnqueueEvent (EventBaseSP (new EventThreadCreate (tid)));
diff --git a/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.h b/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.h
index f27dc67099f..f2a5af3bafe 100644
--- a/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.h
+++ b/lldb/source/Plugins/Process/Linux/ThreadStateCoordinator.h
@@ -51,7 +51,7 @@ namespace lldb_private
NotifyThreadStop (lldb::tid_t tid);
void
- NotifyThreadResume (lldb::tid_t tid);
+ RequestThreadResume (lldb::tid_t tid, const ThreadIDFunc &request_thread_resume_func);
void
NotifyThreadCreate (lldb::tid_t tid);
@@ -88,6 +88,7 @@ namespace lldb_private
class EventThreadStopped;
class EventThreadCreate;
class EventThreadDeath;
+ class EventRequestResume;
class EventStopCoordinator;
class EventReset;
OpenPOWER on IntegriCloud