ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Proc-FastSpawn/FastSpawn.xs
Revision: 1.3
Committed: Tue Apr 2 03:53:50 2013 UTC (11 years, 1 month ago) by root
Branch: MAIN
Changes since 1.2: +4 -0 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.3 /* GetProcessId is XP and up */
2     #define _WIN32_WINNT NTDDI_WINXP
3    
4 root 1.1 #include "EXTERN.h"
5     #include "perl.h"
6     #include "XSUB.h"
7    
8     #include <stdio.h>
9    
10     #ifdef WIN32
11    
12 root 1.3 /* perl probably did this already */
13 root 1.1 #include <windows.h>
14    
15     #else
16    
17     #include <errno.h>
18     #include <fcntl.h>
19     #include <unistd.h>
20    
21     /* openbsd seems to have a buggy vfork (what would you expect), */
22     /* while others might implement vfork as fork in older versions, which is fine */
23     #if __linux || __FreeBSD__ || __NetBSD__ || __sun
24     #define USE_VFORK 1
25     #endif
26    
27     #if !USE_VFORK
28     #if _POSIX_SPAWN >= 200809L
29     #define USE_SPAWN 1
30     #include <spawn.h>
31     #else
32     #define vfork() fork()
33     #endif
34     #endif
35    
36     #endif
37    
38     static char *const *
39     array_to_cvec (SV *sv)
40     {
41     AV *av;
42     int n, i;
43     char **cvec;
44    
45     if (!SvROK (sv) || SvTYPE (SvRV (sv)) != SVt_PVAV)
46     croak ("expected a reference to an array of argument/environment strings");
47    
48     av = (AV *)SvRV (sv);
49     n = av_len (av) + 1;
50     cvec = (char **)SvPVX (sv_2mortal (NEWSV (0, sizeof (char *) * n + 1)));
51    
52     for (i = 0; i < n; ++i)
53     cvec [i] = SvPVbyte_nolen (*av_fetch (av, i, 11));
54    
55     cvec [n] = 0;
56    
57     return cvec;
58     }
59    
60     MODULE = Proc::FastSpawn PACKAGE = Proc::FastSpawn
61    
62     PROTOTYPES: ENABLE
63    
64     BOOT:
65     #ifndef WIN32
66     cv_undef (get_cv ("Proc::FastSpawn::_quote", 0));
67     #endif
68    
69     long
70     spawn (const char *path, SV *argv, SV *envp = &PL_sv_undef)
71     INIT:
72     {
73     #ifdef WIN32
74     if (w32_num_children >= MAXIMUM_WAIT_OBJECTS)
75     {
76     errno = EAGAIN;
77     XSRETURN_UNDEF;
78     }
79    
80     argv = sv_2mortal (newSVsv (argv));
81     PUSHMARK (SP);
82     XPUSHs (argv);
83     PUTBACK;
84     call_pv ("Proc::FastSpawn::_quote", G_VOID | G_DISCARD);
85     SPAGAIN;
86     #endif
87     }
88     CODE:
89     {
90     extern char **environ;
91     char *const *cargv = array_to_cvec (argv);
92     char *const *cenvp = SvOK (envp) ? array_to_cvec (envp) : environ;
93     intptr_t pid;
94    
95     fflush (0);
96     #ifdef WIN32
97     pid = _spawnve (_P_NOWAIT, path, cargv, cenvp);
98    
99     if (pid == -1)
100     XSRETURN_UNDEF;
101    
102     /* do it like perl, dadadoop dadadoop */
103     w32_child_handles [w32_num_children] = (HANDLE)pid;
104 root 1.2 pid = GetProcessId ((HANDLE)pid); /* get the real pid, unfortunately, requires wxp or newer */
105 root 1.1 w32_child_pids [w32_num_children] = pid;
106     ++w32_num_children;
107     #elif USE_SPAWN
108     {
109     pid_t xpid;
110    
111     errno = posix_spawn (&xpid, path, 0, 0, cargv, cenvp);
112    
113     if (errno)
114     XSRETURN_UNDEF;
115    
116     pid = xpid;
117     }
118     #else
119     pid = vfork ();
120    
121     if (pid < 0)
122     XSRETURN_UNDEF;
123    
124     if (pid == 0)
125     {
126     execve (path, cargv, cenvp);
127     _exit (127);
128     }
129     #endif
130    
131     RETVAL = pid;
132     }
133     OUTPUT: RETVAL
134    
135     void
136     fd_inherit (int fd, int on = 1)
137     CODE:
138     #ifdef WIN32
139     SetHandleInformation ((HANDLE)_get_osfhandle (fd), HANDLE_FLAG_INHERIT, on ? HANDLE_FLAG_INHERIT : 0);
140     #else
141     fcntl (fd, F_SETFD, on ? 0 : FD_CLOEXEC);
142     #endif