Skip to content

Commit

Permalink
Add a test suite for programs using libgc + rustgc
Browse files Browse the repository at this point in the history
  • Loading branch information
jacob-hughes committed Apr 9, 2021
1 parent 70ae093 commit 17cf277
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 2 deletions.
10 changes: 10 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ gc_stats = []
libc = "*"
allocator = { path = "allocator", optional = true }

[dev-dependencies]
lang_tester = "0.3"
tempfile = "3.2"


[[test]]
name = "gc_tests"
path = "gc_tests/run_tests.rs"
harness = false

[build-dependencies]
rerun_except = "0.1"
num_cpus = "1.12"
Expand Down
67 changes: 67 additions & 0 deletions gc_tests/run_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use std::{env, path::PathBuf, process::Command};

use lang_tester::LangTester;
use tempfile::TempDir;

fn deps_path() -> String {
let mut path = PathBuf::new();
path.push(env::var("CARGO_MANIFEST_DIR").unwrap());
path.push("target");
#[cfg(debug_assertions)]
path.push("debug");
#[cfg(not(debug_assertions))]
path.push("release");
path.push("deps");

path.to_str().unwrap().to_owned()
}

fn main() {
let rustc = env::var("RUSTGC").expect("RUSTGC environment var not specified");
// We grab the rlibs from `target/<debug | release>/` but in order
// for them to exist here, they must have been moved from `deps/`.
// Simply running `cargo test` will not do this, instead, we must
// ensure that `cargo build` has been run before running the tests.

#[cfg(debug_assertions)]
let build_mode = "--debug";
#[cfg(not(debug_assertions))]
let build_mode = "--release";

Command::new("cargo")
.args(&["build", build_mode])
.env("RUSTC", &rustc.as_str())
.output()
.expect("Failed to build libs");

let tempdir = TempDir::new().unwrap();
LangTester::new()
.test_dir("gc_tests/tests")
.test_file_filter(|p| p.extension().unwrap().to_str().unwrap() == "rs")
.test_extract(|s| {
Some(
s.lines()
.take_while(|l| l.starts_with("//"))
.map(|l| &l[2..])
.collect::<Vec<_>>()
.join("\n"),
)
})
.test_cmds(move |p| {
let mut exe = PathBuf::new();
exe.push(&tempdir);
exe.push(p.file_stem().unwrap());

let mut compiler = Command::new(&rustc);
compiler.args(&[
"-L",
deps_path().as_str(),
p.to_str().unwrap(),
"-o",
exe.to_str().unwrap(),
]);

vec![("Compiler", compiler), ("Run-time", Command::new(exe))]
})
.run();
}
50 changes: 50 additions & 0 deletions gc_tests/tests/multithreaded.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Run-time:
// status: success
#![feature(rustc_private)]

extern crate libgc;

use std::alloc::GcAllocator;
use std::{thread, time};
use std::sync::atomic::{AtomicBool, Ordering};
use libgc::Gc;

#[global_allocator]
static ALLOCATOR: GcAllocator = GcAllocator;

struct PanicOnDrop(String);

impl Drop for PanicOnDrop {
fn drop(&mut self) {
eprintln!("Finalizer called. Object erroneously collected");
}

}

static mut NO_CHILD_EXISTS: AtomicBool = AtomicBool::new(true);

fn main() {
for _ in 1..10 {
thread::spawn(child);
}

while(unsafe { NO_CHILD_EXISTS.load(Ordering::SeqCst) }) {};

// This should collect no garbage, because the call stacks of each child
// thread should be scanned for roots.
GcAllocator::force_gc();

// If there's a problem, a finalizer will print to stderr. Lets wait an
// appropriate amount of time for this to happen.
thread::sleep(time::Duration::from_millis(10));
}

fn child() {
unsafe { NO_CHILD_EXISTS.store(false, Ordering::SeqCst)};
let gc = Gc::new(String::from("Hello world!"));

// Wait a bit before dying, ensuring that the thread stays alive long enough
// cross the force_gc call.
thread::sleep(time::Duration::from_millis(10));
}

7 changes: 5 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![cfg_attr(feature = "rustgc", feature(gc))]
#![cfg_attr(not(feature = "standalone"), feature(gc))]
#![cfg_attr(not(feature = "standalone"), feature(rustc_private))]
#![feature(core_intrinsics)]
#![feature(allocator_api)]
#![feature(alloc_layout_extra)]
Expand All @@ -23,7 +24,9 @@ pub mod stats;
#[cfg(feature = "standalone")]
pub use allocator::GcAllocator;

#[cfg(not(feature = "standalone"))]
pub use std::alloc::GcAllocator;

pub use gc::Gc;

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

0 comments on commit 17cf277

Please sign in to comment.