[lldb, process] Fix occasional hang when launching a process in LLDB

Summary:
Occasionally, when launching a process in lldb (especially on windows, but not limited to), lldb will hang before the process is launched and it will never recover. This happens because the timing of the processing of the state changes can be slightly different. The state changes that are issued are:

1) SetPublicState(eStateLaunching)
2) SetPrivateState(eStateLaunching)
3) SetPublicState(eStateStopped)
4) SetPrivateState(eStateStopped)

What we expect to see is:
public state: launching -> launching -> stopped
private state: launching -> stopped

What we see is:
public state: launching -> stopped -> launching
private state: launching -> stopped

The second launching change to the public state is issued when WaitForProcessStopPrivate calls HandlePrivateEvent on the event which was created when the private state was set to launching. HandlePrivateEvent has logic to determine whether to broadcase the event and a launching event is *always* broadcast. At the same time, when the stopped event is processed by WaitForProcessStopPrivate next, the function exists and that event is never broadcast, so the public state remains as launching.

HandlePrivateEvent does two things: determine whether there's a next action as well as determine whether to broadcast the event that was processed. There's only ever a next action set if we are trying to attach to a process, but WaitForProcessStopPrivate is only ever called when we are launching a process or connecting remotely, so the first part of HandlePrivateEvent (handling the next action) is irrelevant for WaitForProcessStopPrivate. As far as broadcasting the event is concerned, since we are handling state changes that already occurred to the public state (and are now duplicated in the private state), I believe the broadcast step is unnecessary also (and in fact, it causes the hang).

This change removes the call to HandlePrivateEvent from inside WaitForProcessStopPrivate.

Incidentally, there was also a bug filed recently that is the same issue: https://bugs.llvm.org/show_bug.cgi?id=37496

Reviewers: asmith, labath, zturner, jingham

Reviewed By: zturner, jingham

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D47609

llvm-svn: 333781
This commit is contained in:
Stella Stamenova 2018-06-01 19:14:53 +00:00
parent 78a8494eb5
commit 36d457c20d
3 changed files with 7 additions and 3 deletions

View File

@ -44,6 +44,9 @@ enum StateType {
///launched or attached to anything yet
eStateAttaching, ///< Process is currently trying to attach
eStateLaunching, ///< Process is in the process of launching
// The state changes eStateAttaching and eStateLaunching are both sent while the
// private state thread is either not yet started or paused. For that reason, they
// should only be signaled as public state changes, and not private state changes.
eStateStopped, ///< Process or thread is stopped and can be examined.
eStateRunning, ///< Process or thread is running and can't be examined.
eStateStepping, ///< Process or thread is in the process of stepping and can

View File

@ -249,7 +249,6 @@ Status ProcessWindows::DoLaunch(Module *exe_module,
bool stop_at_entry = launch_info.GetFlags().Test(eLaunchFlagStopAtEntry);
m_session_data.reset(new ProcessWindowsData(stop_at_entry));
SetPrivateState(eStateLaunching);
DebugDelegateSP delegate(new LocalDebugDelegate(shared_from_this()));
m_session_data->m_debugger.reset(new DebuggerThread(delegate));
DebuggerThreadSP debugger = m_session_data->m_debugger;

View File

@ -2688,8 +2688,7 @@ StateType
Process::WaitForProcessStopPrivate(EventSP &event_sp,
const Timeout<std::micro> &timeout) {
StateType state;
// Now wait for the process to launch and return control to us, and then call
// DidLaunch:
while (true) {
event_sp.reset();
state = GetStateChangedEventsPrivate(event_sp, timeout);
@ -2767,6 +2766,9 @@ Status Process::Launch(ProcessLaunchInfo &launch_info) {
}
} else {
EventSP event_sp;
// Now wait for the process to launch and return control to us, and then call
// DidLaunch:
StateType state = WaitForProcessStopPrivate(event_sp, seconds(10));
if (state == eStateInvalid || !event_sp) {