Repository: electron/electron (language: cpp)

Issue:
[Bug]: stale process with high cpu usage on windows
### Preflight Checklist

- [X] I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/main/CONTRIBUTING.md) for this project.
- [X] I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/main/CODE_OF_CONDUCT.md) that this project adheres to.
- [X] I have searched the [issue tracker](https://www.github.com/electron/electron/issues) for a bug report that matches the one I want to file, without success.

### Electron Version

18 nightly, 17.0.0, 15.3.4, 13.6.3

### What operating system are you using?

Windows

### Operating System Version

Win 11 21H2

### What arch are you using?

x64

### Last Known Working Electron version

12.1.2

### Expected Behavior

When I quit Electron, all processes (main, renderer, gpu) are terminated.

### Actual Behavior

When the renderer process is busy during application shutdown, it gets stuck in some weird state and doesn't terminate. Even after work is finished, it remains consuming a complete thread of CPU power.

### Testcase Gist URL

https://gist.github.com/3358b37700ca6fb8b7952ff1d72a209b

### Additional Information

In the fiddle the main process terminates while the renderer process is kept busy. This augments the race condition causing a stale renderer process (let's say in 9 of 10 cases). If you change the timeouts so that the renderer has a chance to finish work before it gets shut down, all processes quit as expected.

I tracked down the first affected version to be 13.0.0-beta.21 resp. 14.0.0-nightly.20210426. Both include a Chromium roll which introduced this issue:
- E14 https://github.com/electron/electron/pull/28462
- E13 https://github.com/electron/electron/pull/28660

Halting the process and analyzing the stacktraces, all share the Chromium method `RequestNewLayerTreeFrameSink`. Please find more discussion around that on Slack.

Only Windows seems to be affected, both 32 and 64bit. **This issue does not occur with renderer sandbox enabled.**

Comment from Milan regarding sandbox:
When sandboxed, the renderer processes are enclosed in a win32 job object, which has the `JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE` flag set, this forces them to be killed when the main process is gone. There was an attempt to do this for non-sandboxed renderers as well (without setting any other limitations through the win32 job object), however it got reverted as it caused some regression caught by tests.

Possibly related: #29056.
Unhappy users: https://answers.microsoft.com/en-us/skype/forum/sk_sign-sk_out-sk_win10/high-cpu-usage-after-signing-out-and-then-quitting/8cf5f9d1-00a7-4d4b-991e-96993be2f10b

cc @dsanders11 @zarubond @deepak1556 


Discussion / hints:

Fix patch:
diff --git a/shell/browser/electron_browser_main_parts.cc b/shell/browser/electron_browser_main_parts.cc
index 9a15edbdfddbe..82713b7d15288 100644
--- a/shell/browser/electron_browser_main_parts.cc
+++ b/shell/browser/electron_browser_main_parts.cc
@@ -458,7 +458,8 @@ void ElectronBrowserMainParts::WillRunMainMessageLoop(
     std::unique_ptr<base::RunLoop>& run_loop) {
   js_env_->OnMessageLoopCreated();
   exit_code_ = content::RESULT_CODE_NORMAL_EXIT;
-  Browser::Get()->SetMainMessageLoopQuitClosure(run_loop->QuitClosure());
+  Browser::Get()->SetMainMessageLoopQuitClosure(
+      run_loop->QuitWhenIdleClosure());
 }
 
 void ElectronBrowserMainParts::PostCreateMainMessageLoop() {


Test patch: