[LLDB][ProcessWindows] Set exit status on instance rather than going through all targets#159308
[LLDB][ProcessWindows] Set exit status on instance rather than going through all targets#159308
Conversation
…through all targets
|
@llvm/pr-subscribers-lldb Author: nerix (Nerixyz) ChangesWhen quitting LLDB on Windows while a process was still running, LLDB would take unusually long to exit. This was due to a temporary deadlock: The main thread was destroying the processes. In doing so, it iterated over the target list: llvm-project/lldb/source/Core/Debugger.cpp Lines 1095 to 1098 in 88c64f7 This locks the list for the whole iteration. Finalizing the process would eventually lead to The debugger loop (on a separate thread) would see that the process exited and call ProcessWindows::OnExitProcess. This calls the static function Process::SetProcessExitStatus. This tries to find the process by its ID from the debugger's target list. Doing so requires locking the list, so the debugger thread would then be stuck onAfter 5s, the main thread would give up waiting. So every exit where the process was still running would be delayed by about 5s. Since This can also make some tests run faster. For example, the DIA PDB tests previously took 15s to run on my PC (24 jobs) and now take 5s. For all shell tests, the difference isn't that big (only about 3s), because most don't run into this and the tests run in parallel. Full diff: https://github.com/llvm/llvm-project/pull/159308.diff 1 Files Affected:
diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
index 27530f032ce51..0fecefe23b88e 100644
--- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
+++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp
@@ -666,7 +666,7 @@ void ProcessWindows::OnExitProcess(uint32_t exit_code) {
target->ModulesDidUnload(unloaded_modules, true);
}
- SetProcessExitStatus(GetID(), true, 0, exit_code);
+ SetExitStatus(exit_code, /*exit_string=*/"");
SetPrivateState(eStateExited);
ProcessDebugger::OnExitProcess(exit_code);
|
DavidSpickett
left a comment
There was a problem hiding this comment.
Great find! I had noticed that lldb was slow to quit but I always thought it would be something inherent to how things work on Windows.
|
Nice, thanks! I've also observed this from time to time, but haven't had time to dig into it! |
|
Do you think it'd make sense to backport this fix to 21.x? |
That could make sense, and I'm fine with doing this, though, the bug was already in 20.x. Maybe @DavidSpickett has some thoughts on this? |
|
It always "worked", just slowly. So it's like backporting a code generation improvement, which we have been known to do. Worth a try. I would support it on the basis that the patch is very simple and we haven't seen any regressions. |
|
/cherry-pick a868f28 |
|
/pull-request #161541 |
|
Yeah - it doesn't need to be a regression in 21.x for the fix to be backported, any reasonable bug fix can be eligible IMO. |
…through all targets (#159308) When quitting LLDB on Windows while a process was still running, LLDB would take unusually long to exit. This was due to a temporary deadlock: The main thread was destroying the processes. In doing so, it iterated over the target list: https://github.com/llvm/llvm-project/blob/88c64f76ed2ca226da99b99f60d316b1519fc7d8/lldb/source/Core/Debugger.cpp#L1095-L1098 This locks the list for the whole iteration. Finalizing the process would eventually lead to `DebuggerThread::StopDebugging`, which terminates the process and waits for it to exit: https://github.com/llvm/llvm-project/blob/88c64f76ed2ca226da99b99f60d316b1519fc7d8/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp#L196 The debugger loop (on a separate thread) would see that the process exited and call [`ProcessWindows::OnExitProcess`](https://github.com/llvm/llvm-project/blob/88c64f76ed2ca226da99b99f60d316b1519fc7d8/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp#L656-L673). This calls the static function [`Process::SetProcessExitStatus`](https://github.com/llvm/llvm-project/blob/0a7a7d56fc882653335beba0d1f8ea9f26089c22/lldb/source/Target/Process.cpp#L1098-L1126). This tries to find the process by its ID from the debugger's target list. Doing so requires locking the list, so the debugger thread would then be stuck on https://github.com/llvm/llvm-project/blob/0a7a7d56fc882653335beba0d1f8ea9f26089c22/lldb/source/Target/TargetList.cpp#L403 After 5s, the main thread would give up waiting. So every exit where the process was still running would be delayed by about 5s. Since `ProcessWindows` would find itself when calling `SetProcessExitStatus`, we can call `SetExitStatus` directly. This can also make some tests run faster. For example, the DIA PDB tests previously took 15s to run on my PC (24 jobs) and now take 5s. For all shell tests, the difference isn't that big (only about 3s), because most don't run into this and the tests run in parallel. (cherry picked from commit a868f28)
I noticed that LLDB takes longer to stop than it should. Running a tiny
program like `int main() { return 0; }` in LLDB with `lldb test.exe -o r
-o q` takes about five seconds.
This is caused by the `WaitForMultipleObjects` in
[`ConnectionGenericFile::Read`](https://github.com/llvm/llvm-project/blob/25976e83606f1a7615e3725e6038bb53ee96c3d5/lldb/source/Host/windows/ConnectionGenericFileWindows.cpp#L191-L192)
timing out (it has a timeout of 5s).
It times out, because we never close the PTY created in
[`ProcessLaunchInfo::SetUpPtyRedirection`](https://github.com/llvm/llvm-project/blob/25976e83606f1a7615e3725e6038bb53ee96c3d5/lldb/source/Host/common/ProcessLaunchInfo.cpp#L213).
When we call `target->GetProcessLaunchInfo().GetPTY().Close()` in
`ProcessWindows::OnExitProcess`, we don't access the PTY we created when
setting up the redirection - we're closing a default constructed one.
This is because the target's `m_launch_info` isn't necessarily the
`launch_info` we get in
[`Target::FinalizeFileActions`](https://github.com/llvm/llvm-project/blob/4a8a0593bdecee49331cb5c31a6c9b18d87ea41c/lldb/source/Target/Target.cpp#L3850)
when calling `SetUpPtyRedirection`.
With this PR, we store the PTY that a process was launched with inside
`ProcessWindows`, so we can later close it.
The wait of five seconds and a timed out `WaitForMultipleObjects` sounds
similar to #159308, but it's a
different call to `WaitForMultipleObjects` here. Still, I wonder if we
could do something to detect this earlier. Maybe some warning message or
debug-only assert if these waits time out?
I noticed that LLDB takes longer to stop than it should. Running a tiny
program like `int main() { return 0; }` in LLDB with `lldb test.exe -o r
-o q` takes about five seconds.
This is caused by the `WaitForMultipleObjects` in
[`ConnectionGenericFile::Read`](https://github.com/llvm/llvm-project/blob/25976e83606f1a7615e3725e6038bb53ee96c3d5/lldb/source/Host/windows/ConnectionGenericFileWindows.cpp#L191-L192)
timing out (it has a timeout of 5s).
It times out, because we never close the PTY created in
[`ProcessLaunchInfo::SetUpPtyRedirection`](https://github.com/llvm/llvm-project/blob/25976e83606f1a7615e3725e6038bb53ee96c3d5/lldb/source/Host/common/ProcessLaunchInfo.cpp#L213).
When we call `target->GetProcessLaunchInfo().GetPTY().Close()` in
`ProcessWindows::OnExitProcess`, we don't access the PTY we created when
setting up the redirection - we're closing a default constructed one.
This is because the target's `m_launch_info` isn't necessarily the
`launch_info` we get in
[`Target::FinalizeFileActions`](https://github.com/llvm/llvm-project/blob/4a8a0593bdecee49331cb5c31a6c9b18d87ea41c/lldb/source/Target/Target.cpp#L3850)
when calling `SetUpPtyRedirection`.
With this PR, we store the PTY that a process was launched with inside
`ProcessWindows`, so we can later close it.
The wait of five seconds and a timed out `WaitForMultipleObjects` sounds
similar to llvm/llvm-project#159308, but it's a
different call to `WaitForMultipleObjects` here. Still, I wonder if we
could do something to detect this earlier. Maybe some warning message or
debug-only assert if these waits time out?
I noticed that LLDB takes longer to stop than it should. Running a tiny
program like `int main() { return 0; }` in LLDB with `lldb test.exe -o r
-o q` takes about five seconds.
This is caused by the `WaitForMultipleObjects` in
[`ConnectionGenericFile::Read`](https://github.com/llvm/llvm-project/blob/25976e83606f1a7615e3725e6038bb53ee96c3d5/lldb/source/Host/windows/ConnectionGenericFileWindows.cpp#L191-L192)
timing out (it has a timeout of 5s).
It times out, because we never close the PTY created in
[`ProcessLaunchInfo::SetUpPtyRedirection`](https://github.com/llvm/llvm-project/blob/25976e83606f1a7615e3725e6038bb53ee96c3d5/lldb/source/Host/common/ProcessLaunchInfo.cpp#L213).
When we call `target->GetProcessLaunchInfo().GetPTY().Close()` in
`ProcessWindows::OnExitProcess`, we don't access the PTY we created when
setting up the redirection - we're closing a default constructed one.
This is because the target's `m_launch_info` isn't necessarily the
`launch_info` we get in
[`Target::FinalizeFileActions`](https://github.com/llvm/llvm-project/blob/4a8a0593bdecee49331cb5c31a6c9b18d87ea41c/lldb/source/Target/Target.cpp#L3850)
when calling `SetUpPtyRedirection`.
With this PR, we store the PTY that a process was launched with inside
`ProcessWindows`, so we can later close it.
The wait of five seconds and a timed out `WaitForMultipleObjects` sounds
similar to llvm#159308, but it's a
different call to `WaitForMultipleObjects` here. Still, I wonder if we
could do something to detect this earlier. Maybe some warning message or
debug-only assert if these waits time out?
I noticed that LLDB takes longer to stop than it should. Running a tiny
program like `int main() { return 0; }` in LLDB with `lldb test.exe -o r
-o q` takes about five seconds.
This is caused by the `WaitForMultipleObjects` in
[`ConnectionGenericFile::Read`](https://github.com/llvm/llvm-project/blob/25976e83606f1a7615e3725e6038bb53ee96c3d5/lldb/source/Host/windows/ConnectionGenericFileWindows.cpp#L191-L192)
timing out (it has a timeout of 5s).
It times out, because we never close the PTY created in
[`ProcessLaunchInfo::SetUpPtyRedirection`](https://github.com/llvm/llvm-project/blob/25976e83606f1a7615e3725e6038bb53ee96c3d5/lldb/source/Host/common/ProcessLaunchInfo.cpp#L213).
When we call `target->GetProcessLaunchInfo().GetPTY().Close()` in
`ProcessWindows::OnExitProcess`, we don't access the PTY we created when
setting up the redirection - we're closing a default constructed one.
This is because the target's `m_launch_info` isn't necessarily the
`launch_info` we get in
[`Target::FinalizeFileActions`](https://github.com/llvm/llvm-project/blob/4a8a0593bdecee49331cb5c31a6c9b18d87ea41c/lldb/source/Target/Target.cpp#L3850)
when calling `SetUpPtyRedirection`.
With this PR, we store the PTY that a process was launched with inside
`ProcessWindows`, so we can later close it.
The wait of five seconds and a timed out `WaitForMultipleObjects` sounds
similar to llvm#159308, but it's a
different call to `WaitForMultipleObjects` here. Still, I wonder if we
could do something to detect this earlier. Maybe some warning message or
debug-only assert if these waits time out?
I noticed that LLDB takes longer to stop than it should. Running a tiny
program like `int main() { return 0; }` in LLDB with `lldb test.exe -o r
-o q` takes about five seconds.
This is caused by the `WaitForMultipleObjects` in
[`ConnectionGenericFile::Read`](https://github.com/llvm/llvm-project/blob/25976e83606f1a7615e3725e6038bb53ee96c3d5/lldb/source/Host/windows/ConnectionGenericFileWindows.cpp#L191-L192)
timing out (it has a timeout of 5s).
It times out, because we never close the PTY created in
[`ProcessLaunchInfo::SetUpPtyRedirection`](https://github.com/llvm/llvm-project/blob/25976e83606f1a7615e3725e6038bb53ee96c3d5/lldb/source/Host/common/ProcessLaunchInfo.cpp#L213).
When we call `target->GetProcessLaunchInfo().GetPTY().Close()` in
`ProcessWindows::OnExitProcess`, we don't access the PTY we created when
setting up the redirection - we're closing a default constructed one.
This is because the target's `m_launch_info` isn't necessarily the
`launch_info` we get in
[`Target::FinalizeFileActions`](https://github.com/llvm/llvm-project/blob/4a8a0593bdecee49331cb5c31a6c9b18d87ea41c/lldb/source/Target/Target.cpp#L3850)
when calling `SetUpPtyRedirection`.
With this PR, we store the PTY that a process was launched with inside
`ProcessWindows`, so we can later close it.
The wait of five seconds and a timed out `WaitForMultipleObjects` sounds
similar to llvm#159308, but it's a
different call to `WaitForMultipleObjects` here. Still, I wonder if we
could do something to detect this earlier. Maybe some warning message or
debug-only assert if these waits time out?
(cherry picked from commit 783fbdc)
I noticed that LLDB takes longer to stop than it should. Running a tiny
program like `int main() { return 0; }` in LLDB with `lldb test.exe -o r
-o q` takes about five seconds.
This is caused by the `WaitForMultipleObjects` in
[`ConnectionGenericFile::Read`](https://github.com/llvm/llvm-project/blob/25976e83606f1a7615e3725e6038bb53ee96c3d5/lldb/source/Host/windows/ConnectionGenericFileWindows.cpp#L191-L192)
timing out (it has a timeout of 5s).
It times out, because we never close the PTY created in
[`ProcessLaunchInfo::SetUpPtyRedirection`](https://github.com/llvm/llvm-project/blob/25976e83606f1a7615e3725e6038bb53ee96c3d5/lldb/source/Host/common/ProcessLaunchInfo.cpp#L213).
When we call `target->GetProcessLaunchInfo().GetPTY().Close()` in
`ProcessWindows::OnExitProcess`, we don't access the PTY we created when
setting up the redirection - we're closing a default constructed one.
This is because the target's `m_launch_info` isn't necessarily the
`launch_info` we get in
[`Target::FinalizeFileActions`](https://github.com/llvm/llvm-project/blob/4a8a0593bdecee49331cb5c31a6c9b18d87ea41c/lldb/source/Target/Target.cpp#L3850)
when calling `SetUpPtyRedirection`.
With this PR, we store the PTY that a process was launched with inside
`ProcessWindows`, so we can later close it.
The wait of five seconds and a timed out `WaitForMultipleObjects` sounds
similar to llvm/llvm-project#159308, but it's a
different call to `WaitForMultipleObjects` here. Still, I wonder if we
could do something to detect this earlier. Maybe some warning message or
debug-only assert if these waits time out?
(cherry picked from commit 783fbdc)
I noticed that LLDB takes longer to stop than it should. Running a tiny
program like `int main() { return 0; }` in LLDB with `lldb test.exe -o r
-o q` takes about five seconds.
This is caused by the `WaitForMultipleObjects` in
[`ConnectionGenericFile::Read`](https://github.com/llvm/llvm-project/blob/25976e83606f1a7615e3725e6038bb53ee96c3d5/lldb/source/Host/windows/ConnectionGenericFileWindows.cpp#L191-L192)
timing out (it has a timeout of 5s).
It times out, because we never close the PTY created in
[`ProcessLaunchInfo::SetUpPtyRedirection`](https://github.com/llvm/llvm-project/blob/25976e83606f1a7615e3725e6038bb53ee96c3d5/lldb/source/Host/common/ProcessLaunchInfo.cpp#L213).
When we call `target->GetProcessLaunchInfo().GetPTY().Close()` in
`ProcessWindows::OnExitProcess`, we don't access the PTY we created when
setting up the redirection - we're closing a default constructed one.
This is because the target's `m_launch_info` isn't necessarily the
`launch_info` we get in
[`Target::FinalizeFileActions`](https://github.com/llvm/llvm-project/blob/4a8a0593bdecee49331cb5c31a6c9b18d87ea41c/lldb/source/Target/Target.cpp#L3850)
when calling `SetUpPtyRedirection`.
With this PR, we store the PTY that a process was launched with inside
`ProcessWindows`, so we can later close it.
The wait of five seconds and a timed out `WaitForMultipleObjects` sounds
similar to llvm#159308, but it's a
different call to `WaitForMultipleObjects` here. Still, I wonder if we
could do something to detect this earlier. Maybe some warning message or
debug-only assert if these waits time out?
I noticed that LLDB takes longer to stop than it should. Running a tiny
program like `int main() { return 0; }` in LLDB with `lldb test.exe -o r
-o q` takes about five seconds.
This is caused by the `WaitForMultipleObjects` in
[`ConnectionGenericFile::Read`](https://github.com/llvm/llvm-project/blob/25976e83606f1a7615e3725e6038bb53ee96c3d5/lldb/source/Host/windows/ConnectionGenericFileWindows.cpp#L191-L192)
timing out (it has a timeout of 5s).
It times out, because we never close the PTY created in
[`ProcessLaunchInfo::SetUpPtyRedirection`](https://github.com/llvm/llvm-project/blob/25976e83606f1a7615e3725e6038bb53ee96c3d5/lldb/source/Host/common/ProcessLaunchInfo.cpp#L213).
When we call `target->GetProcessLaunchInfo().GetPTY().Close()` in
`ProcessWindows::OnExitProcess`, we don't access the PTY we created when
setting up the redirection - we're closing a default constructed one.
This is because the target's `m_launch_info` isn't necessarily the
`launch_info` we get in
[`Target::FinalizeFileActions`](https://github.com/llvm/llvm-project/blob/4a8a0593bdecee49331cb5c31a6c9b18d87ea41c/lldb/source/Target/Target.cpp#L3850)
when calling `SetUpPtyRedirection`.
With this PR, we store the PTY that a process was launched with inside
`ProcessWindows`, so we can later close it.
The wait of five seconds and a timed out `WaitForMultipleObjects` sounds
similar to llvm/llvm-project#159308, but it's a
different call to `WaitForMultipleObjects` here. Still, I wonder if we
could do something to detect this earlier. Maybe some warning message or
debug-only assert if these waits time out?
(cherry picked from commit 783fbdc54eff8e39457e7116628df8774726ec80)
(cherry picked from commit 915ef143416a49e446bf4d22f486d406c42ca7a0)
When quitting LLDB on Windows while a process was still running, LLDB would take unusually long to exit. This was due to a temporary deadlock:
The main thread was destroying the processes. In doing so, it iterated over the target list:
llvm-project/lldb/source/Core/Debugger.cpp
Lines 1095 to 1098 in 88c64f7
This locks the list for the whole iteration. Finalizing the process would eventually lead to
DebuggerThread::StopDebugging, which terminates the process and waits for it to exit:llvm-project/lldb/source/Plugins/Process/Windows/Common/DebuggerThread.cpp
Line 196 in 88c64f7
The debugger loop (on a separate thread) would see that the process exited and call
ProcessWindows::OnExitProcess. This calls the static functionProcess::SetProcessExitStatus. This tries to find the process by its ID from the debugger's target list. Doing so requires locking the list, so the debugger thread would then be stuck onllvm-project/lldb/source/Target/TargetList.cpp
Line 403 in 0a7a7d5
After 5s, the main thread would give up waiting. So every exit where the process was still running would be delayed by about 5s.
Since
ProcessWindowswould find itself when callingSetProcessExitStatus, we can callSetExitStatusdirectly.This can also make some tests run faster. For example, the DIA PDB tests previously took 15s to run on my PC (24 jobs) and now take 5s. For all shell tests, the difference isn't that big (only about 3s), because most don't run into this and the tests run in parallel.