Index: source/Plugins/Process/Linux/NativeProcessLinux.h =================================================================== --- source/Plugins/Process/Linux/NativeProcessLinux.h +++ source/Plugins/Process/Linux/NativeProcessLinux.h @@ -28,6 +28,7 @@ #include "lldb/Target/MemoryRegionInfo.h" #include "lldb/Host/common/NativeProcessProtocol.h" +#include "NativeThreadLinux.h" namespace lldb_private { class Error; @@ -345,7 +346,6 @@ Error SingleStep(lldb::tid_t tid, uint32_t signo); - // ThreadStateCoordinator helper methods. void NotifyThreadDeath (lldb::tid_t tid); @@ -353,25 +353,12 @@ Detach(lldb::tid_t tid); - public: // Typedefs. typedef std::unordered_set ThreadIDSet; - // Callback/block definitions. - typedef std::function ResumeThreadFunction; - - private: - enum class ThreadState - { - Running, - Stopped - }; - - // Notify that a thread is created and/or starting to be - // tracked. The state parameter should reflect whether the thread is created in a running - // or stopped state. + // Notify that a thread is created and/or starting to be tracked. void - NotifyThreadCreate(lldb::tid_t tid, ThreadState state); + NotifyThreadCreate(lldb::tid_t tid); // Notify the delegate after a given set of threads stops. The triggering_tid will be set @@ -403,14 +390,14 @@ // a thread that is already in a running state. Error RequestThreadResume (lldb::tid_t tid, - const ResumeThreadFunction &request_thread_resume_function); + const NativeThreadLinux::ResumeThreadFunction &request_thread_resume_function); // Request that the given thread id should have the request_thread_resume_function // called. This call ignores threads that are already running and // does not trigger an error in that case. Error RequestThreadResumeAsNeeded (lldb::tid_t tid, - const ResumeThreadFunction &request_thread_resume_function); + const NativeThreadLinux::ResumeThreadFunction &request_thread_resume_function); // Indicate the calling process did an exec and that the thread state // should be 100% cleared. @@ -418,19 +405,6 @@ ResetForExec (); private: - - struct ThreadContext - { - ThreadState m_state; - bool m_stop_requested = false; - ResumeThreadFunction m_request_resume_function; - - explicit ThreadContext(ThreadState state) - : m_state(state) - {} - }; - typedef std::unordered_map TIDContextMap; - struct PendingNotification { PendingNotification (lldb::tid_t triggering_tid, @@ -470,35 +444,26 @@ void RequestStopOnAllRunningThreads(); - Error - RequestThreadStop (lldb::tid_t tid, ThreadContext& context); - std::mutex m_event_mutex; // Serializes execution of ProcessEvent. XXX Error ThreadDidStop(lldb::tid_t tid, bool initiated_by_llgs); Error - DoResume(lldb::tid_t tid, ResumeThreadFunction request_thread_resume_function, + DoResume(lldb::tid_t tid, NativeThreadLinux::ResumeThreadFunction request_thread_resume_function, bool error_when_already_running); void DoStopThreads(PendingNotificationUP &¬ification_up); void - ThreadWasCreated (lldb::tid_t tid, ThreadState state); + ThreadWasCreated (lldb::tid_t tid); void ThreadDidDie (lldb::tid_t tid); - bool - IsKnownThread(lldb::tid_t tid) const; - // Member variables. PendingNotificationUP m_pending_notification_up; - - // Maps known TIDs to ThreadContext. - TIDContextMap m_tid_map; }; } // namespace process_linux Index: source/Plugins/Process/Linux/NativeProcessLinux.cpp =================================================================== --- source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -58,7 +58,6 @@ #include #include #include -#include #include #include #include @@ -123,11 +122,6 @@ #define TRAP_HWBKPT 4 #endif -// Try to define a macro to encapsulate the tgkill syscall -// fall back on kill() if tgkill isn't available -#define tgkill(pid, tid, sig) \ - syscall(SYS_tgkill, static_cast<::pid_t>(pid), static_cast<::pid_t>(tid), sig) - // We disable the tracing of ptrace calls for integration builds to // avoid the additional indirection and checks. #ifndef LLDB_CONFIGURATION_BUILDANDINTEGRATION @@ -1652,8 +1646,7 @@ m_arch (), m_supports_mem_region (eLazyBoolCalculate), m_mem_region_cache (), - m_mem_region_cache_mutex (), - m_tid_map () + m_mem_region_cache_mutex () { } @@ -1978,8 +1971,8 @@ thread_sp = AddThread (pid); assert (thread_sp && "AddThread() returned a nullptr thread"); - NotifyThreadCreate (pid, ThreadState::Stopped); std::static_pointer_cast (thread_sp)->SetStoppedBySignal (SIGSTOP); + NotifyThreadCreate(pid); // Let our process instance know the thread has stopped. SetCurrentThreadID (thread_sp->GetID ()); @@ -2074,8 +2067,8 @@ assert (thread_sp && "AddThread() returned a nullptr"); // This will notify this is a new thread and tell the system it is stopped. - NotifyThreadCreate (tid, ThreadState::Stopped); std::static_pointer_cast (thread_sp)->SetStoppedBySignal (SIGSTOP); + NotifyThreadCreate(tid); SetCurrentThreadID (thread_sp->GetID ()); } @@ -2331,7 +2324,7 @@ new_thread_sp = AddThread(tid); std::static_pointer_cast (new_thread_sp)->SetRunning (); Resume (tid, LLDB_INVALID_SIGNAL_NUMBER); - NotifyThreadCreate (tid, ThreadState::Running); + NotifyThreadCreate(tid); } void @@ -2427,7 +2420,7 @@ // Tell coordinator about about the "new" (since exec) stopped main thread. const lldb::tid_t main_thread_tid = GetID (); - NotifyThreadCreate (main_thread_tid, ThreadState::Stopped); + NotifyThreadCreate(main_thread_tid); // NOTE: ideally these next statements would execute at the same time as the coordinator thread create was executed. // Consider a handler that can execute when that happens. @@ -2446,9 +2439,15 @@ case (SIGTRAP | (PTRACE_EVENT_EXIT << 8)): { // The inferior process or one of its threads is about to exit. + if (! thread_sp) + break; // This thread is currently stopped. It's not actually dead yet, just about to be. NotifyThreadStop (pid, false); + // The actual stop reason does not matter much, as we are going to resume the thread a + // few lines down. If we ever want to report this state to the debugger, then we should + // invent a new stop reason. + std::static_pointer_cast(thread_sp)->SetStoppedBySignal(LLDB_INVALID_SIGNAL_NUMBER); unsigned long data = 0; if (GetEventMessage(pid, &data).Fail()) @@ -2686,7 +2685,7 @@ // We can now resume the newly created thread. std::static_pointer_cast (thread_sp)->SetRunning (); Resume (pid, LLDB_INVALID_SIGNAL_NUMBER); - NotifyThreadCreate (pid, ThreadState::Running); + NotifyThreadCreate(pid); // Done handling. return; } @@ -2768,6 +2767,7 @@ { case SIGSTOP: { + std::static_pointer_cast (thread_sp)->SetStoppedBySignal (signo); if (log) { if (is_from_llgs) @@ -4217,17 +4217,17 @@ Error NativeProcessLinux::DoResume( lldb::tid_t tid, - ResumeThreadFunction request_thread_resume_function, + NativeThreadLinux::ResumeThreadFunction request_thread_resume_function, bool error_when_already_running) { Log *const log = GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD); - auto find_it = m_tid_map.find (tid); - lldbassert(find_it != m_tid_map.end ()); // Ensure we know about the thread. + auto thread_sp = std::static_pointer_cast(GetThreadByID(tid)); + lldbassert(thread_sp != nullptr); - auto& context = find_it->second; + auto& context = thread_sp->GetThreadContext(); // Tell the thread to resume if we don't already think it is running. - const bool is_stopped = context.m_state == ThreadState::Stopped; + const bool is_stopped = StateIsStoppedState(thread_sp->GetState(), true); lldbassert(!(error_when_already_running && !is_stopped)); @@ -4271,12 +4271,8 @@ // Request a resume. We expect this to be synchronous and the system // to reflect it is running after this completes. const auto error = request_thread_resume_function (tid, false); - if (error.Success ()) - { - // Now mark it is running. - context.m_state = ThreadState::Running; - context.m_request_resume_function = request_thread_resume_function; - } + if (error.Success()) + context.request_resume_function = request_thread_resume_function; else if (log) { log->Printf("NativeProcessLinux::%s failed to resume thread tid %" PRIu64 ": %s", @@ -4377,14 +4373,13 @@ { // Validate we know about all tids for which we must first receive a stop before // triggering the deferred stop notification. - auto find_it = m_tid_map.find (tid); - lldbassert(find_it != m_tid_map.end()); + auto thread_sp = std::static_pointer_cast(GetThreadByID(tid)); + lldbassert(thread_sp != nullptr); // If the pending stop thread is currently running, we need to send it a stop request. - auto& context = find_it->second; - if (context.m_state == ThreadState::Running) + if (StateIsRunningState(thread_sp->GetState())) { - RequestThreadStop (tid, context); + thread_sp->RequestStop(); sent_tids.insert (tid); } } @@ -4405,66 +4400,40 @@ // threads from which we still need to hear a stop reply. ThreadIDSet sent_tids; - for (auto it = m_tid_map.begin(); it != m_tid_map.end(); ++it) + for (const auto &thread_sp: m_threads) { - // We only care about threads not stopped. - const bool running = it->second.m_state == ThreadState::Running; - if (running) - { - const lldb::tid_t tid = it->first; + // We only care about running threads + if (StateIsStoppedState(thread_sp->GetState(), true)) + continue; - // Request this thread stop if the tid stop request is not explicitly ignored. - const bool skip_stop_request = m_pending_notification_up->skip_stop_request_tids.count (tid) > 0; - if (!skip_stop_request) - RequestThreadStop (tid, it->second); + const lldb::tid_t tid = thread_sp->GetID(); - // Even if we skipped sending the stop request for other reasons (like stepping), - // we still need to wait for that stepping thread to notify completion/stop. - sent_tids.insert (tid); - } + // Request this thread stop if the tid stop request is not explicitly ignored. + const bool skip_stop_request = m_pending_notification_up->skip_stop_request_tids.count (tid) > 0; + if (!skip_stop_request) + static_pointer_cast(thread_sp)->RequestStop(); + + // Even if we skipped sending the stop request for other reasons (like stepping), + // we still need to wait for that stepping thread to notify completion/stop. + sent_tids.insert (tid); } // Set the wait list to the set of tids for which we requested stops. m_pending_notification_up->wait_for_stop_tids.swap (sent_tids); } -Error -NativeProcessLinux::RequestThreadStop (lldb::tid_t tid, ThreadContext& context) -{ - Log* log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); - - lldb::pid_t pid = GetID(); - - if (log) - log->Printf ("NativeProcessLinux::%s requesting thread stop(pid: %" PRIu64 ", tid: %" PRIu64 ")", __FUNCTION__, pid, tid); - - Error err; - errno = 0; - if (::tgkill (pid, tid, SIGSTOP) != 0) - { - err.SetErrorToErrno (); - if (log) - log->Printf ("NativeProcessLinux::%s tgkill(%" PRIu64 ", %" PRIu64 ", SIGSTOP) failed: %s", __FUNCTION__, pid, tid, err.AsCString ()); - } - else - context.m_stop_requested = true; - - return err; -} - Error NativeProcessLinux::ThreadDidStop (lldb::tid_t tid, bool initiated_by_llgs) { // Ensure we know about the thread. - auto find_it = m_tid_map.find (tid); - lldbassert(find_it != m_tid_map.end()); + auto thread_sp = std::static_pointer_cast(GetThreadByID(tid)); + lldbassert(thread_sp != nullptr); // Update the global list of known thread states. This one is definitely stopped. - auto& context = find_it->second; - const auto stop_was_requested = context.m_stop_requested; - context.m_state = ThreadState::Stopped; - context.m_stop_requested = false; + auto& context = thread_sp->GetThreadContext(); + const auto stop_was_requested = context.stop_requested; + context.stop_requested = false; // If we have a pending notification, remove this from the set. if (m_pending_notification_up) @@ -4473,37 +4442,27 @@ SignalIfRequirementsSatisfied(); } - if (initiated_by_llgs && context.m_request_resume_function && !stop_was_requested) + Error error; + if (initiated_by_llgs && context.request_resume_function && !stop_was_requested) { Log *const log = GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD); // We can end up here if stop was initiated by LLGS but by this time a // thread stop has occurred - maybe initiated by another event. if (log) log->Printf("Resuming thread %" PRIu64 " since stop wasn't requested", tid); - const auto error = context.m_request_resume_function (tid, true); - if (error.Success ()) - { - context.m_state = ThreadState::Running; - } - else + error = context.request_resume_function (tid, true); + if (error.Fail() && log) { - if (log) - { log->Printf("NativeProcessLinux::%s failed to resume thread tid %" PRIu64 ": %s", __FUNCTION__, tid, error.AsCString ()); - } - return error; } } - return Error(); + return error; } void NativeProcessLinux::DoStopThreads(PendingNotificationUP &¬ification_up) { - // Validate we know about the deferred trigger thread. - lldbassert(IsKnownThread (notification_up->triggering_tid)); - Log *const log = GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD); if (m_pending_notification_up && log) { @@ -4528,35 +4487,23 @@ } void -NativeProcessLinux::ThreadWasCreated (lldb::tid_t tid, ThreadState state) +NativeProcessLinux::ThreadWasCreated (lldb::tid_t tid) { - // Ensure we don't already know about the thread. - lldbassert(m_tid_map.find(tid) == m_tid_map.end()); + auto thread_sp = std::static_pointer_cast(GetThreadByID(tid)); + lldbassert(thread_sp != nullptr); - // Add the new thread to the stop map. - auto tid_it = m_tid_map.emplace(tid, ThreadContext(state)).first; - - if (m_pending_notification_up && state == ThreadState::Running) + if (m_pending_notification_up && StateIsRunningState(thread_sp->GetState())) { // We will need to wait for this new thread to stop as well before firing the // notification. m_pending_notification_up->wait_for_stop_tids.insert(tid); - RequestThreadStop(tid, tid_it->second); + thread_sp->RequestStop(); } } void NativeProcessLinux::ThreadDidDie (lldb::tid_t tid) { - // Ensure we know about the thread. - auto find_it = m_tid_map.find (tid); - lldbassert(find_it != m_tid_map.end()); - - // 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_map.erase (find_it); - // If we have a pending notification, remove this from the set. if (m_pending_notification_up) { @@ -4589,7 +4536,7 @@ Error NativeProcessLinux::RequestThreadResume (lldb::tid_t tid, - const ResumeThreadFunction &request_thread_resume_function) + const NativeThreadLinux::ResumeThreadFunction &request_thread_resume_function) { Log *const log = GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD); std::lock_guard lock(m_event_mutex); @@ -4612,7 +4559,7 @@ Error NativeProcessLinux::RequestThreadResumeAsNeeded (lldb::tid_t tid, - const ResumeThreadFunction &request_thread_resume_function) + const NativeThreadLinux::ResumeThreadFunction &request_thread_resume_function) { Log *const log = GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD); std::lock_guard lock(m_event_mutex); @@ -4634,18 +4581,15 @@ } void -NativeProcessLinux::NotifyThreadCreate (lldb::tid_t tid, ThreadState state) +NativeProcessLinux::NotifyThreadCreate(lldb::tid_t tid) { Log *const log = GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD); std::lock_guard lock(m_event_mutex); if (log) - { - log->Printf("NativeProcessLinux::%s about to process event: (tid: %" PRIu64 ", is %sstopped)", - __FUNCTION__, tid, state==ThreadState::Stopped?"":"not "); - } + log->Printf("NativeProcessLinux::%s about to process event: (tid: %" PRIu64 ")", __FUNCTION__, tid); - ThreadWasCreated (tid, state); + ThreadWasCreated(tid); if (log) { @@ -4686,20 +4630,8 @@ // Clear the pending notification if there was one. m_pending_notification_up.reset (); - // Clear the stop map - we no longer know anything about any thread state. - // The caller is expected to reset thread states for all threads, and we - // will assume anything we haven't heard about is running and requires a - // stop. - m_tid_map.clear (); - if (log) { log->Printf("NativeProcessLinux::%s event processing done", __FUNCTION__); } } - -bool -NativeProcessLinux::IsKnownThread (lldb::tid_t tid) const -{ - return m_tid_map.find (tid) != m_tid_map.end (); -} Index: source/Plugins/Process/Linux/NativeThreadLinux.h =================================================================== --- source/Plugins/Process/Linux/NativeThreadLinux.h +++ source/Plugins/Process/Linux/NativeThreadLinux.h @@ -95,6 +95,19 @@ void SetExited (); + Error + RequestStop (); + + typedef std::function ResumeThreadFunction; + struct ThreadContext + { + bool stop_requested = false; + ResumeThreadFunction request_resume_function; + }; + + ThreadContext & + GetThreadContext() { return m_thread_context; } + // --------------------------------------------------------------------- // Private interface // --------------------------------------------------------------------- @@ -110,6 +123,7 @@ std::string m_stop_description; using WatchpointIndexMap = std::map; WatchpointIndexMap m_watchpoint_index_map; + ThreadContext m_thread_context; }; } // namespace process_linux Index: source/Plugins/Process/Linux/NativeThreadLinux.cpp =================================================================== --- source/Plugins/Process/Linux/NativeThreadLinux.cpp +++ source/Plugins/Process/Linux/NativeThreadLinux.cpp @@ -37,6 +37,11 @@ #include "Plugins/Process/Utility/RegisterContextLinux_mips64.h" #include "Plugins/Process/Utility/RegisterInfoInterface.h" +#include +// Try to define a macro to encapsulate the tgkill syscall +#define tgkill(pid, tid, sig) \ + syscall(SYS_tgkill, static_cast<::pid_t>(pid), static_cast<::pid_t>(tid), sig) + using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_linux; @@ -479,6 +484,35 @@ m_stop_info.reason = StopReason::eStopReasonThreadExiting; } +Error +NativeThreadLinux::RequestStop () +{ + Log* log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); + + const auto process_sp = GetProcess(); + if (! process_sp) + return Error("Process is null."); + + lldb::pid_t pid = process_sp->GetID(); + lldb::tid_t tid = GetID(); + + if (log) + log->Printf ("NativeThreadLinux::%s requesting thread stop(pid: %" PRIu64 ", tid: %" PRIu64 ")", __FUNCTION__, pid, tid); + + Error err; + errno = 0; + if (::tgkill (pid, tid, SIGSTOP) != 0) + { + err.SetErrorToErrno (); + if (log) + log->Printf ("NativeThreadLinux::%s tgkill(%" PRIu64 ", %" PRIu64 ", SIGSTOP) failed: %s", __FUNCTION__, pid, tid, err.AsCString ()); + } + else + m_thread_context.stop_requested = true; + + return err; +} + void NativeThreadLinux::MaybeLogStateChange (lldb::StateType new_state) {