/* GetProcessId is XP and up */ #define _WIN32_WINNT NTDDI_WINXP #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include #ifdef WIN32 /* perl probably did this already */ #include #else #include #include #include /* openbsd seems to have a buggy vfork (what would you expect), */ /* while others might implement vfork as fork in older versions, which is fine */ #if __linux || __FreeBSD__ || __NetBSD__ || __sun #define USE_VFORK 1 #endif #if !USE_VFORK #if _POSIX_SPAWN >= 200809L #define USE_SPAWN 1 #include #else #define vfork() fork() #endif #endif #endif static char *const * array_to_cvec (SV *sv) { AV *av; int n, i; char **cvec; if (!SvROK (sv) || SvTYPE (SvRV (sv)) != SVt_PVAV) croak ("expected a reference to an array of argument/environment strings"); av = (AV *)SvRV (sv); n = av_len (av) + 1; cvec = (char **)SvPVX (sv_2mortal (NEWSV (0, sizeof (char *) * n + 1))); for (i = 0; i < n; ++i) cvec [i] = SvPVbyte_nolen (*av_fetch (av, i, 11)); cvec [n] = 0; return cvec; } MODULE = Proc::FastSpawn PACKAGE = Proc::FastSpawn PROTOTYPES: ENABLE BOOT: #ifndef WIN32 cv_undef (get_cv ("Proc::FastSpawn::_quote", 0)); #endif long spawn (const char *path, SV *argv, SV *envp = &PL_sv_undef) INIT: { #ifdef WIN32 if (w32_num_children >= MAXIMUM_WAIT_OBJECTS) { errno = EAGAIN; XSRETURN_UNDEF; } argv = sv_2mortal (newSVsv (argv)); PUSHMARK (SP); XPUSHs (argv); PUTBACK; call_pv ("Proc::FastSpawn::_quote", G_VOID | G_DISCARD); SPAGAIN; #endif } CODE: { extern char **environ; char *const *cargv = array_to_cvec (argv); char *const *cenvp = SvOK (envp) ? array_to_cvec (envp) : environ; intptr_t pid; fflush (0); #ifdef WIN32 pid = _spawnve (_P_NOWAIT, path, cargv, cenvp); if (pid == -1) XSRETURN_UNDEF; /* do it like perl, dadadoop dadadoop */ w32_child_handles [w32_num_children] = (HANDLE)pid; pid = GetProcessId ((HANDLE)pid); /* get the real pid, unfortunately, requires wxp or newer */ w32_child_pids [w32_num_children] = pid; ++w32_num_children; #elif USE_SPAWN { pid_t xpid; errno = posix_spawn (&xpid, path, 0, 0, cargv, cenvp); if (errno) XSRETURN_UNDEF; pid = xpid; } #else pid = vfork (); if (pid < 0) XSRETURN_UNDEF; if (pid == 0) { execve (path, cargv, cenvp); _exit (127); } #endif RETVAL = pid; } OUTPUT: RETVAL void fd_inherit (int fd, int on = 1) CODE: #ifdef WIN32 SetHandleInformation ((HANDLE)_get_osfhandle (fd), HANDLE_FLAG_INHERIT, on ? HANDLE_FLAG_INHERIT : 0); #else fcntl (fd, F_SETFD, on ? 0 : FD_CLOEXEC); #endif