1
- // So when running tests in parallel there's a potential race on environment
2
- // variables if we let each task spawn its own children - between the time the
3
- // environment is set and the process is spawned another task could spawn its
4
- // child process. Because of that we have to use a complicated scheme with a
5
- // dedicated server for spawning processes.
6
-
7
- import std:: generic_os:: setenv;
8
- import std:: generic_os:: getenv;
9
- import std:: os;
10
1
import std:: run;
2
+ import std:: run:: spawn_process;
11
3
import std:: io;
4
+ import std:: os;
12
5
import io:: writer_util;
13
- import comm:: chan;
14
- import comm:: port;
15
- import comm:: send;
16
- import comm:: recv;
17
6
import ctypes:: { pid_t, fd_t} ;
18
7
19
- export handle;
20
- export mk;
21
- export from_chan;
22
8
export run;
23
- export close;
24
- export reqchan;
25
9
26
- type reqchan = chan < request > ;
27
-
28
- type handle =
29
- { task : option < ( task:: task , port < task:: task_notification > ) > ,
30
- chan : reqchan } ;
31
-
32
- enum request { exec( [ u8 ] , [ u8 ] , [ [ u8 ] ] , chan < response > ) , stop, }
10
+ #[ cfg( target_os = "win32" ) ]
11
+ fn target_env ( lib_path : str , prog : str ) -> option < [ ( str , str ) ] > {
33
12
34
- type response = { pid : pid_t , infd : fd_t ,
35
- outfd : fd_t , errfd : fd_t } ;
13
+ let env = std:: generic_os:: env ( ) ;
36
14
37
- fn mk ( ) -> handle {
38
- let setupport = port ( ) ;
39
- let setupchan = chan ( setupport) ;
40
- let task = task:: spawn_joinable { ||
41
- let reqport = port ( ) ;
42
- let reqchan = chan ( reqport) ;
43
- send ( setupchan, reqchan) ;
44
- worker ( reqport) ;
15
+ env = vec:: map ( env) { |pair|
16
+ let ( k, v) = pair;
17
+ if k == "PATH" { ( "PATH" , v + ";" + lib_path) }
18
+ else { ( k, v) }
45
19
} ;
46
- ret { task : option:: some ( task) , chan : recv ( setupport) } ;
20
+ if str:: ends_with ( prog, "rustc.exe" ) {
21
+ env += [ ( "RUST_THREADS" , "1" ) ]
22
+ }
23
+ ret some( env) ;
47
24
}
48
25
49
- fn from_chan ( ch : reqchan ) -> handle { { task : option :: none , chan : ch } }
50
-
51
- fn close ( handle : handle ) {
52
- send ( handle . chan , stop ) ;
53
- task :: join ( option :: get ( handle . task ) ) ;
26
+ # [ cfg ( target_os = "linux" ) ]
27
+ # [ cfg ( target_os = "macos" ) ]
28
+ # [ cfg ( target_os = "freebsd" ) ]
29
+ fn target_env ( lib_path : str , prog : str ) -> option < [ ( str , str ) ] > {
30
+ none
54
31
}
55
32
56
- fn run ( handle : handle , lib_path : str , prog : str , args : [ str ] ,
33
+
34
+ fn run ( lib_path : str , prog : str , args : [ str ] ,
57
35
input : option < str > ) -> { status : int , out : str , err : str } {
58
- let p = port ( ) ;
59
- let ch = chan ( p) ;
60
- send ( handle. chan ,
61
- exec ( str:: bytes ( lib_path) , str:: bytes ( prog) , clone_vecstr ( args) ,
62
- ch) ) ;
63
- let resp = recv ( p) ;
64
36
65
- writeclose ( resp. infd , input) ;
66
- let output = readclose ( resp. outfd ) ;
67
- let errput = readclose ( resp. errfd ) ;
68
- let status = run:: waitpid ( resp. pid ) ;
37
+ let pipe_in = os:: pipe ( ) ;
38
+ let pipe_out = os:: pipe ( ) ;
39
+ let pipe_err = os:: pipe ( ) ;
40
+ let pid = spawn_process ( prog, args, target_env ( lib_path, prog) , none,
41
+ pipe_in. in , pipe_out. out , pipe_err. out ) ;
42
+
43
+ os:: close ( pipe_in. in ) ;
44
+ os:: close ( pipe_out. out ) ;
45
+ os:: close ( pipe_err. out ) ;
46
+ if pid == -1i32 {
47
+ os:: close ( pipe_in. out ) ;
48
+ os:: close ( pipe_out. in ) ;
49
+ os:: close ( pipe_err. in ) ;
50
+ fail;
51
+ }
52
+
53
+
54
+ writeclose ( pipe_in. out , input) ;
55
+ let output = readclose ( pipe_out. in ) ;
56
+ let errput = readclose ( pipe_err. in ) ;
57
+ let status = run:: waitpid ( pid) ;
69
58
ret { status : status, out : output, err : errput} ;
70
59
}
71
60
@@ -90,106 +79,3 @@ fn readclose(fd: fd_t) -> str {
90
79
os:: fclose ( file) ;
91
80
ret buf;
92
81
}
93
-
94
- fn worker ( p : port < request > ) {
95
-
96
- // FIXME (787): If we declare this inside of the while loop and then
97
- // break out of it before it's ever initialized (i.e. we don't run
98
- // any tests), then the cleanups will puke.
99
- let execparms;
100
-
101
- while true {
102
- // FIXME: Sending strings across channels seems to still
103
- // leave them refed on the sender's end, which causes problems if
104
- // the receiver's poniters outlive the sender's. Here we clone
105
- // everything and let the originals go out of scope before sending
106
- // a response.
107
- execparms =
108
- {
109
-
110
- // FIXME (785): The 'discriminant' of an alt expression has
111
- // the same scope as the alt expression itself, so we have to
112
- // put the entire alt in another block to make sure the exec
113
- // message goes out of scope. Seems like the scoping rules for
114
- // the alt discriminant are wrong.
115
- alt recv ( p) {
116
- exec ( lib_path, prog, args, respchan) {
117
- { lib_path: str :: from_bytes ( lib_path) ,
118
- prog: str:: from_bytes ( prog) ,
119
- args: clone_vecu8str ( args) ,
120
- respchan: respchan}
121
- }
122
- stop { ret }
123
- }
124
- } ;
125
-
126
- // This is copied from run::start_program
127
- let pipe_in = os:: pipe ( ) ;
128
- let pipe_out = os:: pipe ( ) ;
129
- let pipe_err = os:: pipe ( ) ;
130
- let spawnproc =
131
- bind run:: spawn_process ( execparms. prog , execparms. args ,
132
- pipe_in. in , pipe_out. out , pipe_err. out ) ;
133
- let pid = maybe_with_lib_path ( execparms. lib_path , spawnproc) ;
134
-
135
- os:: close ( pipe_in. in ) ;
136
- os:: close ( pipe_out. out ) ;
137
- os:: close ( pipe_err. out ) ;
138
- if pid == -1i32 {
139
- os:: close ( pipe_in. out ) ;
140
- os:: close ( pipe_out. in ) ;
141
- os:: close ( pipe_err. in ) ;
142
- fail;
143
- }
144
-
145
- send ( execparms. respchan ,
146
- { pid: pid,
147
- infd: pipe_in. out ,
148
- outfd: pipe_out. in ,
149
- errfd: pipe_err. in } ) ;
150
- }
151
- }
152
-
153
- // Only windows needs to set the library path
154
- #[ cfg( target_os = "win32" ) ]
155
- fn maybe_with_lib_path < T > ( path : str , f : fn @( ) -> T ) -> T {
156
- with_lib_path ( path, f)
157
- }
158
-
159
- #[ cfg( target_os = "linux" ) ]
160
- #[ cfg( target_os = "macos" ) ]
161
- #[ cfg( target_os = "freebsd" ) ]
162
- fn maybe_with_lib_path < T > ( _path : str , f : fn @( ) -> T ) -> T {
163
- f ( )
164
- }
165
-
166
- fn with_lib_path < T > ( path : str , f : fn @( ) -> T ) -> T {
167
- let maybe_oldpath = getenv ( util:: lib_path_env_var ( ) ) ;
168
- append_lib_path ( path) ;
169
- let res = f ( ) ;
170
- if option:: is_some ( maybe_oldpath) {
171
- export_lib_path ( option:: get ( maybe_oldpath) ) ;
172
- } else {
173
- // FIXME: This should really be unset but we don't have that yet
174
- export_lib_path ( "" ) ;
175
- }
176
- ret res;
177
- }
178
-
179
- fn append_lib_path ( path : str ) { export_lib_path ( util:: make_new_path ( path) ) ; }
180
-
181
- fn export_lib_path ( path : str ) { setenv ( util:: lib_path_env_var ( ) , path) ; }
182
-
183
- fn clone_vecstr ( v : [ str ] ) -> [ [ u8 ] ] {
184
- let r = [ ] ;
185
- for t: str in vec:: slice ( v, 0 u, vec:: len ( v) ) { r += [ str:: bytes ( t) ] ; }
186
- ret r;
187
- }
188
-
189
- fn clone_vecu8str ( v : [ [ u8 ] ] ) -> [ str ] {
190
- let r = [ ] ;
191
- for t in vec:: slice ( v, 0 u, vec:: len ( v) ) {
192
- r += [ str:: from_bytes ( t) ] ;
193
- }
194
- ret r;
195
- }
0 commit comments