about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2011-07-28 23:24:07 -0700
committerBrian Anderson <banderson@mozilla.com>2011-07-29 14:36:56 -0700
commitb306a0d714215717c7cc2fbabd7fd74438fe77e5 (patch)
tree97cf43ef93337f9d14e283aad658fd7611eaeb70
parentf3df9f50ea8fb136767677821ce433bc7ec188fb (diff)
downloadrust-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.rs117
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});
         }
     }