forked from OSchip/llvm-project
Modify ThreadStateCoodrinator in order to resume threads if stop wasn't requested.
llvm-svn: 227924
This commit is contained in:
parent
97ccc294da
commit
86fd8e45f4
|
@ -166,7 +166,7 @@ namespace
|
|||
{
|
||||
Log *const log = GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD);
|
||||
if (log)
|
||||
log->Printf ("NativePlatformLinux::%s %s", __FUNCTION__, error_message.c_str ());
|
||||
log->Printf ("NativeProcessLinux::%s %s", __FUNCTION__, error_message.c_str ());
|
||||
assert (false && "ThreadStateCoordinator error reported");
|
||||
}
|
||||
|
||||
|
@ -1952,7 +1952,7 @@ NativeProcessLinux::MonitorCallback(void *callback_baton,
|
|||
if (exited)
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("NativeProcessLinux::%s() got exit signal, tid = %" PRIu64 " (%s main thread)", __FUNCTION__, pid, is_main_thread ? "is" : "is not");
|
||||
log->Printf ("NativeProcessLinux::%s() got exit signal(%d) , tid = %" PRIu64 " (%s main thread)", __FUNCTION__, signal, pid, is_main_thread ? "is" : "is not");
|
||||
|
||||
// This is a thread that exited. Ensure we're not tracking it anymore.
|
||||
const bool thread_found = process->StopTrackingThread (pid);
|
||||
|
@ -2111,7 +2111,7 @@ NativeProcessLinux::MonitorSIGTRAP(const siginfo_t *info, lldb::pid_t pid)
|
|||
// We can now resume the newly created thread since it is fully created.
|
||||
NotifyThreadCreateStopped (tid);
|
||||
m_coordinator_up->RequestThreadResume (tid,
|
||||
[=](lldb::tid_t tid_to_resume)
|
||||
[=](lldb::tid_t tid_to_resume, bool supress_signal)
|
||||
{
|
||||
reinterpret_cast<NativeThreadLinux*> (new_thread_sp.get ())->SetRunning ();
|
||||
Resume (tid_to_resume, LLDB_INVALID_SIGNAL_NUMBER);
|
||||
|
@ -2133,7 +2133,7 @@ NativeProcessLinux::MonitorSIGTRAP(const siginfo_t *info, lldb::pid_t pid)
|
|||
|
||||
// In all cases, we can resume the main thread here.
|
||||
m_coordinator_up->RequestThreadResume (pid,
|
||||
[=](lldb::tid_t tid_to_resume)
|
||||
[=](lldb::tid_t tid_to_resume, bool supress_signal)
|
||||
{
|
||||
reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetRunning ();
|
||||
Resume (tid_to_resume, LLDB_INVALID_SIGNAL_NUMBER);
|
||||
|
@ -2237,10 +2237,10 @@ NativeProcessLinux::MonitorSIGTRAP(const siginfo_t *info, lldb::pid_t pid)
|
|||
|
||||
const int signo = static_cast<int> (data);
|
||||
m_coordinator_up->RequestThreadResume (pid,
|
||||
[=](lldb::tid_t tid_to_resume)
|
||||
[=](lldb::tid_t tid_to_resume, bool supress_signal)
|
||||
{
|
||||
reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetRunning ();
|
||||
Resume (tid_to_resume, signo);
|
||||
Resume (tid_to_resume, (supress_signal) ? LLDB_INVALID_SIGNAL_NUMBER : signo);
|
||||
},
|
||||
CoordinatorErrorHandler);
|
||||
|
||||
|
@ -2253,6 +2253,11 @@ NativeProcessLinux::MonitorSIGTRAP(const siginfo_t *info, lldb::pid_t pid)
|
|||
if (log)
|
||||
log->Printf ("NativeProcessLinux::%s() received trace event, pid = %" PRIu64 " (single stepping)", __FUNCTION__, pid);
|
||||
|
||||
if (thread_sp)
|
||||
{
|
||||
reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (SIGTRAP);
|
||||
}
|
||||
|
||||
// This thread is currently stopped.
|
||||
NotifyThreadStop (pid);
|
||||
|
||||
|
@ -2260,6 +2265,9 @@ NativeProcessLinux::MonitorSIGTRAP(const siginfo_t *info, lldb::pid_t pid)
|
|||
// This would have already happened at the time the Resume() with step operation was signaled.
|
||||
// At this point, we just need to say we stopped, and the deferred notifcation will fire off
|
||||
// once all running threads have checked in as stopped.
|
||||
SetCurrentThreadID (pid);
|
||||
// Tell the process we have a stop (from software breakpoint).
|
||||
SetState (StateType::eStateStopped, true);
|
||||
break;
|
||||
|
||||
case SI_KERNEL:
|
||||
|
@ -2338,7 +2346,7 @@ NativeProcessLinux::MonitorSIGTRAP(const siginfo_t *info, lldb::pid_t pid)
|
|||
|
||||
// Ignore these signals until we know more about them.
|
||||
m_coordinator_up->RequestThreadResume (pid,
|
||||
[=](lldb::tid_t tid_to_resume)
|
||||
[=](lldb::tid_t tid_to_resume, bool supress_signal)
|
||||
{
|
||||
reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetRunning ();
|
||||
Resume (tid_to_resume, LLDB_INVALID_SIGNAL_NUMBER);
|
||||
|
@ -2418,7 +2426,7 @@ NativeProcessLinux::MonitorSignal(const siginfo_t *info, lldb::pid_t pid, bool e
|
|||
// We can now resume the newly created thread since it is fully created.
|
||||
NotifyThreadCreateStopped (pid);
|
||||
m_coordinator_up->RequestThreadResume (pid,
|
||||
[=](lldb::tid_t tid_to_resume)
|
||||
[=](lldb::tid_t tid_to_resume, bool supress_signal)
|
||||
{
|
||||
reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetRunning ();
|
||||
Resume (tid_to_resume, LLDB_INVALID_SIGNAL_NUMBER);
|
||||
|
@ -2463,8 +2471,9 @@ NativeProcessLinux::MonitorSignal(const siginfo_t *info, lldb::pid_t pid, bool e
|
|||
// An inferior thread just stopped, but was not the primary cause of the process stop.
|
||||
// Instead, something else (like a breakpoint or step) caused the stop. Mark the
|
||||
// stop signal as 0 to let lldb know this isn't the important stop.
|
||||
reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (0);
|
||||
linux_thread_p->SetStoppedBySignal (0);
|
||||
SetCurrentThreadID (thread_sp->GetID ());
|
||||
m_coordinator_up->NotifyThreadStop (thread_sp->GetID (), true, CoordinatorErrorHandler);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2485,10 +2494,9 @@ NativeProcessLinux::MonitorSignal(const siginfo_t *info, lldb::pid_t pid, bool e
|
|||
stop_signo,
|
||||
signal_name);
|
||||
}
|
||||
// Tell the thread state coordinator about the stop.
|
||||
NotifyThreadStop (thread_sp->GetID ());
|
||||
}
|
||||
|
||||
// Tell the thread state coordinator about the stop.
|
||||
NotifyThreadStop (thread_sp->GetID ());
|
||||
}
|
||||
|
||||
// Done handling.
|
||||
|
@ -2498,55 +2506,13 @@ NativeProcessLinux::MonitorSignal(const siginfo_t *info, lldb::pid_t pid, bool e
|
|||
if (log)
|
||||
log->Printf ("NativeProcessLinux::%s() received signal %s", __FUNCTION__, GetUnixSignals ().GetSignalAsCString (signo));
|
||||
|
||||
// This thread is stopped.
|
||||
NotifyThreadStop (pid);
|
||||
|
||||
switch (signo)
|
||||
{
|
||||
case SIGSEGV:
|
||||
case SIGABRT:
|
||||
case SIGILL:
|
||||
case SIGFPE:
|
||||
case SIGBUS:
|
||||
default:
|
||||
{
|
||||
// This thread is stopped.
|
||||
NotifyThreadStop (pid);
|
||||
|
||||
// lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
|
||||
|
||||
// This is just a pre-signal-delivery notification of the incoming signal.
|
||||
if (thread_sp)
|
||||
reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (signo);
|
||||
|
||||
// We can get more details on the exact nature of the crash here.
|
||||
// ProcessMessage::CrashReason reason = GetCrashReasonForSIGSEGV(info);
|
||||
if (!exited)
|
||||
{
|
||||
// Send a stop to the debugger after we get all other threads to stop.
|
||||
CallAfterRunningThreadsStop (pid,
|
||||
[=] (lldb::tid_t signaling_tid)
|
||||
{
|
||||
SetCurrentThreadID (signaling_tid);
|
||||
SetState (StateType::eStateStopped, true);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME the process might die right after this - might not ever get stops on any other threads.
|
||||
// Send a stop to the debugger after we get all other threads to stop.
|
||||
CallAfterRunningThreadsStop (pid,
|
||||
[=] (lldb::tid_t signaling_tid)
|
||||
{
|
||||
SetCurrentThreadID (signaling_tid);
|
||||
SetState (StateType::eStateCrashed, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SIGSTOP:
|
||||
{
|
||||
// This thread is stopped.
|
||||
NotifyThreadStop (pid);
|
||||
|
||||
if (log)
|
||||
{
|
||||
if (is_from_llgs)
|
||||
|
@ -2558,25 +2524,38 @@ NativeProcessLinux::MonitorSignal(const siginfo_t *info, lldb::pid_t pid, bool e
|
|||
// Resume this thread to get the group-stop mechanism to fire off the true group stops.
|
||||
// This thread will get stopped again as part of the group-stop completion.
|
||||
m_coordinator_up->RequestThreadResume (pid,
|
||||
[=](lldb::tid_t tid_to_resume)
|
||||
[=](lldb::tid_t tid_to_resume, bool supress_signal)
|
||||
{
|
||||
reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetRunning ();
|
||||
// Pass this signal number on to the inferior to handle.
|
||||
Resume (tid_to_resume, signo);
|
||||
Resume (tid_to_resume, (supress_signal) ? LLDB_INVALID_SIGNAL_NUMBER : signo);
|
||||
},
|
||||
CoordinatorErrorHandler);
|
||||
|
||||
// And now we want to signal that we received a SIGSTOP on this thread
|
||||
// as soon as all running threads stop (i.e. the group stop sequence completes).
|
||||
CallAfterRunningThreadsStop (pid,
|
||||
[=] (lldb::tid_t signaling_tid)
|
||||
{
|
||||
SetCurrentThreadID (signaling_tid);
|
||||
SetState (StateType::eStateStopped, true);
|
||||
});
|
||||
}
|
||||
break;
|
||||
case SIGSEGV:
|
||||
case SIGILL:
|
||||
case SIGFPE:
|
||||
case SIGBUS:
|
||||
if (thread_sp)
|
||||
reinterpret_cast<NativeThreadLinux*>(thread_sp.get())->SetCrashedWithException(
|
||||
signo, reinterpret_cast<lldb::addr_t>(info->si_addr));
|
||||
break;
|
||||
default:
|
||||
// This is just a pre-signal-delivery notification of the incoming signal.
|
||||
if (thread_sp)
|
||||
reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStoppedBySignal (signo);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Send a stop to the debugger after we get all other threads to stop.
|
||||
CallAfterRunningThreadsStop (pid,
|
||||
[=] (lldb::tid_t signaling_tid)
|
||||
{
|
||||
SetCurrentThreadID (signaling_tid);
|
||||
SetState (StateType::eStateStopped, true);
|
||||
});
|
||||
}
|
||||
|
||||
Error
|
||||
|
@ -2593,6 +2572,7 @@ NativeProcessLinux::Resume (const ResumeActionList &resume_actions)
|
|||
int deferred_signo = 0;
|
||||
NativeThreadProtocolSP deferred_signal_thread_sp;
|
||||
int resume_count = 0;
|
||||
bool stepping = false;
|
||||
|
||||
|
||||
// std::vector<NativeThreadProtocolSP> new_stop_threads;
|
||||
|
@ -2620,11 +2600,11 @@ NativeProcessLinux::Resume (const ResumeActionList &resume_actions)
|
|||
// Run the thread, possibly feeding it the signal.
|
||||
const int signo = action->signal;
|
||||
m_coordinator_up->RequestThreadResumeAsNeeded (thread_sp->GetID (),
|
||||
[=](lldb::tid_t tid_to_resume)
|
||||
[=](lldb::tid_t tid_to_resume, bool supress_signal)
|
||||
{
|
||||
reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetRunning ();
|
||||
// Pass this signal number on to the inferior to handle.
|
||||
Resume (tid_to_resume, (signo > 0) ? signo : LLDB_INVALID_SIGNAL_NUMBER);
|
||||
Resume (tid_to_resume, (signo > 0 && !supress_signal) ? signo : LLDB_INVALID_SIGNAL_NUMBER);
|
||||
},
|
||||
CoordinatorErrorHandler);
|
||||
++resume_count;
|
||||
|
@ -2636,31 +2616,14 @@ NativeProcessLinux::Resume (const ResumeActionList &resume_actions)
|
|||
// Request the step.
|
||||
const int signo = action->signal;
|
||||
m_coordinator_up->RequestThreadResume (thread_sp->GetID (),
|
||||
[=](lldb::tid_t tid_to_step)
|
||||
[=](lldb::tid_t tid_to_step, bool supress_signal)
|
||||
{
|
||||
reinterpret_cast<NativeThreadLinux*> (thread_sp.get ())->SetStepping ();
|
||||
auto step_result = SingleStep (tid_to_step,(signo > 0) ? signo : LLDB_INVALID_SIGNAL_NUMBER);
|
||||
auto step_result = SingleStep (tid_to_step,(signo > 0 && !supress_signal) ? signo : LLDB_INVALID_SIGNAL_NUMBER);
|
||||
assert (step_result && "SingleStep() failed");
|
||||
},
|
||||
CoordinatorErrorHandler);
|
||||
|
||||
// The deferred signal tid is the stepping tid.
|
||||
// This assumes there is only one stepping tid, or the last stepping tid is a fine choice.
|
||||
deferred_signal_tid = thread_sp->GetID ();
|
||||
deferred_signal_thread_sp = thread_sp;
|
||||
|
||||
// Don't send a stop request to this thread. The thread resume request
|
||||
// above will actually run the step thread, and it will finish the step
|
||||
// by sending a SIGTRAP with the appropriate bits set. So, the deferred
|
||||
// signal call that happens at the end of the loop below needs to let
|
||||
// the pending signal handling to *not* send a stop for this thread here
|
||||
// since the start/stop step functionality will end up with a stop state.
|
||||
// Otherwise, this stepping thread will get sent an erroneous tgkill for
|
||||
// with a SIGSTOP signal.
|
||||
deferred_signal_skip_tid = thread_sp->GetID ();
|
||||
|
||||
// And the stop signal we should apply for it is a SIGTRAP.
|
||||
deferred_signo = SIGTRAP;
|
||||
stepping = true;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2684,7 +2647,8 @@ NativeProcessLinux::Resume (const ResumeActionList &resume_actions)
|
|||
|
||||
// If we had any thread stopping, then do a deferred notification of the chosen stop thread id and signal
|
||||
// after all other running threads have stopped.
|
||||
if (deferred_signal_tid != LLDB_INVALID_THREAD_ID)
|
||||
// If there is a stepping thread involved we'll be eventually stopped by SIGTRAP trace signal.
|
||||
if (deferred_signal_tid != LLDB_INVALID_THREAD_ID && !stepping)
|
||||
{
|
||||
CallAfterRunningThreadsStopWithSkipTID (deferred_signal_tid,
|
||||
deferred_signal_skip_tid,
|
||||
|
@ -3894,18 +3858,22 @@ NativeProcessLinux::NotifyThreadDeath (lldb::tid_t tid)
|
|||
void
|
||||
NativeProcessLinux::NotifyThreadStop (lldb::tid_t tid)
|
||||
{
|
||||
m_coordinator_up->NotifyThreadStop (tid, CoordinatorErrorHandler);
|
||||
m_coordinator_up->NotifyThreadStop (tid, false, CoordinatorErrorHandler);
|
||||
}
|
||||
|
||||
void
|
||||
NativeProcessLinux::CallAfterRunningThreadsStop (lldb::tid_t tid,
|
||||
const std::function<void (lldb::tid_t tid)> &call_after_function)
|
||||
{
|
||||
Log *const log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
|
||||
if (log)
|
||||
log->Printf("NativeProcessLinux::%s tid %" PRIu64, __FUNCTION__, tid);
|
||||
|
||||
const lldb::pid_t pid = GetID ();
|
||||
m_coordinator_up->CallAfterRunningThreadsStop (tid,
|
||||
[=](lldb::tid_t request_stop_tid)
|
||||
{
|
||||
tgkill (pid, request_stop_tid, SIGSTOP);
|
||||
RequestThreadStop(pid, request_stop_tid);
|
||||
},
|
||||
call_after_function,
|
||||
CoordinatorErrorHandler);
|
||||
|
@ -3916,13 +3884,36 @@ NativeProcessLinux::CallAfterRunningThreadsStopWithSkipTID (lldb::tid_t deferred
|
|||
lldb::tid_t skip_stop_request_tid,
|
||||
const std::function<void (lldb::tid_t tid)> &call_after_function)
|
||||
{
|
||||
Log *const log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
|
||||
if (log)
|
||||
log->Printf("NativeProcessLinux::%s deferred_signal_tid %" PRIu64 ", skip_stop_request_tid %" PRIu64, __FUNCTION__, deferred_signal_tid, skip_stop_request_tid);
|
||||
|
||||
const lldb::pid_t pid = GetID ();
|
||||
m_coordinator_up->CallAfterRunningThreadsStopWithSkipTIDs (deferred_signal_tid,
|
||||
skip_stop_request_tid != LLDB_INVALID_THREAD_ID ? ThreadStateCoordinator::ThreadIDSet {skip_stop_request_tid} : ThreadStateCoordinator::ThreadIDSet (),
|
||||
[=](lldb::tid_t request_stop_tid)
|
||||
{
|
||||
tgkill (pid, request_stop_tid, SIGSTOP);
|
||||
RequestThreadStop(pid, request_stop_tid);
|
||||
},
|
||||
call_after_function,
|
||||
CoordinatorErrorHandler);
|
||||
}
|
||||
|
||||
lldb_private::Error
|
||||
NativeProcessLinux::RequestThreadStop (const lldb::pid_t pid, const lldb::tid_t tid)
|
||||
{
|
||||
Log* log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
|
||||
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 ());
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -408,6 +408,9 @@ namespace lldb_private
|
|||
|
||||
lldb_private::Error
|
||||
Detach(lldb::tid_t tid);
|
||||
|
||||
lldb_private::Error
|
||||
RequestThreadStop (const lldb::pid_t pid, const lldb::tid_t tid);
|
||||
};
|
||||
} // End lldb_private namespace.
|
||||
|
||||
|
|
|
@ -149,7 +149,7 @@ public:
|
|||
ProcessEvent(ThreadStateCoordinator &coordinator) override
|
||||
{
|
||||
// Validate we know about the deferred trigger thread.
|
||||
if (coordinator.m_tid_stop_map.find (m_triggering_tid) == coordinator.m_tid_stop_map.end ())
|
||||
if (!coordinator.IsKnownThread (m_triggering_tid))
|
||||
{
|
||||
// We don't know about this thread. This is an error condition.
|
||||
std::ostringstream error_message;
|
||||
|
@ -172,7 +172,7 @@ public:
|
|||
|
||||
if (m_wait_for_stop_tids.empty ())
|
||||
{
|
||||
// We're not waiting for any threads. Fire off the deferred signal delivery event.
|
||||
// We're not waiting for any threads. Fire off the deferred signal delivery event.
|
||||
NotifyNow ();
|
||||
}
|
||||
else
|
||||
|
@ -235,7 +235,7 @@ private:
|
|||
}
|
||||
|
||||
bool
|
||||
RequestStopOnAllSpecifiedThreads (const ThreadStateCoordinator &coordinator)
|
||||
RequestStopOnAllSpecifiedThreads (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
|
||||
|
@ -246,8 +246,8 @@ private:
|
|||
{
|
||||
// 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 ())
|
||||
auto find_it = coordinator.m_tid_map.find (tid);
|
||||
if (find_it == coordinator.m_tid_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
|
||||
|
@ -261,9 +261,10 @@ private:
|
|||
}
|
||||
|
||||
// If the pending stop thread is currently running, we need to send it a stop request.
|
||||
if (!find_it->second)
|
||||
if (find_it->second.m_state == ThreadState::Running)
|
||||
{
|
||||
m_request_thread_stop_function (tid);
|
||||
RequestThreadStop (tid, find_it->second);
|
||||
sent_tids.insert (tid);
|
||||
}
|
||||
}
|
||||
|
@ -278,17 +279,17 @@ private:
|
|||
}
|
||||
|
||||
void
|
||||
RequestStopOnAllRunningThreads (const ThreadStateCoordinator &coordinator)
|
||||
RequestStopOnAllRunningThreads (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)
|
||||
for (auto it = coordinator.m_tid_map.begin(); it != coordinator.m_tid_map.end(); ++it)
|
||||
{
|
||||
// We only care about threads not stopped.
|
||||
const bool running = !it->second;
|
||||
const bool running = it->second.m_state == ThreadState::Running;
|
||||
if (running)
|
||||
{
|
||||
const lldb::tid_t tid = it->first;
|
||||
|
@ -296,7 +297,7 @@ private:
|
|||
// Request this thread stop if the tid stop request is not explicitly ignored.
|
||||
const bool skip_stop_request = m_skip_stop_request_tids.count (tid) > 0;
|
||||
if (!skip_stop_request)
|
||||
m_request_thread_stop_function (tid);
|
||||
RequestThreadStop (tid, it->second);
|
||||
|
||||
// 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.
|
||||
|
@ -308,6 +309,13 @@ private:
|
|||
m_wait_for_stop_tids.swap (sent_tids);
|
||||
}
|
||||
|
||||
void
|
||||
RequestThreadStop (lldb::tid_t tid, ThreadContext& context)
|
||||
{
|
||||
m_request_thread_stop_function (tid);
|
||||
context.m_stop_requested = true;
|
||||
}
|
||||
|
||||
const lldb::tid_t m_triggering_tid;
|
||||
ThreadIDSet m_wait_for_stop_tids;
|
||||
const ThreadIDSet m_original_wait_for_stop_tids;
|
||||
|
@ -348,9 +356,11 @@ class ThreadStateCoordinator::EventThreadStopped : public ThreadStateCoordinator
|
|||
{
|
||||
public:
|
||||
EventThreadStopped (lldb::tid_t tid,
|
||||
bool initiated_by_llgs,
|
||||
const ErrorFunction &error_function):
|
||||
EventBase (),
|
||||
m_tid (tid),
|
||||
m_initiated_by_llgs (initiated_by_llgs),
|
||||
m_error_function (error_function)
|
||||
{
|
||||
}
|
||||
|
@ -358,7 +368,7 @@ public:
|
|||
EventLoopResult
|
||||
ProcessEvent(ThreadStateCoordinator &coordinator) override
|
||||
{
|
||||
coordinator.ThreadDidStop (m_tid, m_error_function);
|
||||
coordinator.ThreadDidStop (m_tid, m_initiated_by_llgs, m_error_function);
|
||||
return eventLoopResultContinue;
|
||||
}
|
||||
|
||||
|
@ -373,6 +383,7 @@ public:
|
|||
private:
|
||||
|
||||
const lldb::tid_t m_tid;
|
||||
const bool m_initiated_by_llgs;
|
||||
ErrorFunction m_error_function;
|
||||
};
|
||||
|
||||
|
@ -453,7 +464,7 @@ class ThreadStateCoordinator::EventRequestResume : public ThreadStateCoordinator
|
|||
{
|
||||
public:
|
||||
EventRequestResume (lldb::tid_t tid,
|
||||
const ThreadIDFunction &request_thread_resume_function,
|
||||
const ResumeThreadFunction &request_thread_resume_function,
|
||||
const ErrorFunction &error_function,
|
||||
bool error_when_already_running):
|
||||
EventBase (),
|
||||
|
@ -468,8 +479,8 @@ public:
|
|||
ProcessEvent(ThreadStateCoordinator &coordinator) override
|
||||
{
|
||||
// Ensure we know about the thread.
|
||||
auto find_it = coordinator.m_tid_stop_map.find (m_tid);
|
||||
if (find_it == coordinator.m_tid_stop_map.end ())
|
||||
auto find_it = coordinator.m_tid_map.find (m_tid);
|
||||
if (find_it == coordinator.m_tid_map.end ())
|
||||
{
|
||||
// We don't know about this thread. This is an error condition.
|
||||
std::ostringstream error_message;
|
||||
|
@ -477,9 +488,9 @@ public:
|
|||
m_error_function (error_message.str ());
|
||||
return eventLoopResultContinue;
|
||||
}
|
||||
|
||||
auto& context = find_it->second;
|
||||
// Tell the thread to resume if we don't already think it is running.
|
||||
const bool is_stopped = find_it->second;
|
||||
const bool is_stopped = context.m_state == ThreadState::Stopped;
|
||||
if (!is_stopped)
|
||||
{
|
||||
// It's not an error, just a log, if the m_already_running_no_error flag is set.
|
||||
|
@ -532,10 +543,11 @@ public:
|
|||
|
||||
// Request a resume. We expect this to be synchronous and the system
|
||||
// to reflect it is running after this completes.
|
||||
m_request_thread_resume_function (m_tid);
|
||||
m_request_thread_resume_function (m_tid, false);
|
||||
|
||||
// Now mark it is running.
|
||||
find_it->second = false;
|
||||
context.m_state = ThreadState::Running;
|
||||
context.m_request_resume_function = m_request_thread_resume_function;
|
||||
|
||||
return eventLoopResultContinue;
|
||||
}
|
||||
|
@ -551,7 +563,7 @@ public:
|
|||
private:
|
||||
|
||||
const lldb::tid_t m_tid;
|
||||
ThreadIDFunction m_request_thread_resume_function;
|
||||
ResumeThreadFunction m_request_thread_resume_function;
|
||||
ErrorFunction m_error_function;
|
||||
const bool m_error_when_already_running;
|
||||
};
|
||||
|
@ -563,7 +575,7 @@ ThreadStateCoordinator::ThreadStateCoordinator (const LogFunction &log_function)
|
|||
m_event_queue (),
|
||||
m_queue_condition (),
|
||||
m_queue_mutex (),
|
||||
m_tid_stop_map (),
|
||||
m_tid_map (),
|
||||
m_log_event_processing (false)
|
||||
{
|
||||
}
|
||||
|
@ -660,11 +672,11 @@ ThreadStateCoordinator::CallAfterRunningThreadsStopWithSkipTIDs (lldb::tid_t tri
|
|||
|
||||
|
||||
void
|
||||
ThreadStateCoordinator::ThreadDidStop (lldb::tid_t tid, ErrorFunction &error_function)
|
||||
ThreadStateCoordinator::ThreadDidStop (lldb::tid_t tid, bool initiated_by_llgs, ErrorFunction &error_function)
|
||||
{
|
||||
// Ensure we know about the thread.
|
||||
auto find_it = m_tid_stop_map.find (tid);
|
||||
if (find_it == m_tid_stop_map.end ())
|
||||
auto find_it = m_tid_map.find (tid);
|
||||
if (find_it == m_tid_map.end ())
|
||||
{
|
||||
// We don't know about this thread. This is an error condition.
|
||||
std::ostringstream error_message;
|
||||
|
@ -674,7 +686,10 @@ ThreadStateCoordinator::ThreadDidStop (lldb::tid_t tid, ErrorFunction &error_fun
|
|||
}
|
||||
|
||||
// Update the global list of known thread states. This one is definitely stopped.
|
||||
find_it->second = true;
|
||||
auto& context = find_it->second;
|
||||
const auto stop_was_requested = context.m_stop_requested;
|
||||
context.m_state = ThreadState::Stopped;
|
||||
context.m_stop_requested = false;
|
||||
|
||||
// If we have a pending notification, remove this from the set.
|
||||
EventCallAfterThreadsStop *const call_after_event = GetPendingThreadStopNotification ();
|
||||
|
@ -687,14 +702,23 @@ ThreadStateCoordinator::ThreadDidStop (lldb::tid_t tid, ErrorFunction &error_fun
|
|||
m_pending_notification_sp.reset ();
|
||||
}
|
||||
}
|
||||
|
||||
if (initiated_by_llgs && context.m_request_resume_function && !stop_was_requested)
|
||||
{
|
||||
// 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.
|
||||
Log ("Resuming thread %" PRIu64 " since stop wasn't requested", tid);
|
||||
context.m_request_resume_function (tid, true);
|
||||
context.m_state = ThreadState::Running;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ThreadStateCoordinator::ThreadWasCreated (lldb::tid_t tid, bool is_stopped, ErrorFunction &error_function)
|
||||
{
|
||||
// Ensure we don't already know about the thread.
|
||||
auto find_it = m_tid_stop_map.find (tid);
|
||||
if (find_it != m_tid_stop_map.end ())
|
||||
auto find_it = m_tid_map.find (tid);
|
||||
if (find_it != m_tid_map.end ())
|
||||
{
|
||||
// We already know about this thread. This is an error condition.
|
||||
std::ostringstream error_message;
|
||||
|
@ -704,7 +728,9 @@ ThreadStateCoordinator::ThreadWasCreated (lldb::tid_t tid, bool is_stopped, Erro
|
|||
}
|
||||
|
||||
// Add the new thread to the stop map.
|
||||
m_tid_stop_map[tid] = is_stopped;
|
||||
ThreadContext ctx;
|
||||
ctx.m_state = (is_stopped) ? ThreadState::Stopped : ThreadState::Running;
|
||||
m_tid_map[tid] = std::move(ctx);
|
||||
|
||||
EventCallAfterThreadsStop *const call_after_event = GetPendingThreadStopNotification ();
|
||||
if (call_after_event && !is_stopped)
|
||||
|
@ -719,8 +745,8 @@ void
|
|||
ThreadStateCoordinator::ThreadDidDie (lldb::tid_t tid, ErrorFunction &error_function)
|
||||
{
|
||||
// Ensure we know about the thread.
|
||||
auto find_it = m_tid_stop_map.find (tid);
|
||||
if (find_it == m_tid_stop_map.end ())
|
||||
auto find_it = m_tid_map.find (tid);
|
||||
if (find_it == m_tid_map.end ())
|
||||
{
|
||||
// We don't know about this thread. This is an error condition.
|
||||
std::ostringstream error_message;
|
||||
|
@ -732,7 +758,7 @@ ThreadStateCoordinator::ThreadDidDie (lldb::tid_t tid, ErrorFunction &error_func
|
|||
// 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_stop_map.erase (find_it);
|
||||
m_tid_map.erase (find_it);
|
||||
|
||||
// If we have a pending notification, remove this from the set.
|
||||
EventCallAfterThreadsStop *const call_after_event = GetPendingThreadStopNotification ();
|
||||
|
@ -757,7 +783,7 @@ ThreadStateCoordinator::ResetNow ()
|
|||
// 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_stop_map.clear ();
|
||||
m_tid_map.clear ();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -773,27 +799,26 @@ ThreadStateCoordinator::Log (const char *format, ...)
|
|||
|
||||
void
|
||||
ThreadStateCoordinator::NotifyThreadStop (lldb::tid_t tid,
|
||||
bool initiated_by_llgs,
|
||||
const ErrorFunction &error_function)
|
||||
{
|
||||
EnqueueEvent (EventBaseSP (new EventThreadStopped (tid, error_function)));
|
||||
EnqueueEvent (EventBaseSP (new EventThreadStopped (tid, initiated_by_llgs, error_function)));
|
||||
}
|
||||
|
||||
void
|
||||
ThreadStateCoordinator::RequestThreadResume (lldb::tid_t tid,
|
||||
const ThreadIDFunction &request_thread_resume_function,
|
||||
const ResumeThreadFunction &request_thread_resume_function,
|
||||
const ErrorFunction &error_function)
|
||||
{
|
||||
const bool error_when_already_running = true;
|
||||
EnqueueEvent (EventBaseSP (new EventRequestResume (tid, request_thread_resume_function, error_function, error_when_already_running)));
|
||||
EnqueueEvent (EventBaseSP (new EventRequestResume (tid, request_thread_resume_function, error_function, true)));
|
||||
}
|
||||
|
||||
void
|
||||
ThreadStateCoordinator::RequestThreadResumeAsNeeded (lldb::tid_t tid,
|
||||
const ThreadIDFunction &request_thread_resume_function,
|
||||
const ResumeThreadFunction &request_thread_resume_function,
|
||||
const ErrorFunction &error_function)
|
||||
{
|
||||
const bool error_when_already_running = false;
|
||||
EnqueueEvent (EventBaseSP (new EventRequestResume (tid, request_thread_resume_function, error_function, error_when_already_running)));
|
||||
EnqueueEvent (EventBaseSP (new EventRequestResume (tid, request_thread_resume_function, error_function, false)));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -880,3 +905,9 @@ ThreadStateCoordinator::GetPendingThreadStopNotification ()
|
|||
{
|
||||
return static_cast<EventCallAfterThreadsStop*> (m_pending_notification_sp.get ());
|
||||
}
|
||||
|
||||
bool
|
||||
ThreadStateCoordinator::IsKnownThread (lldb::tid_t tid) const
|
||||
{
|
||||
return m_tid_map.find (tid) != m_tid_map.end ();
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ namespace lldb_private
|
|||
typedef std::function<void (lldb::tid_t tid)> ThreadIDFunction;
|
||||
typedef std::function<void (const char *format, va_list args)> LogFunction;
|
||||
typedef std::function<void (const std::string &error_message)> ErrorFunction;
|
||||
typedef std::function<void (lldb::tid_t tid, bool supress_signal)> ResumeThreadFunction;
|
||||
|
||||
// Constructors.
|
||||
ThreadStateCoordinator (const LogFunction &log_function);
|
||||
|
@ -98,6 +99,7 @@ namespace lldb_private
|
|||
// already think it is stopped.
|
||||
void
|
||||
NotifyThreadStop (lldb::tid_t tid,
|
||||
bool initiated_by_llgs,
|
||||
const ErrorFunction &error_function);
|
||||
|
||||
// Request that the given thread id should have the request_thread_resume_function
|
||||
|
@ -106,7 +108,7 @@ namespace lldb_private
|
|||
// a thread that is already in a running state.
|
||||
void
|
||||
RequestThreadResume (lldb::tid_t tid,
|
||||
const ThreadIDFunction &request_thread_resume_function,
|
||||
const ResumeThreadFunction &request_thread_resume_function,
|
||||
const ErrorFunction &error_function);
|
||||
|
||||
// Request that the given thread id should have the request_thread_resume_function
|
||||
|
@ -115,7 +117,7 @@ namespace lldb_private
|
|||
// does not trigger an error in that case.
|
||||
void
|
||||
RequestThreadResumeAsNeeded (lldb::tid_t tid,
|
||||
const ThreadIDFunction &request_thread_resume_function,
|
||||
const ResumeThreadFunction &request_thread_resume_function,
|
||||
const ErrorFunction &error_function);
|
||||
|
||||
// Indicate the calling process did an exec and that the thread state
|
||||
|
@ -160,7 +162,19 @@ namespace lldb_private
|
|||
|
||||
typedef std::queue<EventBaseSP> QueueType;
|
||||
|
||||
typedef std::unordered_map<lldb::tid_t, bool> TIDBoolMap;
|
||||
enum class ThreadState
|
||||
{
|
||||
Running,
|
||||
Stopped
|
||||
};
|
||||
|
||||
struct ThreadContext
|
||||
{
|
||||
ThreadState m_state;
|
||||
bool m_stop_requested = false;
|
||||
ResumeThreadFunction m_request_resume_function;
|
||||
};
|
||||
typedef std::unordered_map<lldb::tid_t, ThreadContext> TIDContextMap;
|
||||
|
||||
|
||||
// Private member functions.
|
||||
|
@ -174,7 +188,7 @@ namespace lldb_private
|
|||
SetPendingNotification (const EventBaseSP &event_sp);
|
||||
|
||||
void
|
||||
ThreadDidStop (lldb::tid_t tid, ErrorFunction &error_function);
|
||||
ThreadDidStop (lldb::tid_t tid, bool initiated_by_llgs, ErrorFunction &error_function);
|
||||
|
||||
void
|
||||
ThreadWasCreated (lldb::tid_t tid, bool is_stopped, ErrorFunction &error_function);
|
||||
|
@ -185,6 +199,9 @@ namespace lldb_private
|
|||
void
|
||||
ResetNow ();
|
||||
|
||||
bool
|
||||
IsKnownThread(lldb::tid_t tid) const;
|
||||
|
||||
void
|
||||
Log (const char *format, ...);
|
||||
|
||||
|
@ -204,8 +221,8 @@ namespace lldb_private
|
|||
|
||||
EventBaseSP m_pending_notification_sp;
|
||||
|
||||
// Maps known TIDs to stop (true) or not-stopped (false) state.
|
||||
TIDBoolMap m_tid_stop_map;
|
||||
// Maps known TIDs to ThreadContext.
|
||||
TIDContextMap m_tid_map;
|
||||
|
||||
bool m_log_event_processing;
|
||||
};
|
||||
|
|
|
@ -372,7 +372,7 @@ class ConcurrentEventsTestCase(TestBase):
|
|||
"""
|
||||
return self.finish_breakpoint.GetHitCount() > 0 or \
|
||||
self.crash_count > 0 or \
|
||||
self.inferior_process.GetState == lldb.eStateExited
|
||||
self.inferior_process.GetState() == lldb.eStateExited
|
||||
|
||||
def do_thread_actions(self,
|
||||
num_breakpoint_threads = 0,
|
||||
|
|
Loading…
Reference in New Issue