Currently just file actions open/close/dup2 are supported in the fast
path.
---
 winsup/cygwin/spawn.cc | 92 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index dc5f04db98..8a3879256c 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -1421,8 +1421,100 @@ do_posix_spawn (pid_t *pid, const char *path,
                const posix_spawnattr_t *sa, char * const argv[],
                char * const envp[], int use_env_path)
 {
+  short flags;
   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 && (posix_spawnattr_getflags (sa, &flags) || 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;
+               fds[fae->fae_newfildes] = dup (fae->fae_fildes);
+               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;
+               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);
+               fallthrough;
+             case __posix_spawn_file_actions_entry::FAE_CLOSE:
+               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

Reply via email to