Skip to content

Commit b306a0d

Browse files
committed
Get compile tests to run in parallel
Takes a lot of workarounds. The biggest problem is that boxes still don't seem to be moved across channels and bad things happen when the receiver destroys them. So there's all sorts of defensive cloning and scoping going on here to make the box lifetimes come out right.
1 parent f3df9f5 commit b306a0d

File tree

1 file changed

+86
-31
lines changed

1 file changed

+86
-31
lines changed

src/test/compiletest/compiletest.rs

Lines changed: 86 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import std::generic_os::getenv;
1111
import std::os;
1212
import std::run;
1313
import std::task;
14+
import std::unsafe;
1415

1516
tag mode { mode_compile_fail; mode_run_fail; mode_run_pass; }
1617

@@ -175,7 +176,6 @@ fn make_test(cx: &cx, testfile: &str, configport: &port[str]) ->
175176
ignore: header::is_test_ignored(cx.config, testfile)}
176177
}
177178

178-
179179
/*
180180
So this is kind of crappy:
181181
@@ -223,7 +223,7 @@ fn closure_to_task(cx: cx, configport: port[str], testfn: &fn() ) -> task {
223223
cx.config.run_ignored, opt_str(cx.config.filter),
224224
opt_str(cx.config.runtool),
225225
opt_str(cx.config.rustcflags), cx.config.verbose,
226-
procsrv::clone(cx.procsrv).chan, testfile);
226+
task::clone_chan(cx.procsrv.chan), testfile);
227227
}
228228

229229
fn run_test_task(compile_lib_path: str, run_lib_path: str, rustc_path: str,
@@ -304,6 +304,23 @@ fn logv(config: &config, s: &str) {
304304
if config.verbose { io::stdout().write_line(s); }
305305
}
306306

307+
fn clone_str(s: &str) -> str {
308+
let new = s + "";
309+
// new should be a different pointer
310+
let sptr: int = unsafe::reinterpret_cast(s);
311+
let newptr: int = unsafe::reinterpret_cast(new);
312+
assert sptr != newptr;
313+
new
314+
}
315+
316+
fn clone_ivecstr(v: &str[]) -> str[] {
317+
let r = ~[];
318+
for t: str in ivec::slice(v, 0u, ivec::len(v)) {
319+
r += ~[clone_str(t)];
320+
}
321+
ret r;
322+
}
323+
307324
mod header {
308325

309326
export test_props;
@@ -396,10 +413,10 @@ mod runtest {
396413
log #fmt("running %s", testfile);
397414
let props = load_props(testfile);
398415
alt cx.config.mode {
399-
mode_compile_fail. { run_cfail_test(cx, props, testfile); }
400-
mode_run_fail. { run_rfail_test(cx, props, testfile); }
401-
mode_run_pass. { run_rpass_test(cx, props, testfile); }
402-
}
416+
mode_compile_fail. { run_cfail_test(cx, props, testfile); }
417+
mode_run_fail. { run_rfail_test(cx, props, testfile); }
418+
mode_run_pass. { run_rpass_test(cx, props, testfile); }
419+
}
403420
}
404421

405422
fn run_cfail_test(cx: &cx, props: &test_props, testfile: &str) {
@@ -622,7 +639,7 @@ mod procsrv {
622639

623640
type handle = {task: option::t[task], chan: reqchan};
624641

625-
tag request { exec(str, str, vec[str], chan[response]); stop; }
642+
tag request { exec(str, str, str[], chan[response]); stop; }
626643

627644
type response = {pid: int, outfd: int, errfd: int};
628645

@@ -631,7 +648,7 @@ mod procsrv {
631648
let task = spawn fn(setupchan: chan[chan[request]]) {
632649
let reqport = port();
633650
let reqchan = chan(reqport);
634-
task::send(setupchan, reqchan);
651+
task::send(setupchan, task::clone_chan(reqchan));
635652
worker(reqport);
636653
} (chan(setupport));
637654
ret {task: option::some(task),
@@ -657,7 +674,10 @@ mod procsrv {
657674
{status: int, out: str, err: str} {
658675
let p = port[response]();
659676
let ch = chan(p);
660-
task::send(handle.chan, exec(lib_path, prog, args, ch));
677+
task::send(handle.chan, exec(lib_path,
678+
prog,
679+
clone_ivecstr(ivec::from_vec(args)),
680+
task::clone_chan(ch)));
661681
let resp = task::recv(p);
662682
let output = readclose(resp.outfd);
663683
let errput = readclose(resp.errfd);
@@ -679,29 +699,64 @@ mod procsrv {
679699
}
680700

681701
fn worker(p: port[request]) {
702+
703+
// FIXME: If we declare this inside of the while loop and then
704+
// break out of it before it's ever initialized (i.e. we don't run
705+
// any tests), then the cleanups will puke, so we're initializing it
706+
// here with defaults.
707+
let execparms = {
708+
lib_path: "",
709+
prog: "",
710+
args: ~[],
711+
// This works because a NULL box is ignored during cleanup
712+
respchan: unsafe::reinterpret_cast(0)
713+
};
714+
682715
while true {
683-
alt task::recv(p) {
684-
exec(lib_path, prog, args, respchan) {
685-
// This is copied from run::start_program
686-
let pipe_in = os::pipe();
687-
let pipe_out = os::pipe();
688-
let pipe_err = os::pipe();
689-
let spawnproc =
690-
bind run::spawn_process(prog, args, pipe_in.in,
691-
pipe_out.out, pipe_err.out);
692-
let pid = with_lib_path(lib_path, spawnproc);
693-
if pid == -1 { fail; }
694-
os::libc::close(pipe_in.in);
695-
os::libc::close(pipe_in.out);
696-
os::libc::close(pipe_out.out);
697-
os::libc::close(pipe_err.out);
698-
task::send(respchan,
699-
{pid: pid,
700-
outfd: pipe_out.in,
701-
errfd: pipe_err.in});
702-
}
703-
stop. { ret; }
704-
}
716+
// FIXME: Sending strings across channels seems to still
717+
// leave them refed on the sender's end, which causes problems if
718+
// the receiver's poniters outlive the sender's. Here we clone
719+
// everything and let the originals go out of scope before sending
720+
// a response.
721+
execparms = {
722+
// FIXME: The 'discriminant' of an alt expression has the
723+
// same scope as the alt expression itself, so we have to put
724+
// the entire alt in another block to make sure the exec
725+
// message goes out of scope. Seems like the scoping rules for
726+
// the alt discriminant are wrong.
727+
alt task::recv(p) {
728+
exec(lib_path, prog, args, respchan) {
729+
{
730+
lib_path: clone_str(lib_path),
731+
prog: clone_str(prog),
732+
args: clone_ivecstr(args),
733+
respchan: respchan
734+
}
735+
}
736+
stop. { ret }
737+
}
738+
};
739+
740+
// This is copied from run::start_program
741+
let pipe_in = os::pipe();
742+
let pipe_out = os::pipe();
743+
let pipe_err = os::pipe();
744+
let spawnproc =
745+
bind run::spawn_process(execparms.prog,
746+
ivec::to_vec(execparms.args),
747+
pipe_in.in,
748+
pipe_out.out,
749+
pipe_err.out);
750+
let pid = with_lib_path(execparms.lib_path, spawnproc);
751+
if pid == -1 { fail; }
752+
os::libc::close(pipe_in.in);
753+
os::libc::close(pipe_in.out);
754+
os::libc::close(pipe_out.out);
755+
os::libc::close(pipe_err.out);
756+
task::send(execparms.respchan,
757+
{pid: pid,
758+
outfd: pipe_out.in,
759+
errfd: pipe_err.in});
705760
}
706761
}
707762

0 commit comments

Comments
 (0)