Skip to content

Commit 17cf277

Browse files
committed
Add a test suite for programs using libgc + rustgc
1 parent 70ae093 commit 17cf277

File tree

4 files changed

+132
-2
lines changed

4 files changed

+132
-2
lines changed

Cargo.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,16 @@ gc_stats = []
1717
libc = "*"
1818
allocator = { path = "allocator", optional = true }
1919

20+
[dev-dependencies]
21+
lang_tester = "0.3"
22+
tempfile = "3.2"
23+
24+
25+
[[test]]
26+
name = "gc_tests"
27+
path = "gc_tests/run_tests.rs"
28+
harness = false
29+
2030
[build-dependencies]
2131
rerun_except = "0.1"
2232
num_cpus = "1.12"

gc_tests/run_tests.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
use std::{env, path::PathBuf, process::Command};
2+
3+
use lang_tester::LangTester;
4+
use tempfile::TempDir;
5+
6+
fn deps_path() -> String {
7+
let mut path = PathBuf::new();
8+
path.push(env::var("CARGO_MANIFEST_DIR").unwrap());
9+
path.push("target");
10+
#[cfg(debug_assertions)]
11+
path.push("debug");
12+
#[cfg(not(debug_assertions))]
13+
path.push("release");
14+
path.push("deps");
15+
16+
path.to_str().unwrap().to_owned()
17+
}
18+
19+
fn main() {
20+
let rustc = env::var("RUSTGC").expect("RUSTGC environment var not specified");
21+
// We grab the rlibs from `target/<debug | release>/` but in order
22+
// for them to exist here, they must have been moved from `deps/`.
23+
// Simply running `cargo test` will not do this, instead, we must
24+
// ensure that `cargo build` has been run before running the tests.
25+
26+
#[cfg(debug_assertions)]
27+
let build_mode = "--debug";
28+
#[cfg(not(debug_assertions))]
29+
let build_mode = "--release";
30+
31+
Command::new("cargo")
32+
.args(&["build", build_mode])
33+
.env("RUSTC", &rustc.as_str())
34+
.output()
35+
.expect("Failed to build libs");
36+
37+
let tempdir = TempDir::new().unwrap();
38+
LangTester::new()
39+
.test_dir("gc_tests/tests")
40+
.test_file_filter(|p| p.extension().unwrap().to_str().unwrap() == "rs")
41+
.test_extract(|s| {
42+
Some(
43+
s.lines()
44+
.take_while(|l| l.starts_with("//"))
45+
.map(|l| &l[2..])
46+
.collect::<Vec<_>>()
47+
.join("\n"),
48+
)
49+
})
50+
.test_cmds(move |p| {
51+
let mut exe = PathBuf::new();
52+
exe.push(&tempdir);
53+
exe.push(p.file_stem().unwrap());
54+
55+
let mut compiler = Command::new(&rustc);
56+
compiler.args(&[
57+
"-L",
58+
deps_path().as_str(),
59+
p.to_str().unwrap(),
60+
"-o",
61+
exe.to_str().unwrap(),
62+
]);
63+
64+
vec![("Compiler", compiler), ("Run-time", Command::new(exe))]
65+
})
66+
.run();
67+
}

gc_tests/tests/multithreaded.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Run-time:
2+
// status: success
3+
#![feature(rustc_private)]
4+
5+
extern crate libgc;
6+
7+
use std::alloc::GcAllocator;
8+
use std::{thread, time};
9+
use std::sync::atomic::{AtomicBool, Ordering};
10+
use libgc::Gc;
11+
12+
#[global_allocator]
13+
static ALLOCATOR: GcAllocator = GcAllocator;
14+
15+
struct PanicOnDrop(String);
16+
17+
impl Drop for PanicOnDrop {
18+
fn drop(&mut self) {
19+
eprintln!("Finalizer called. Object erroneously collected");
20+
}
21+
22+
}
23+
24+
static mut NO_CHILD_EXISTS: AtomicBool = AtomicBool::new(true);
25+
26+
fn main() {
27+
for _ in 1..10 {
28+
thread::spawn(child);
29+
}
30+
31+
while(unsafe { NO_CHILD_EXISTS.load(Ordering::SeqCst) }) {};
32+
33+
// This should collect no garbage, because the call stacks of each child
34+
// thread should be scanned for roots.
35+
GcAllocator::force_gc();
36+
37+
// If there's a problem, a finalizer will print to stderr. Lets wait an
38+
// appropriate amount of time for this to happen.
39+
thread::sleep(time::Duration::from_millis(10));
40+
}
41+
42+
fn child() {
43+
unsafe { NO_CHILD_EXISTS.store(false, Ordering::SeqCst)};
44+
let gc = Gc::new(String::from("Hello world!"));
45+
46+
// Wait a bit before dying, ensuring that the thread stays alive long enough
47+
// cross the force_gc call.
48+
thread::sleep(time::Duration::from_millis(10));
49+
}
50+

src/lib.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
#![cfg_attr(feature = "rustgc", feature(gc))]
1+
#![cfg_attr(not(feature = "standalone"), feature(gc))]
2+
#![cfg_attr(not(feature = "standalone"), feature(rustc_private))]
23
#![feature(core_intrinsics)]
34
#![feature(allocator_api)]
45
#![feature(alloc_layout_extra)]
@@ -23,7 +24,9 @@ pub mod stats;
2324
#[cfg(feature = "standalone")]
2425
pub use allocator::GcAllocator;
2526

27+
#[cfg(not(feature = "standalone"))]
28+
pub use std::alloc::GcAllocator;
29+
2630
pub use gc::Gc;
2731

28-
#[cfg(feature = "standalone")]
2932
pub static ALLOCATOR: GcAllocator = GcAllocator;

0 commit comments

Comments
 (0)