File: FastSpawn.xs

package info (click to toggle)
libproc-fastspawn-perl 1.2-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 96 kB
  • sloc: perl: 20; makefile: 3
file content (153 lines) | stat: -rw-r--r-- 3,335 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/* 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