Currently just file actions open/close/dup2 are supported in the fast path.
Signed-off-by: Jeremy Drake <cyg...@jdrake.com> --- winsup/cygwin/spawn.cc | 126 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index 63b6233255..7b02512212 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -1442,6 +1442,132 @@ do_posix_spawn (pid_t *pid, const char *path, { syscall_printf ("posix_spawn%s (%p, %s, %p, %p, %p, %p)", use_env_path ? "p" : "", pid, path, fa, sa, argv, envp); + + /* TODO: possibly implement spawnattr flags: + POSIX_SPAWN_RESETIDS + POSIX_SPAWN_SETPGROUP + POSIX_SPAWN_SETSCHEDPARAM + POSIX_SPAWN_SETSCHEDULER + POSIX_SPAWN_SETSIGDEF + POSIX_SPAWN_SETSIGMASK */ + if (sa && (*sa)->sa_flags) + goto fallback; + + { + path_conv buf; + lock_process now; + posix_spawn_file_actions_entry_t *fae; + pid_t chpid; + int fds[3] = {-1, -1, -1}; + int oldflags[cygheap->fdtab.size]; + int ret = -1; + memset (oldflags, -1, sizeof (oldflags)); + + if (fa) + { + STAILQ_FOREACH(fae, &(*fa)->fa_list, fae_list) + { + switch (fae->fae_action) + { + case __posix_spawn_file_actions_entry::FAE_DUP2: + if (fae->fae_newfildes < 0 || fae->fae_newfildes > 2) + goto closes; + + if (fds[fae->fae_newfildes] != -1) + close (fds[fae->fae_newfildes]); + + if (fae->fae_fildes >= 0 && fae->fae_fildes <= 2 && + fds[fae->fae_fildes] != -1) + fds[fae->fae_newfildes] = dup (fds[fae->fae_fildes]); + else + fds[fae->fae_newfildes] = dup (fae->fae_fildes); + + if (fds[fae->fae_newfildes] < 0) + { + fds[fae->fae_newfildes] = -1; + ret = get_errno (); + goto closes; + } + + if (oldflags[fae->fae_newfildes] == -1) + oldflags[fae->fae_newfildes] = fcntl (fae->fae_newfildes, + F_GETFD, 0); + fcntl (fae->fae_newfildes, F_SETFD, FD_CLOEXEC); + break; + + case __posix_spawn_file_actions_entry::FAE_OPEN: + if (fae->fae_fildes < 0 || fae->fae_fildes > 2) + goto closes; + if (fds[fae->fae_fildes] != -1) + close (fds[fae->fae_fildes]); + /* can we just mask out O_CLOEXEC from fae_oflag, or must we + use F_SETFD later? */ + fds[fae->fae_fildes] = open (fae->fae_path, fae->fae_oflag, + fae->fae_mode); + if (fds[fae->fae_fildes] < 0) + { + fds[fae->fae_fildes] = -1; + ret = get_errno (); + goto closes; + } + fcntl (fds[fae->fae_fildes], F_SETFD, 0); + if (oldflags[fae->fae_fildes] == -1) + oldflags[fae->fae_fildes] = fcntl (fae->fae_fildes, F_GETFD, + 0); + fcntl (fae->fae_fildes, F_SETFD, FD_CLOEXEC); + break; + case __posix_spawn_file_actions_entry::FAE_CLOSE: + if (fae->fae_fildes >= 0 && fae->fae_fildes <= 2 && + fds[fae->fae_fildes] != -1) + { + fcntl (fds[fae->fae_fildes], F_SETFD, FD_CLOEXEC); + } + else + { + if (oldflags[fae->fae_fildes] == -1) + oldflags[fae->fae_fildes] = fcntl (fae->fae_fildes, + F_GETFD, 0); + fcntl (fae->fae_fildes, F_SETFD, FD_CLOEXEC); + } + break; + /* TODO: FAE_(F)CHDIR */ + default: + goto closes; + } + } + } + + chpid = ch_spawn.worker ( + use_env_path ? (find_exec (path, buf, "PATH", FE_NNF) ?: "") + : path, + argv, envp ?: environ, + _P_NOWAIT | (use_env_path ? _P_PATH_TYPE_EXEC : 0), + fds[0], fds[1], fds[2]); + + if (chpid < 0) + { + ret = get_errno (); + } + else + { + *pid = chpid; + ret = 0; + } + +closes: + int save_errno = get_errno (); + for (size_t i = 0; i < 3; i++) + if (fds[i] != -1) + close (fds[i]); + for (size_t i = 0; i < sizeof (oldflags) / sizeof (oldflags[0]); i++) + if (oldflags[i] != -1) + fcntl (i, F_SETFD, oldflags[i]); + set_errno (save_errno); + if (ret != -1) + return ret; + } + +fallback: if (use_env_path) return posix_spawnp (pid, path, fa, sa, argv, envp); else -- 2.49.0.windows.1