/* GetProcessId is XP and up, which means in all supported versions */ /* but older SDK's might need this */ #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, 1)); 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) ALIAS: spawnp = 1 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 = (ix ? _spawnvpe : _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 = (ix ? posix_spawnp : posix_spawn) (&xpid, path, 0, 0, cargv, cenvp); if (errno) XSRETURN_UNDEF; pid = xpid; } #else pid = (ix ? fork : vfork) (); if (pid < 0) XSRETURN_UNDEF; if (pid == 0) { if (ix) { environ = (char **)cenvp; execvp (path, cargv); } else 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