posix_spawn() - #140
Draft
dscho wants to merge 28 commits into
Draft
Conversation
This will allow Cygwin to examine and handle the posix_spawnattr_t and posix_spawn_file_actions_t arguments itself. Cherry-picked-from: 756669312c (posix_spawn: factor out structs to an internal header, 2025-06-17) Signed-off-by: Jeremy Drake <cygwin@jdrake.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Currently just a couple of tests of error conditions, but I have more tests to add. Cherry-picked-from: 6df7cdc54b (Cygwin: testsuite: add posix_spawn tests, 2025-06-17) Signed-off-by: Jeremy Drake <cygwin@jdrake.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Given the limited binaries available (sh, ls, sleep), use sh -c true Cherry-picked-from: 0139b7ae69 (Cygwin: testsuite: test posix_spawnp, 2025-06-18) Signed-off-by: Jeremy Drake <cygwin@jdrake.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Test both that SIG_IGN and sigprocmask are inherited by default, and that posix_spawnattr options can prevent this. Cherry-picked-from: d33a13e5c1 (Cygwin: testsuite: test signal mask and ignore options., 2025-06-19) Signed-off-by: Jeremy Drake <cygwin@jdrake.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
There are still more that could be tested, such as (f)chdir. Cherry-picked-from: 908e644b7d (Cygwin: testsuite: test posix_spawn_file_actions., 2025-06-19) Signed-off-by: Jeremy Drake <cygwin@jdrake.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Also test their interaction with addopen, as opens added subsequent to a chdir need to be relative to that new cwd. In order for the tests to compile on Linux, define O_SEARCH to O_PATH if O_SEARCH is not defined, and use the *chdir_np names instead of the now-standardized *chdir. Cherry-picked-from: 922719ba36 (Cygwin: testsuite: test posix_file_actions_add(f)chdir, 2025-06-24) Signed-off-by: Jeremy Drake <cygwin@jdrake.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This is required on Linux. Cherry-picked-from: 1b60f4861b (Cygwin: testsuite: include sys/stat.h for chmod in posix_spawn/errors.c, 2025-06-26) Signed-off-by: Jeremy Drake <cygwin@jdrake.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This program is currently meant to test standard file handles and current working directory (since these are settable via posix_spawn), but could be extended to add additional checks if other cygwin-to-win32 process properties need to be tested. Cherry-picked-from: 2af1914b6a (Cygwin: testsuite: add a mingw test program to spawn, 2025-06-25) Signed-off-by: Jeremy Drake <cygwin@jdrake.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Test CWD and redirection of standard handles. Cherry-picked-from: 9deb0bc3b5 (Cygwin: testsuite: test posix_spawn of a non-Cygwin executable., 2025-06-25) Signed-off-by: Jeremy Drake <cygwin@jdrake.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This is a legal (if non-obvious) thing to do, so test it. Cherry-picked-from: a4c2540d0f (Cygwin: testsuite: test passing directory fd to child, 2025-06-26) Signed-off-by: Jeremy Drake <cygwin@jdrake.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This is apparently relative to the new cwd, but my implementation is currently treating it as relative to the parent's cwd, so it's worth testing. Cherry-picked-from: b4e4cb4c86 (Cygwin: testsuite: test relative path to exe after addchdir., 2025-06-26) Signed-off-by: Jeremy Drake <cygwin@jdrake.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
According to the POSIX documentation, "when the new process image is executed, any file descriptor (from this new set) which has its FD_CLOEXEC flag set shall be closed (see posix_spawn())." The "new set" is after processing the file actions, so if addopen had the O_CLOEXEC flag set the descriptor should be closed after the exec. The adddup2 docs, by contrast, specify that the flag should be cleared, even if dup2 wouldn't have done so due to the specified file descriptors being equal. Add a comment to that effect. Addresses: https://sourceware.org/pipermail/newlib/2025/021968.html Fixes: c7c1a1c ("2013-10-01 Petr Hosek <phosek@chromium.org>") Cherry-picked-from: fb092671a7 (posix_spawn: preserve FD flags when processing FAE_OPEN, 2025-07-08) Signed-off-by: Jeremy Drake <cygwin@jdrake.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This was previously not handled correctly by newlib. Cherry-picked-from: 1abf10e225 (Cygwin: testsuite: test posix_spawn_file_actions_addopen with O_CLOEXEC, 2025-07-08) Signed-off-by: Jeremy Drake <cygwin@jdrake.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
stdin and stdout were alreadly allowed for popen, but implementing posix_spawn in terms of spawn would require stderr as well. Replace the conveniently-located 4 filler bytes with int __stderr so that child_info_spawn doesn't have to grow. Introduce a struct for passing additional args to ch_worker.spawn, since there are getting to be quite a lot of additional args. Signed-off-by: Jeremy Drake <cygwin@jdrake.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This will be used by posix_spawn_fileaction_add_(f)chdir. The int cwdfd is placed such that it fits into space previously unused due to alignment in the cygheap_exec_info class. This uses a file descriptor rather than a path both because it is easier to marshal to the child and because this should protect against races where the directory might be renamed or removed between addfchdir and the actual setting of the cwd in the child. Signed-off-by: Jeremy Drake <cygwin@jdrake.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This will allow checking for and optimizing cases that can easily be implemented using ch_spawn instead of using a full fork/exec. Signed-off-by: Jeremy Drake <cygwin@jdrake.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Currently just file actions are supported in the fast path, open/dup2 with a target fd of stdin/out/err, close of any fd, and chdir and fchdir. These were chosen as the least-common-denominator of functionality supported for any child process, as they are allowed to be specified via CreateProcess. They also happen to be the most common file operations, performed by the likes of GNU make, ninja, LLVM, and rust. For other attributes or actions, fall back to the newlib implementation of posix_spawn (which uses fork/exec to set everything up in the child process). Signed-off-by: Jeremy Drake <cygwin@jdrake.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
the sigmask was already a member of the child_info, so this just needed an arg to allow overriding the value copied from cygheap. The signal handlers are referenced by two pointers, global_sigs which is used by the signal routines, and cygheap->sigs which is only used during process launch and startup. Temporarily replace cygheap->sigs with a copy that has the requested signals reset to default while spawning the child. Signed-off-by: Jeremy Drake <cygwin@jdrake.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Tweak proc_subproc PROC_ADD_CHILD to only initialize vchild->pgid if it's not already set. The error checking of setpgid is lacking with respect to the POSIX standard, but this code replicates what setpgid does. This attribute is used by ninja, so is worth adding to the fast path. Signed-off-by: Jeremy Drake <cygwin@jdrake.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Commit 8860524 (Cygwin: fix child getting another pid after spawnve, 2019-02-08) uses INVALID_HANDLE_VALUE to tell pinfo::thisproc() that a spawned process already received its Cygwin PID from its parent. Unlike a genuinely exec'ed process, that process still has to create and maintain its own winpid symlink. Commit 1b86dd7 (Cygwin: make sure exec'ed process exists early in process list, 2022-05-19) taught the exec'ing process to maintain that symlink across exec. As part of that change, it used the truthiness of the handle argument to identify exec'ed processes and stopped them from creating the symlink themselves. INVALID_HANDLE_VALUE is truthy, too, so this also unintentionally stopped spawned Cygwin processes from creating their winpid symlink. Such a process has a valid internal PID and process group, but is missing from winpids enumeration. Consequently, ps does not list it as a Cygwin process and kill(-pgid, ...) returns ESRCH. In particular, this prevents terminal-generated signals such as Ctrl+C from reaching a foreground process started via posix_spawn(). Distinguish the spawn sentinel from a real exec handle and create the winpid symlink for spawned processes. Actual exec'ed processes keep the behavior introduced in 1b86dd7: their exec'ing process creates and preserves the symlink while the new image starts. Fixes: 1b86dd7 ("Cygwin: make sure exec'ed process exists early in process list") Assisted-by: Claude Sonnet 5 and GPT 5.6 Sol Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
cygwin: testsuite: link test DLLs against libmsys-2.0
posix_spawn() assigns the Cygwin PID and process group before starting the child. The spawned process must also create its winpid symlink so that winpids enumeration can map the Windows PID back to that Cygwin process-table entry. Without that mapping, getpgid() in the child can report the requested process group while group operations such as kill(-pgid, ...) fail with ESRCH. This also prevents terminal-generated signals from reaching a foreground process group. Spawn a copy of the test in a new process group, verify both the stored pgid and group enumeration via kill(-pgid, 0), then terminate the child through the process group. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
POSIX spawn file actions transform a logical copy of the child's descriptor table in insertion order. Later actions must observe every open, dup2, and close performed by earlier actions, rather than the parent's unchanged descriptor table. Exercise interactions that the fast path's separate stdfds array and deferred-close handling do not currently represent: a same-descriptor dup2 after addopen, dup2 from a descriptor closed by an earlier action, fchdir from a closed descriptor, and fchdir through a directory opened into a standard descriptor by an earlier action. These cases also verify that same-descriptor dup2 preserves the logical open file while applying dup2's descriptor-flag semantics, and that action failures are returned by posix_spawn() without executing the child image. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The POSIX-spawn error test expects a file created by mkstemp() to be non-executable until chmod() changes its mode, and therefore expects posix_spawn() to return EACCES. MSYS2 mounts filesystems with noacl by default. POSIX execute bits are not enforced by Windows ACLs in that configuration, so process creation gets as far as examining the file format and returns ENOEXEC instead. This is the same deliberate platform distinction behind the existing MSYS2 permission-test XFAILs. Skip only the pre-chmod EACCES assertion when building the test for MSYS2. Cygwin and other platforms retain the original check, and the subsequent ENOEXEC assertion still exercises spawning the executable file on MSYS2. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The fast path intentionally handles open and dup2 targets only for stdin, stdout, and stderr. Targets above stderr must therefore remain correct through the newlib fork/exec fallback. Cover addopen and adddup2 for a higher descriptor, including addopen with O_CLOEXEC. Also verify that closing an already closed descriptor is harmless, as required for spawn file actions. Strengthen the ordered same-descriptor dup2 test by opening the logical descriptor with O_CLOEXEC first. The later dup2 must leave the opened file in place while clearing FD_CLOEXEC. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The posix_spawn fast path processes file actions before it knows whether the child is a Cygwin or native executable. Ordered-action coverage must therefore exercise both child types. For the native helper, verify that same-descriptor dup2 keeps a file opened by an earlier action and clears O_CLOEXEC. Also verify that fchdir resolves a directory descriptor opened into stdin by an earlier action. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The posix_spawn fast path represents replacement standard descriptors
in spawn_worker_args::stdfds and implements close actions by temporarily
setting FD_CLOEXEC in the parent. It did not, however, preserve a
logical child descriptor table while processing later actions.
As a consequence, later actions could resolve a descriptor in the
unchanged parent table after an earlier action had closed it. A
same-descriptor dup2 after addopen discarded the opened file, and
fchdir could not use a directory opened into a standard descriptor by
an earlier action. These behaviors violate the requirement that file
actions transform the child's descriptor table in insertion order.
Track logical closes separately from the parent descriptor table and
resolve dup2 and fchdir sources through both that state and the mapped
standard descriptors. Opens and dup2 operations replace the logical
target, while close makes later references fail with EBADF.
Move temporary standard and cwd descriptors above stderr immediately
so subsequent actions cannot overwrite them accidentally. Preserve
the flags created by addopen, clear FD_CLOEXEC for adddup2 including
the same-descriptor case, and continue restoring every temporary parent
FD_CLOEXEC change on exit.
Pre-scan the action list and select the newlib fork/exec fallback before
changing descriptor flags when an open or dup2 target above stderr is
requested. Allocate the closed-descriptor set with checked heap
storage and release it on every fast-path and fallback exit.
Fixes: 9dd807043b28 ("Cygwin: add fast-path for posix_spawn(p)")
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The posix_spawn process-group support adds pgid to spawn_worker_args,
which changes the child-info layout shared between the spawning process
and a Cygwin child.
CURR_CHILD_INFO_MAGIC still described the preceding layout. The build
therefore warned that the generated magic was 0x99ae8af0 rather than
0xd0e19b15.
Update the constant to the generated value so incompatible parent and
child layouts are detected correctly.
Fixes: 0802d9184bc8 ("Cygwin: add pgroup support to posix_spawn fast path")
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.