diff options
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; |