/* 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 <stdio.h>
#ifdef WIN32
/* perl probably did this already */
#include <windows.h>
#else
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
/* 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 <spawn.h>
#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