Skip to content

Commit b580bea

Browse files
committed
[simple] Only depend on parking_lot and crossbeam if feature="sync"
The single threaded collector doesn't need these dependencies. Alsp be more specific by requiring "crossbeam-utils" instead of all of "crossbeam". The only thing we care about right now is 'AtomicCell'
1 parent d6b410e commit b580bea

File tree

5 files changed

+72
-45
lines changed

5 files changed

+72
-45
lines changed

libs/context/Cargo.toml

Whitespace-only changes.

libs/simple/Cargo.toml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,10 @@ edition = "2018"
1212
zerogc = { path = "../..", version = "0.1.0" }
1313
once_cell = { version = "1.4.0", optional = true }
1414
# Concurrency
15-
# TODO: Make this optional for the single-threaded implementation
16-
parking_lot = { version = "0.10", features = ["nightly"] }
17-
crossbeam = { version = "0.7" }
15+
parking_lot = { version = "0.11", features = ["nightly"], optional = true }
16+
crossbeam-utils = { version = "0.8.1", optional = true }
1817
# Logging
19-
slog = "2.5"
18+
slog = "2.7"
2019

2120
[features]
2221
default = [
@@ -42,7 +41,10 @@ implicit-grey-stack = []
4241
# by creating a seperate context for each.
4342
#
4443
# This can increase overhead by requiring communication between threads.
45-
sync = []
44+
sync = [
45+
"parking_lot",
46+
"crossbeam-utils"
47+
]
4648
# Allow multiple collectors to exist at once
4749
# Otherwise, there's a single global collector (useful in VMs)
4850
#

libs/simple/src/alloc.rs

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
#![allow(clippy::vec_box)] // We must Box<Chunk> for a stable address
2-
use once_cell::sync::OnceCell;
32
use std::alloc::Layout;
4-
use crate::{GcHeader};
53
use std::mem;
64
use std::ptr::NonNull;
75
use std::mem::MaybeUninit;
6+
7+
#[cfg(feature = "sync")]
8+
use once_cell::sync::OnceCell;
9+
#[cfg(not(feature = "sync"))]
10+
use once_cell::unsync::OnceCell;
11+
#[cfg(feature = "sync")]
812
use parking_lot::Mutex;
9-
use crossbeam::atomic::AtomicCell;
13+
#[cfg(not(feature = "sync"))]
14+
use std::cell::RefCell;
15+
16+
use crate::{GcHeader};
17+
use crate::utils::AtomicCell;
1018

1119
/// The minimum size of supported memory (in words)
1220
///
@@ -136,7 +144,13 @@ struct ArenaState {
136144
/// This is required for thread safety.
137145
/// One thread could still be seeing an old chunk's location
138146
/// after it's been moved.
147+
#[cfg(feature = "sync")]
139148
chunks: Mutex<Vec<Box<Chunk>>>,
149+
/// List of chunks, not thread-safe
150+
///
151+
/// We still box it however, as an extra check of safety.
152+
#[cfg(not(feature = "sync"))]
153+
chunks: RefCell<Vec<Box<Chunk>>>,
140154
/// Lockless access to the current chunk
141155
///
142156
/// The pointers wont be invalidated,
@@ -147,16 +161,29 @@ impl ArenaState {
147161
fn new(chunks: Vec<Box<Chunk>>) -> Self {
148162
assert!(!chunks.is_empty());
149163
let current_chunk = NonNull::from(&**chunks.last().unwrap());
164+
let chunk_lock;
165+
#[cfg(feature = "sync")] {
166+
chunk_lock = Mutex::new(chunks);
167+
}
168+
#[cfg(not(feature = "sync"))] {
169+
chunk_lock = RefCell::new(chunks);
170+
}
150171
ArenaState {
151-
chunks: Mutex::new(chunks),
172+
chunks: chunk_lock,
152173
current_chunk: AtomicCell::new(current_chunk)
153174
}
154175
}
155176
#[inline]
177+
#[cfg(feature = "sync")]
156178
fn lock_chunks(&self) -> ::parking_lot::MutexGuard<Vec<Box<Chunk>>> {
157179
self.chunks.lock()
158180
}
159181
#[inline]
182+
#[cfg(not(feature = "sync"))]
183+
fn lock_chunks(&self) -> ::std::cell::RefMut<Vec<Box<Chunk>>> {
184+
self.chunks.borrow_mut()
185+
}
186+
#[inline]
160187
fn current_chunk(&self) -> NonNull<Chunk> {
161188
self.current_chunk.load()
162189
}

libs/simple/src/lib.rs

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -29,47 +29,14 @@ use std::sync::Arc;
2929
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering};
3030
#[cfg(not(feature = "multiple-collectors"))]
3131
use std::sync::atomic::AtomicPtr;
32-
#[cfg(not(feature = "sync"))]
33-
use std::cell::Cell;
34-
3532

