ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Proc-FastSpawn/FastSpawn.xs
Revision: 1.4
Committed: Tue Apr 2 04:27:01 2013 UTC (11 years, 1 month ago) by root
Branch: MAIN
CVS Tags: rel-1_0, rel-0_2
Changes since 1.3: +2 -1 lines
Log Message:
*** empty log message ***

File Contents

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