Skip to content

Commit

Permalink
Safety comments
Browse files Browse the repository at this point in the history
  • Loading branch information
ecton committed Apr 3, 2024
1 parent 16bb0cf commit 174bbba
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 11 deletions.
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[package]
name = "refuse"
description = "An easy-to-use, incremental, multi-threaded garbage collector"
version = "0.0.1"
version = "0.0.2"
edition = "2021"
rust-version = "1.73.0"
repository = "https://github.com/khonsulabs/refuse"
Expand All @@ -17,7 +17,7 @@ flume = "0.11.0"
intentional = "0.1.1"
kempt = "0.2.4"
parking_lot = { version = "0.12.1" }
refuse-macros = { path = "./refuse-macros" }
refuse-macros = { path = "./refuse-macros", version = "=0.0.2" }

[lints]
rust.missing_docs = "warn"
Expand Down
7 changes: 5 additions & 2 deletions refuse-macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
[package]
name = "refuse-macros"
version = "0.1.0"
version = "0.0.2"
description = "Macros for the Refuse garbage collector"
edition = "2021"
rust-version = "1.73.0"
repository = "https://github.com/khonsulabs/refuse"
license = "MIT OR Apache-2.0"

[lib]
proc-macro = true

[dependencies]

syn = "2.0.52"
manyhow = "0.11.1"
attribute-derive = { version = "0.9.1" }
Expand Down
12 changes: 8 additions & 4 deletions refuse-pool/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
[package]
name = "refuse-pool"
version = "0.1.0"
version = "0.0.2"
description = "A string interner utilizing the Refuse garbage collector"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
rust-version = "1.73.0"
repository = "https://github.com/khonsulabs/refuse"
license = "MIT OR Apache-2.0"
categories = ["memory-management"]
keywords = ["symbols", "string-interner", "interner"]

[dependencies]
refuse = { path = "../" }
refuse = { path = "../", version = "=0.0.2" }
ahash = { version = "0.8.11", default-features = false, features = [
"runtime-rng",
] }
Expand Down
32 changes: 32 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,8 @@ impl Collector {
Some(
thread_bins
.iter()
// SAFETY: We have acquired all of the locks, so we can now gain
// exclusive access safely.
.map(|entry| (*entry.key(), unsafe { entry.value.bins.assume_mut() }))
.collect(),
)
Expand Down Expand Up @@ -582,21 +584,40 @@ thread_local! {
struct UnsafeBins(UnsafeCell<ManuallyDrop<Bins>>);

impl UnsafeBins {
/// # Safety
///
/// The caller of this function must ensure that no exclusive references
/// exist to this data.
unsafe fn assume_readable(&self) -> &Bins {
&*self.0.get()
}

/// # Safety
///
/// The caller of this function must ensure that no other references exist
/// to this data. For the design of this collector, this function should
/// only be called by the garbage collector thread after acquiring the lock
/// that contains this structure.
#[allow(clippy::mut_from_ref)]
unsafe fn assume_mut(&self) -> &mut Bins {
&mut *self.0.get()
}
}

// SAFETY: Auto-implementation is prevented by UnsafeCell. The contained type
// would be `Send`, and this crate takes care to ensure correct thread-safe
// access to the contents of the UnsafeCell.
unsafe impl Send for UnsafeBins {}
// SAFETY: Auto-implementation is prevented by UnsafeCell. The contained type
// would be `Send`, and this crate takes care to ensure correct thread-safe
// access to the contents of the UnsafeCell.
unsafe impl Sync for UnsafeBins {}

impl Drop for UnsafeBins {
fn drop(&mut self) {
// SAFETY: We never leave the contents of the unsafe cell in an invalid
// state, making it safe to invoke the drop function without any extra
// checks.
unsafe {
ManuallyDrop::drop(self.0.get_mut());
}
Expand Down Expand Up @@ -944,6 +965,9 @@ impl CollectionGuard<'static> {
impl CollectionGuard<'_> {
#[allow(clippy::unused_self)]
fn bins_for<'a>(&'a self, bins: &'a UnsafeBins) -> &'a Bins {
// SAFETY: We have read access ensuring the collector can't call
// `assume_mut()` while `self` exists. We can use this knowledge to
// safely create a reference tied to `self`'s lifetime.
unsafe { bins.assume_readable() }
}

Expand Down Expand Up @@ -2713,6 +2737,10 @@ impl AnyRoot {
T: Collectable,
{
if TypeIndex::of::<T>() == self.any.type_index {
// SAFETY: `self` has a root reference to the underlying data,
// ensuring that it cannot be collected while `self` exists. We've
// verified that `T` is the same underlying type. We can return a
// reference bound to `self`'s lifetime safely.
let rooted = unsafe { &*self.rooted.cast::<Rooted<T>>() };
Some(&rooted.value)
} else {
Expand All @@ -2728,6 +2756,8 @@ impl AnyRoot {

impl Clone for AnyRoot {
fn clone(&self) -> Self {
// SAFETY: `self` has a root reference to the underlying data, ensuring
// that it cannot be collected while `self` exists.
unsafe { &*self.roots }.fetch_add(1, Ordering::Acquire);
Self {
rooted: self.rooted,
Expand All @@ -2739,6 +2769,8 @@ impl Clone for AnyRoot {

impl Drop for AnyRoot {
fn drop(&mut self) {
// SAFETY: `self` has a root reference to the underlying data, ensuring
// that it cannot be collected while `self` exists.
if unsafe { &*self.roots }.fetch_sub(1, Ordering::Acquire) == 1 {
CollectorCommand::schedule_collect_if_needed();
}
Expand Down

0 comments on commit 174bbba

Please sign in to comment.