Modify ThreadStateCoodrinator in order to resume threads if stop wasn't requested.

llvm-svn: 227924
This commit is contained in:
Chaoren Lin 2015-02-03 01:51:15 +00:00
parent 97ccc294da
commit 86fd8e45f4
5 changed files with 181 additions and 139 deletions

View File

@ -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;
}

View File

@ -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.

View File

@ -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 ();
}

View File

@ -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;
};

View File

@ -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,