diff options
| author | Brian Anderson <banderson@mozilla.com> | 2011-07-28 23:24:07 -0700 |
|---|---|---|
| committer | Brian Anderson <banderson@mozilla.com> | 2011-07-29 14:36:56 -0700 |
| commit | b306a0d714215717c7cc2fbabd7fd74438fe77e5 (patch) | |
| tree | 97cf43ef93337f9d14e283aad658fd7611eaeb70 | |
| parent | f3df9f50ea8fb136767677821ce433bc7ec188fb (diff) | |
| download | rust-b306a0d714215717c7cc2fbabd7fd74438fe77e5.tar.gz rust-b306a0d714215717c7cc2fbabd7fd74438fe77e5.zip | |
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.
| -rw-r--r-- | src/test/compiletest/compiletest.rs | 117 |
1 files changed, 86 insertions, 31 deletions
diff --git a/src/test/compiletest/compiletest.rs b/src/test/compiletest/compiletest.rs index 1f5e4913414..0c1f85a4d85 100644 --- a/src/test/compiletest/compiletest.rs +++ b/src/test/compiletest/compiletest.rs @@ -11,6 +11,7 @@ import std::generic_os::getenv; import std::os; import std::run; import std::task; +import std::unsafe; tag mode { mode_compile_fail; mode_run_fail; mode_run_pass; } @@ -175,7 +176,6 @@ fn make_test(cx: &cx, testfile: &str, configport: &port[str]) -> ignore: header::is_test_ignored(cx.config, testfile)} } - /* So this is kind of crappy: @@ -223,7 +223,7 @@ fn closure_to_task(cx: cx, configport: port[str], testfn: &fn() ) -> task { cx.config.run_ignored, opt_str(cx.config.filter), opt_str(cx.config.runtool), opt_str(cx.config.rustcflags), cx.config.verbose, - procsrv::clone(cx.procsrv).chan, testfile); + task::clone_chan(cx.procsrv.chan), testfile); } 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) { if config.verbose { io::stdout().write_line(s); } } +fn clone_str(s: &str) -> str { + let new = s + ""; + // new should be a different pointer + let sptr: int = unsafe::reinterpret_cast(s); + let newptr: int = unsafe::reinterpret_cast(new); + assert sptr != newptr; + new +} + +fn clone_ivecstr(v: &str[]) -> str[] { + let r = ~[]; + for t: str in ivec::slice(v, 0u, ivec::len(v)) { + r += ~[clone_str(t)]; + } + ret r; +} + mod header { export test_props; @@ -396,10 +413,10 @@ mod runtest { log #fmt("running %s", testfile); let props = load_props(testfile); alt cx.config.mode { - mode_compile_fail. { run_cfail_test(cx, props, testfile); } - mode_run_fail. { run_rfail_test(cx, props, testfile); } - mode_run_pass. { run_rpass_test(cx, props, testfile); } - } + mode_compile_fail. { run_cfail_test(cx, props, testfile); } + mode_run_fail. { run_rfail_test(cx, props, testfile); } + mode_run_pass. { run_rpass_test(cx, props, testfile); } + } } fn run_cfail_test(cx: &cx, props: &test_props, testfile: &str) { @@ -622,7 +639,7 @@ mod procsrv { type handle = {task: option::t[task], chan: reqchan}; - tag request { exec(str, str, vec[str], chan[response]); stop; } + tag request { exec(str, str, str[], chan[response]); stop; } type response = {pid: int, outfd: int, errfd: int}; @@ -631,7 +648,7 @@ mod procsrv { let task = spawn fn(setupchan: chan[chan[request]]) { let reqport = port(); let reqchan = chan(reqport); - task::send(setupchan, reqchan); + task::send(setupchan, task::clone_chan(reqchan)); worker(reqport); } (chan(setupport)); ret {task: option::some(task), @@ -657,7 +674,10 @@ mod procsrv { {status: int, out: str, err: str} { let p = port[response](); let ch = chan(p); - task::send(handle.chan, exec(lib_path, prog, args, ch)); + task::send(handle.chan, exec(lib_path, + prog, + clone_ivecstr(ivec::from_vec(args)), + task::clone_chan(ch))); let resp = task::recv(p); let output = readclose(resp.outfd); let errput = readclose(resp.errfd); @@ -679,29 +699,64 @@ mod procsrv { } fn worker(p: port[request]) { + + // FIXME: If we declare this inside of the while loop and then + // break out of it before it's ever initialized (i.e. we don't run + // any tests), then the cleanups will puke, so we're initializing it + // here with defaults. + let execparms = { + lib_path: "", + prog: "", + args: ~[], + // This works because a NULL box is ignored during cleanup + respchan: unsafe::reinterpret_cast(0) + }; + while true { - alt task::recv(p) { - exec(lib_path, prog, args, respchan) { - // This is copied from run::start_program - let pipe_in = os::pipe(); - let pipe_out = os::pipe(); - let pipe_err = os::pipe(); - let spawnproc = - bind run::spawn_process(prog, args, pipe_in.in, - pipe_out.out, pipe_err.out); - let pid = with_lib_path(lib_path, spawnproc); - if pid == -1 { fail; } - os::libc::close(pipe_in.in); - os::libc::close(pipe_in.out); - os::libc::close(pipe_out.out); - os::libc::close(pipe_err.out); - task::send(respchan, - {pid: pid, - outfd: pipe_out.in, - errfd: pipe_err.in}); - } - stop. { ret; } - } + // FIXME: Sending strings across channels seems to still + // leave them refed on the sender's end, which causes problems if + // the receiver's poniters outlive the sender's. Here we clone + // everything and let the originals go out of scope before sending + // a response. + execparms = { + // FIXME: The 'discriminant' of an alt expression has the + // same scope as the alt expression itself, so we have to put + // the entire alt in another block to make sure the exec + // message goes out of scope. Seems like the scoping rules for + // the alt discriminant are wrong. + alt task::recv(p) { + exec(lib_path, prog, args, respchan) { + { + lib_path: clone_str(lib_path), + prog: clone_str(prog), + args: clone_ivecstr(args), + respchan: respchan + } + } + stop. { ret } + } + }; + + // This is copied from run::start_program + let pipe_in = os::pipe(); + let pipe_out = os::pipe(); + let pipe_err = os::pipe(); + let spawnproc = + bind run::spawn_process(execparms.prog, + ivec::to_vec(execparms.args), + pipe_in.in, + pipe_out.out, + pipe_err.out); + let pid = with_lib_path(execparms.lib_path, spawnproc); + if pid == -1 { fail; } + os::libc::close(pipe_in.in); + os::libc::close(pipe_in.out); + os::libc::close(pipe_out.out); + os::libc::close(pipe_err.out); + task::send(execparms.respchan, + {pid: pid, + outfd: pipe_out.in, + errfd: pipe_err.in}); } } |
