darwin: Use posix_spawn to spawn subprocesses in macOS - #3064
Conversation
|
I verified that spawn times are just as fast with & without JIT using the repro project (https://github.com/deepak1556/libuv-spawn)! Results taken using a codesigned build, 2016 MacBook Pro, macOS 11.0.1 posix_spawnWithout MAP_JITWith MAP_JITforkCompare the results above against the head of the Without MAP_JITWith MAP_JIT |
|
Switched to a proper PR. Updated the description to include all the information I have about the successful/failed builds and their respective command lines emited by the build systems. |
|
Ok, with the help of @marcello3d the build is now back up, and so I could run the unit tests and fix all but one. I've rewritten the PR description to reflect the current state of affairs. |
bnoordhuis
left a comment
There was a problem hiding this comment.
I did a very light review, mostly on style issues.
I feel the big #ifdef __APPLE__ block in the middle of an already large function is not so nice, it makes things hard to follow.
It should probably be broken out into a separate function, possibly in a different file like src/unix/darwin.c.
|
Moved the process spawn and initialization logic to a separate function which in turn delegates to a purpose specific one (posix_spawn or fork+exec). Also, corrected all formatting and convenction issues. |
|
|
|
Thanks @bnoordhuis for the review! I've addressed all comments. |
Spawning child processes in an Electron application with a hardened runtime has become slow in macOS Big Sur. This patch is a squashed version of libuv/libuv#3064, with the addition of API availability annotations to fix a build warning (since Electron compiles with the `-Wunguarded-availability-new` flag). This patch should be removed when libuv PR 3064 is merged. Fixes: libuv/libuv#3050 Fixes: electron#26143 PR-URL: libuv/libuv#3064 Authored-by: Juan Pablo Canepa <jpcanepa@gmail.com> Co-authored-by: Marcello Bastéa-Forte <marcello@descript.com> Electron patch prepared by: Pat DeSantis <pdesantis3@gmail.com>
Spawning child processes in an Electron application with a hardened runtime has become slow in macOS Big Sur. This patch is a squashed version of libuv/libuv#3064, with the addition of API availability annotations to fix a build warning (since Electron compiles with the `-Wunguarded-availability-new` flag). This patch should be removed when libuv PR 3064 is merged. Fixes: libuv/libuv#3050 Fixes: electron#26143 PR-URL: libuv/libuv#3064 Authored-by: Juan Pablo Canepa <jpcanepa@gmail.com> Co-authored-by: Marcello Bastéa-Forte <marcello@descript.com> Electron patch prepared by: Pat DeSantis <pdesantis3@gmail.com>
bnoordhuis
left a comment
There was a problem hiding this comment.
I don't expect to have much time in the coming weeks so it would be good if other maintainers can also help review.
|
Resolved all pointed out issues. I refactored the initialization of the |
Spawning child processes in an Electron application with a hardened runtime has become slow in macOS Big Sur. This patch is a squashed version of libuv/libuv#3064, with the addition of API availability annotations to fix a build warning (since Electron compiles with the `-Wunguarded-availability-new` flag). This patch should be removed when libuv PR 3064 is merged. Fixes: libuv/libuv#3050 Fixes: electron#26143 PR-URL: libuv/libuv#3064 Authored-by: Juan Pablo Canepa <jpcanepa@gmail.com> Co-authored-by: Marcello Bastéa-Forte <marcello@descript.com> Electron patch prepared by: Pat DeSantis <pdesantis3@gmail.com>
| (void) posix_spawn_file_actions_destroy(&actions); | ||
| (void) posix_spawnattr_destroy(&attrs); |
There was a problem hiding this comment.
Seemed to me that the failure of either of these functions was not a reason to signal failure to the caller.
There was a problem hiding this comment.
optional: I'd perhaps suggest making them call abort instead?
There was a problem hiding this comment.
Your call, @vtjnash. If you think that failure of these calls warrants termination, let's do that.
Spawning child processes in an Electron application with a hardened runtime has become slow in macOS Big Sur. This patch is a squashed version of libuv/libuv#3064, with the addition of API availability annotations to fix a build warning (since Electron compiles with the `-Wunguarded-availability-new` flag). This patch should be removed when libuv PR 3064 is merged. Fixes: libuv/libuv#3050 Fixes: electron#26143 PR-URL: libuv/libuv#3064 Authored-by: Juan Pablo Canepa <jpcanepa@gmail.com> Co-authored-by: Marcello Bastéa-Forte <marcello@descript.com> Electron patch prepared by: Pat DeSantis <pdesantis3@gmail.com>
Spawning child processes in an Electron application with a hardened runtime has become slow in macOS Big Sur. This patch is a squashed version of libuv/libuv#3064, with the addition of API availability annotations to fix a build warning (since Electron compiles with the `-Wunguarded-availability-new` flag). This patch should be removed when libuv PR 3064 is merged. Fixes: libuv/libuv#3050 Fixes: electron#26143 PR-URL: libuv/libuv#3064 Authored-by: Juan Pablo Canepa <jpcanepa@gmail.com> Co-authored-by: Marcello Bastéa-Forte <marcello@descript.com> Electron patch prepared by: Pat DeSantis <pdesantis3@gmail.com>
Spawning child processes in an Electron application with a hardened runtime has become slow in macOS Big Sur. This patch is a squashed version of libuv/libuv#3064, with the addition of API availability annotations to fix a build warning (since Electron compiles with the `-Wunguarded-availability-new` flag). This patch should be removed when libuv PR 3064 is merged. Fixes: libuv/libuv#3050 Fixes: electron#26143 PR-URL: libuv/libuv#3064 Authored-by: Juan Pablo Canepa <jpcanepa@gmail.com> Co-authored-by: Marcello Bastéa-Forte <marcello@descript.com> Electron patch prepared by: Pat DeSantis <pdesantis3@gmail.com>
| if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) { | ||
| /* See the comment on the call to setgroups in uv__process_child_init above | ||
| * for why this is not a fatal error */ | ||
| SAVE_ERRNO(posix_spawn_fncs->spawnattr.set_groups_np(attrs, 0, NULL, KAUTH_UID_NONE)); |
There was a problem hiding this comment.
Is there any documentation on this? The best I could find is the source code, which indicates that NULL is invalid:
There was a problem hiding this comment.
None that I could find, hence the caveat in the description. I used the source for reference too, but failed to check that restriction. The ngroups set to zero means that that var will never be read (besides the if call, of course), so I think we can just pass in a pointer to a gid_t and that should be enough...
Spawning child processes in an Electron application with a hardened runtime has become slow in macOS Big Sur. This patch is a cherry-pick of libuv/libuv#3064. This patch should be removed when Electron's libuv version is updated to a version containing this fix. Fixes: libuv/libuv#3050 Fixes: electron#26143 PR-URL: libuv/libuv#3064 Authored-by: Juan Pablo Canepa <jpcanepa@gmail.com> Co-authored-by: Marcello Bastéa-Forte <marcello@descript.com>
This is a complete rewrite `posix/runProcess.c`. There are a few goals of this rewrite: * fix a long-standing and serious bug in the `execvpe` fallback path, which uses non-reentrant functions after `fork`ing. This is of course undefined behavior and has been causing failures under Darwin's Rosetta binary translation engine (see GHC #19994). * eliminate code duplication in the `fork/exec` implementation. * introduce support for `posix_spawn`, allowing us to unload a significant amount of complexity in some cases. This is particularly desireable as the cost of `fork` has increased considerably in some cases on recent Darwin releases (namely when `MAP_JIT` mappings are used; see [1]) While `posix_spawn` is often a win, there are unfortunately several cases where it cannot be used: * `posix_spawn_file_actions_addchdir_np` is broken on Darwin * `POSIX_SPAWN_SETSID` is only supported on mac 10.15 and later, but doesn't return a proper error code when not supported * the originally-specified semantics of `posix_spawn_file_actions_adddup2` are unsafe and have been amended (see [3]) but not all implementations have caught up (musl has [4], glibc did later [5], Darwin seemingly hasn't) there appears to be no support at all for setuid and setgid * `spawn` is significantly slower than fork on some Darwin releases (see [6]) To address this we first try using `posix_spawn`, falling back on `fork/exec` if we encounter a case which the former cannot handle. [1]: libuv/libuv#3064 [2]: https://www.austingroupbugs.net/view.php?id=411 [3]: rust-lang/rust#80537 [4]: https://git.musl-libc.org/cgit/musl/commit/?id=6fc6ca1a323bc0b6b9e9cdc8fa72221ae18fe206 [5]: https://sourceware.org/bugzilla/show_bug.cgi?id=23640 [6]: https://discuss.python.org/t/multiprocessing-spawn-default-on-macos-since-python-3-8-is-slower-than-fork-method/5910/4
This is a complete rewrite `posix/runProcess.c`. There are a few goals of this rewrite: * fix a long-standing and serious bug in the `execvpe` fallback path, which uses non-reentrant functions after `fork`ing. This is of course undefined behavior and has been causing failures under Darwin's Rosetta binary translation engine (see GHC #19994). * eliminate code duplication in the `fork/exec` implementation. * introduce support for `posix_spawn`, allowing us to unload a significant amount of complexity in some cases. This is particularly desireable as the cost of `fork` has increased considerably in some cases on recent Darwin releases (namely when `MAP_JIT` mappings are used; see [1]) While `posix_spawn` is often a win, there are unfortunately several cases where it cannot be used: * `posix_spawn_file_actions_addchdir_np` is broken on Darwin * `POSIX_SPAWN_SETSID` is only supported on mac 10.15 and later, but doesn't return a proper error code when not supported * the originally-specified semantics of `posix_spawn_file_actions_adddup2` are unsafe and have been amended (see [3]) but not all implementations have caught up (musl has [4], glibc did later [5], Darwin seemingly hasn't) there appears to be no support at all for setuid and setgid * `spawn` is significantly slower than fork on some Darwin releases (see [6]) To address this we first try using `posix_spawn`, falling back on `fork/exec` if we encounter a case which the former cannot handle. [1]: libuv/libuv#3064 [2]: https://www.austingroupbugs.net/view.php?id=411 [3]: rust-lang/rust#80537 [4]: https://git.musl-libc.org/cgit/musl/commit/?id=6fc6ca1a323bc0b6b9e9cdc8fa72221ae18fe206 [5]: https://sourceware.org/bugzilla/show_bug.cgi?id=23640 [6]: https://discuss.python.org/t/multiprocessing-spawn-default-on-macos-since-python-3-8-is-slower-than-fork-method/5910/4
Spawning child processes in an Electron application with a hardened runtime has become slow in macOS Big Sur. This patch is a cherry-pick of libuv/libuv#3064. This patch should be removed when Electron's libuv version is updated to a version containing this fix. Fixes: libuv/libuv#3050 Fixes: electron#26143 PR-URL: libuv/libuv#3064 Authored-by: Juan Pablo Canepa <jpcanepa@gmail.com> Co-authored-by: Marcello Bastéa-Forte <marcello@descript.com>
This is a complete rewrite `posix/runProcess.c`. There are a few goals of this rewrite: * fix a long-standing and serious bug in the `execvpe` fallback path, which uses non-reentrant functions after `fork`ing. This is of course undefined behavior and has been causing failures under Darwin's Rosetta binary translation engine (see GHC #19994). * eliminate code duplication in the `fork/exec` implementation. * introduce support for `posix_spawn`, allowing us to unload a significant amount of complexity in some cases. This is particularly desireable as the cost of `fork` has increased considerably in some cases on recent Darwin releases (namely when `MAP_JIT` mappings are used; see [1]) While `posix_spawn` is often a win, there are unfortunately several cases where it cannot be used: * `posix_spawn_file_actions_addchdir_np` is broken on Darwin * `POSIX_SPAWN_SETSID` is only supported on mac 10.15 and later, but doesn't return a proper error code when not supported * the originally-specified semantics of `posix_spawn_file_actions_adddup2` are unsafe and have been amended (see [3]) but not all implementations have caught up (musl has [4], glibc did later [5], Darwin seemingly hasn't) there appears to be no support at all for setuid and setgid * `spawn` is significantly slower than fork on some Darwin releases (see [6]) To address this we first try using `posix_spawn`, falling back on `fork/exec` if we encounter a case which the former cannot handle. [1]: libuv/libuv#3064 [2]: https://www.austingroupbugs.net/view.php?id=411 [3]: rust-lang/rust#80537 [4]: https://git.musl-libc.org/cgit/musl/commit/?id=6fc6ca1a323bc0b6b9e9cdc8fa72221ae18fe206 [5]: https://sourceware.org/bugzilla/show_bug.cgi?id=23640 [6]: https://discuss.python.org/t/multiprocessing-spawn-default-on-macos-since-python-3-8-is-slower-than-fork-method/5910/4
From: deepak1556 <hop2deep@gmail.com> Date: Wed, 3 Feb 2021 20:01:16 -0800 Subject: Use posix_spawn to spawn subprocesses on macOS Backports libuv/libuv#3064
Spawning child processes in an Electron application with a hardened runtime has become slow in macOS Big Sur. This patch is a cherry-pick of libuv/libuv#3064. This patch should be removed when Electron's libuv version is updated to a version containing this fix. Fixes: libuv/libuv#3050 Fixes: electron#26143 PR-URL: libuv/libuv#3064 Authored-by: Juan Pablo Canepa <jpcanepa@gmail.com> Co-authored-by: Marcello Bastéa-Forte <marcello@descript.com>
From: deepak1556 <hop2deep@gmail.com> Date: Wed, 3 Feb 2021 20:01:16 -0800 Subject: Use posix_spawn to spawn subprocesses on macOS Backports libuv/libuv#3064
From: deepak1556 <hop2deep@gmail.com> Date: Wed, 3 Feb 2021 20:01:16 -0800 Subject: Use posix_spawn to spawn subprocesses on macOS Backports libuv/libuv#3064
Spawning child processes in an Electron application with a hardened runtime has become slow in macOS Big Sur. This patch is a cherry-pick of libuv/libuv#3064. This patch should be removed when Electron's libuv version is updated to a version containing this fix. Fixes: libuv/libuv#3050 Fixes: electron#26143 PR-URL: libuv/libuv#3064 Authored-by: Juan Pablo Canepa <jpcanepa@gmail.com> Co-authored-by: Marcello Bastéa-Forte <marcello@descript.com>
From: deepak1556 <hop2deep@gmail.com> Date: Wed, 3 Feb 2021 20:01:16 -0800 Subject: Use posix_spawn to spawn subprocesses on macOS Backports libuv/libuv#3064
Spawning child processes in an Electron application with a hardened runtime has become slow in macOS Big Sur. This patch is a cherry-pick of libuv/libuv#3064. This patch should be removed when Electron's libuv version is updated to a version containing this fix. Fixes: libuv/libuv#3050 Fixes: electron#26143 PR-URL: libuv/libuv#3064 Authored-by: Juan Pablo Canepa <jpcanepa@gmail.com> Co-authored-by: Marcello Bastéa-Forte <marcello@descript.com>
Spawning child processes in an Electron application with a hardened runtime has become slow in macOS Big Sur. This patch is a cherry-pick of libuv/libuv#3064. This patch should be removed when Electron's libuv version is updated to a version containing this fix. Fixes: libuv/libuv#3050 Fixes: electron#26143 PR-URL: libuv/libuv#3064 Authored-by: Juan Pablo Canepa <jpcanepa@gmail.com> Co-authored-by: Marcello Bastéa-Forte <marcello@descript.com>
Spawning child processes in an Electron application with a hardened runtime has become slow in macOS Big Sur. This patch is a cherry-pick of libuv/libuv#3064. This patch should be removed when Electron's libuv version is updated to a version containing this fix. Fixes: libuv/libuv#3050 Fixes: electron#26143 PR-URL: libuv/libuv#3064 Authored-by: Juan Pablo Canepa <jpcanepa@gmail.com> Co-authored-by: Marcello Bastéa-Forte <marcello@descript.com>
Spawning child processes in an Electron application with a hardened runtime has become slow in macOS Big Sur. This patch is a cherry-pick of libuv/libuv#3064. This patch should be removed when Electron's libuv version is updated to a version containing this fix. Fixes: libuv/libuv#3050 Fixes: electron#26143 PR-URL: libuv/libuv#3064 Authored-by: Juan Pablo Canepa <jpcanepa@gmail.com> Co-authored-by: Marcello Bastéa-Forte <marcello@descript.com>
Spawning child processes in an Electron application with a hardened runtime has become slow in macOS Big Sur. This patch is a cherry-pick of libuv/libuv#3064. This patch should be removed when Electron's libuv version is updated to a version containing this fix. Fixes: libuv/libuv#3050 Fixes: electron#26143 PR-URL: libuv/libuv#3064 Authored-by: Juan Pablo Canepa <jpcanepa@gmail.com> Co-authored-by: Marcello Bastéa-Forte <marcello@descript.com>
Spawning child processes in an Electron application with a hardened runtime has become slow in macOS Big Sur. This patch is a cherry-pick of libuv/libuv#3064. This patch should be removed when Electron's libuv version is updated to a version containing this fix. Fixes: libuv/libuv#3050 Fixes: electron#26143 PR-URL: libuv/libuv#3064 Authored-by: Juan Pablo Canepa <jpcanepa@gmail.com> Co-authored-by: Marcello Bastéa-Forte <marcello@descript.com>
Spawning child processes in an Electron application with a hardened runtime has become slow in macOS Big Sur. This patch is a cherry-pick of libuv/libuv#3064. This patch should be removed when Electron's libuv version is updated to a version containing this fix. Fixes: libuv/libuv#3050 Fixes: electron#26143 PR-URL: libuv/libuv#3064 Authored-by: Juan Pablo Canepa <jpcanepa@gmail.com> Co-authored-by: Marcello Bastéa-Forte <marcello@descript.com>
Issue
This PR tackles #3050.
Overview
With Big Sur (macOS 11), apple introduced a significant performance degradation when trying to
fork()/execa new child process when the parent has many pages mmaped withMAP_JIT(like, say, a javascript interpreter). At the same time, on macOS spawning a subprocess withposix_spawn(as chromium does) does not incur on the overhead.This bug impacts electron apps that spawn subprocess, like for example, VSCode. There is an issue filed against electron itself as a consequence.
Using the repro app from the issue, I implemented the forking logic specific to macOS using posix_spawn, as far as I know, doing everything that the normal
forkpath does, with the extra advantage of having the macOS extension to posix_spawnPOSIX_SPAWN_CLOEXEC_DEFAULTthat treats all descriptors, regardless if opened or not withO_CLOEXEC, as if they had; that way we can guarantee no descriptors leak into the child process.