forked from GitHub/bdwgc-rust
@@ -0,0 +1,25 @@
|
||||
[package]
|
||||
name = "bdwgc-alloc-sys"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
description = "Rust bindings to the bdwgc C API"
|
||||
documentation = "https://bdwgc.github.io/bdwgc-rust/bdwgc_alloc_sys/"
|
||||
repository.workspace = true
|
||||
license.workspace = true
|
||||
categories = ["external-ffi-bindings", "memory-management", "no-std", "no-std::no-alloc"]
|
||||
links = "gc"
|
||||
|
||||
[build-dependencies]
|
||||
autotools = { version = "0.2.7", optional = true }
|
||||
bindgen = "0.73.2"
|
||||
cmake = { version = "0.1.58", optional = true }
|
||||
|
||||
[features]
|
||||
default = ["autotools"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[[test]]
|
||||
name = "collector"
|
||||
harness = false
|
||||
@@ -0,0 +1,28 @@
|
||||
# bdwgc-alloc-sys
|
||||
|
||||
[](https://github.com/bdwgc/bdwgc-rust/actions)
|
||||
[](https://github.com/bdwgc/bdwgc-rust/blob/main/LICENSE)
|
||||
|
||||
Rust bindings to the C API of [`bdwgc`][bdwgc], the conservative garbage collector.
|
||||
|
||||
This crate builds [`bdwgc`][bdwgc] from its vendored source and links it statically. The bindings are generated from its headers at build time by [`bindgen`](https://github.com/rust-lang/rust-bindgen), which requires `libclang`.
|
||||
|
||||
See the [`bdwgc-alloc`](https://crates.io/crates/bdwgc-alloc) crate for a [`GlobalAlloc`](https://doc.rust-lang.org/std/alloc/trait.GlobalAlloc.html) implementation on top of these bindings.
|
||||
|
||||
## Install
|
||||
|
||||
```sh
|
||||
cargo add bdwgc-alloc-sys
|
||||
```
|
||||
|
||||
By default [`bdwgc`][bdwgc] is built with autotools. To build with cmake, enable the `cmake` feature:
|
||||
|
||||
```sh
|
||||
cargo add bdwgc-alloc-sys --no-default-features --features cmake
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
[MIT](https://github.com/bdwgc/bdwgc-rust/blob/main/LICENSE)
|
||||
|
||||
[bdwgc]: https://github.com/bdwgc/bdwgc
|
||||
@@ -0,0 +1,96 @@
|
||||
//! A build script.
|
||||
|
||||
use core::error::Error;
|
||||
use std::{env, path::PathBuf};
|
||||
|
||||
const LIB_ATOMIC_OPS_DIR: &str = "vendor/libatomic_ops";
|
||||
const LIB_GC_DIR: &str = "vendor/bdwgc";
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
build_library()?;
|
||||
|
||||
bindgen::builder()
|
||||
.header(format!("{LIB_GC_DIR}/include/gc.h"))
|
||||
.clang_arg(format!("-I{LIB_GC_DIR}/include"))
|
||||
.clang_arg("-DGC_THREADS")
|
||||
.use_core()
|
||||
.allowlist_item("GC_.*")
|
||||
.default_macro_constant_type(bindgen::MacroTypeVariation::Signed)
|
||||
.generate()?
|
||||
.write_to_file(PathBuf::from(env::var("OUT_DIR")?).join("bindings.rs"))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
cfg_select! {
|
||||
feature = "cmake" => {
|
||||
fn build_library() -> Result<(), Box<dyn Error>> {
|
||||
use cmake::Config;
|
||||
use std::path::Path;
|
||||
|
||||
let libatomic_include_path = Path::new(LIB_ATOMIC_OPS_DIR)
|
||||
.join("src")
|
||||
.canonicalize()?
|
||||
.display()
|
||||
.to_string()
|
||||
.replace(r"\\?\", "");
|
||||
|
||||
let dst = Config::new(LIB_GC_DIR)
|
||||
.profile("Release")
|
||||
.define("GC_BUILD_SHARED_LIBS", "FALSE")
|
||||
.cflag(format!("-I{}", libatomic_include_path))
|
||||
.build();
|
||||
|
||||
println!(
|
||||
"cargo:rustc-link-search=native={}",
|
||||
dst.join("lib").display()
|
||||
);
|
||||
println!("cargo:rustc-link-lib=static=gc");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
feature = "autotools" => {
|
||||
fn build_library() -> Result<(), Box<dyn Error>> {
|
||||
for dir in &[LIB_ATOMIC_OPS_DIR, LIB_GC_DIR] {
|
||||
std::process::Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(format!("cd {dir} && ./autogen.sh"))
|
||||
.output()?;
|
||||
}
|
||||
|
||||
let dst = autotools::Config::new(LIB_ATOMIC_OPS_DIR)
|
||||
.cflag("-fPIC")
|
||||
.build();
|
||||
|
||||
println!(
|
||||
"cargo:rustc-link-search=native={}",
|
||||
dst.join("lib").display()
|
||||
);
|
||||
println!("cargo:rustc-link-lib=static=atomic_ops");
|
||||
|
||||
let dst = autotools::Config::new(LIB_GC_DIR)
|
||||
.cflag(format!(
|
||||
// spell-checker: disable-next-line
|
||||
"-I{} -L/lib/x86_64-linux-gnu -lpthread -fPIC",
|
||||
dst.join("include").display()
|
||||
))
|
||||
.build();
|
||||
|
||||
println!(
|
||||
"cargo:rustc-link-search=native={}",
|
||||
dst.join("lib").display()
|
||||
);
|
||||
println!("cargo:rustc-link-lib=static=gc");
|
||||
|
||||
for dir in &[LIB_ATOMIC_OPS_DIR, LIB_GC_DIR] {
|
||||
std::process::Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(format!("cd {dir} && git clean -dfx"))
|
||||
.output()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![no_std]
|
||||
#![allow(missing_docs)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(non_upper_case_globals)]
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
||||
@@ -0,0 +1,76 @@
|
||||
//! A smoke test of the bindings.
|
||||
|
||||
use bdwgc_alloc_sys::{
|
||||
GC_SUCCESS, GC_allow_register_threads, GC_free, GC_gcollect, GC_get_stack_base, GC_init,
|
||||
GC_malloc, GC_realloc, GC_register_finalizer, GC_register_my_thread, GC_stack_base,
|
||||
GC_unregister_my_thread,
|
||||
};
|
||||
use core::{
|
||||
ffi::c_void,
|
||||
ptr::null_mut,
|
||||
sync::atomic::{AtomicUsize, Ordering},
|
||||
};
|
||||
use std::thread::spawn;
|
||||
|
||||
const TOTAL_COUNT: usize = 1 << 10;
|
||||
|
||||
static FINALIZED_COUNT: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
GC_init();
|
||||
GC_allow_register_threads();
|
||||
}
|
||||
|
||||
allocate();
|
||||
finalize();
|
||||
register_thread();
|
||||
}
|
||||
|
||||
fn allocate() {
|
||||
let ptr = unsafe { GC_malloc(42) };
|
||||
assert!(!ptr.is_null());
|
||||
|
||||
let ptr = unsafe { GC_realloc(ptr, 84) };
|
||||
assert!(!ptr.is_null());
|
||||
|
||||
unsafe { GC_free(ptr) };
|
||||
}
|
||||
|
||||
fn finalize() {
|
||||
extern "C" fn count(_object: *mut c_void, _client_data: *mut c_void) {
|
||||
FINALIZED_COUNT.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
for _ in 0..TOTAL_COUNT {
|
||||
unsafe {
|
||||
GC_register_finalizer(
|
||||
GC_malloc(42),
|
||||
Some(count),
|
||||
null_mut(),
|
||||
null_mut(),
|
||||
null_mut(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe { GC_gcollect() };
|
||||
|
||||
// TODO Is there any way to collect all?
|
||||
assert!(FINALIZED_COUNT.load(Ordering::Relaxed) > TOTAL_COUNT / 2);
|
||||
}
|
||||
|
||||
fn register_thread() {
|
||||
spawn(|| {
|
||||
let mut base = GC_stack_base {
|
||||
mem_base: null_mut(),
|
||||
};
|
||||
|
||||
assert_eq!(unsafe { GC_get_stack_base(&mut base) }, GC_SUCCESS);
|
||||
assert_eq!(unsafe { GC_register_my_thread(&base) }, GC_SUCCESS);
|
||||
assert!(!unsafe { GC_malloc(42) }.is_null());
|
||||
assert_eq!(unsafe { GC_unregister_my_thread() }, GC_SUCCESS);
|
||||
})
|
||||
.join()
|
||||
.unwrap();
|
||||
}
|
||||
+1
Submodule bdwgc-alloc-sys/vendor/bdwgc added at 2547e33aa8
+1
Submodule bdwgc-alloc-sys/vendor/libatomic_ops added at d007246aa7
Reference in New Issue
Block a user