ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Proc-FastSpawn/FastSpawn.xs
Revision: 1.5
Committed: Sun Apr 28 00:49:43 2013 UTC (11 years, 1 month ago) by root
Branch: MAIN
CVS Tags: rel-1_1
Changes since 1.4: +21 -10 lines
Log Message:
1.1

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 root 1.5 ALIAS:
73     spawnp = 1
74 root 1.1 INIT:
75     {
76     #ifdef WIN32
77     if (w32_num_children >= MAXIMUM_WAIT_OBJECTS)
78     {
79     errno = EAGAIN;
80     XSRETURN_UNDEF;
81     }
82    
83     argv = sv_2mortal (newSVsv (argv));
84     PUSHMARK (SP);
85     XPUSHs (argv);
86     PUTBACK;
87     call_pv ("Proc::FastSpawn::_quote", G_VOID | G_DISCARD);
88     SPAGAIN;
89     #endif
90     }
91     CODE:
92     {
93     extern char **environ;
94     char *const *cargv = array_to_cvec (argv);
95     char *const *cenvp = SvOK (envp) ? array_to_cvec (envp) : environ;
96     intptr_t pid;
97    
98     fflush (0);
99     #ifdef WIN32
100 root 1.5 pid = (ix ? _spawnvpe : _spawnve) (_P_NOWAIT, path, cargv, cenvp);
101 root 1.1
102     if (pid == -1)
103     XSRETURN_UNDEF;
104    
105     /* do it like perl, dadadoop dadadoop */
106     w32_child_handles [w32_num_children] = (HANDLE)pid;
107 root 1.2 pid = GetProcessId ((HANDLE)pid); /* get the real pid, unfortunately, requires wxp or newer */
108 root 1.1 w32_child_pids [w32_num_children] = pid;
109     ++w32_num_children;
110     #elif USE_SPAWN
111     {
112     pid_t xpid;
113    
114 root 1.5 errno = (ix ? posix_spawnp : posix_spawn) (&xpid, path, 0, 0, cargv, cenvp);
115 root 1.1
116     if (errno)
117     XSRETURN_UNDEF;
118    
119     pid = xpid;
120     }
121     #else
122 root 1.5 {
123     char **old_environ = environ;
124     environ = (char **)cenvp;
125    
126     pid = vfork ();
127    
128     if (pid)
129     environ = old_environ;
130 root 1.1
131 root 1.5 if (pid < 0)
132     XSRETURN_UNDEF;
133 root 1.1
134 root 1.5 if (pid == 0)
135     {
136     (ix ? execvp : execv) (path, cargv);
137     _exit (127);
138     }
139     }
140 root 1.1 #endif
141    
142     RETVAL = pid;
143     }
144     OUTPUT: RETVAL
145    
146     void
147     fd_inherit (int fd, int on = 1)
148     CODE:
149     #ifdef WIN32
150     SetHandleInformation ((HANDLE)_get_osfhandle (fd), HANDLE_FLAG_INHERIT, on ? HANDLE_FLAG_INHERIT : 0);
151     #else
152     fcntl (fd, F_SETFD, on ? 0 : FD_CLOEXEC);
153     #endif
154 root 1.5