3633
use slog::{Logger, FnValue, o, debug};
3734
use crate::context::{RawContext};
38-
use crate::utils::ThreadId;
35+
use crate::utils::{ThreadId, AtomicCell};
3936

4037
pub use crate::context::SimpleCollectorContext;
4138
use handles::GcHandleList;
4239

43-
#[cfg(feature = "sync")]
44-
type AtomicCell<T> = ::crossbeam::atomic::AtomicCell<T>;
45-
/// Fallback `AtomicCell` implementation when we actually
46-
/// don't care about thread safety
47-
#[cfg(not(feature = "sync"))]
48-
#[derive(Default)]
49-
struct AtomicCell<T>(Cell<T>);
50-
#[cfg(not(feature = "sync"))]
51-
impl<T: Copy> AtomicCell<T> {
52-
const fn new(value: T) -> Self {
53-
AtomicCell(Cell::new(value))
54-
}
55-
fn store(&self, value: T) {
56-
self.0.set(value)
57-
}
58-
fn load(&self) -> T {
59-
self.0.get()
60-
}
61-
fn compare_exchange(&self, expected: T, updated: T) -> Result<T, T>
62-
where T: PartialEq {
63-
let existing = self.0.get();
64-
if existing == expected {
65-
self.0.set(updated);
66-
Ok(existing)
67-
} else {
68-
Err(existing)
69-
}
70-
}
71-
}
72-
7340
mod handles;
7441
mod context;
7542
mod utils;

libs/simple/src/utils.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,36 @@
1-
use std::fmt::{Debug, Formatter};
2-
use std::fmt;
1+
use std::fmt::{self, Debug, Formatter};
2+
#[cfg(not(feature = "sync"))]
3+
use std::cell::Cell;
4+
5+
#[cfg(feature = "sync")]
6+
pub type AtomicCell<T> = ::crossbeam_utils::atomic::AtomicCell<T>;
7+
/// Fallback `AtomicCell` implementation when we actually
8+
/// don't care about thread safety
9+
#[cfg(not(feature = "sync"))]
10+
#[derive(Default)]
11+
pub struct AtomicCell<T>(Cell<T>);
12+
#[cfg(not(feature = "sync"))]
13+
impl<T: Copy> AtomicCell<T> {
14+
pub const fn new(value: T) -> Self {
15+
AtomicCell(Cell::new(value))
16+
}
17+
pub fn store(&self, value: T) {
18+
self.0.set(value)
19+
}
20+
pub fn load(&self) -> T {
21+
self.0.get()
22+
}
23+
pub fn compare_exchange(&self, expected: T, updated: T) -> Result<T, T>
24+
where T: PartialEq {
25+
let existing = self.0.get();
26+
if existing == expected {
27+
self.0.set(updated);
28+
Ok(existing)
29+
} else {
30+
Err(existing)
31+
}
32+
}
33+
}
334

435
#[derive(Clone)]
536
pub enum ThreadId {

0 commit comments

Comments
 (0)