Skip to content

Commit ba304c1

Browse files
committed
src: Implement a pool allocator for execution stacks
1 parent 4870e64 commit ba304c1

File tree

3 files changed

+61
-5
lines changed

3 files changed

+61
-5
lines changed

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ mod preemption;
1212
pub mod profiler;
1313
mod reusable;
1414
mod signals;
15+
mod stacks;
1516
mod timer;
1617
mod unfurl;
1718

src/linger.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ use reusable::ReusableSync;
77
use signal::Set;
88
use signal::Signal;
99
use signal::siginfo_t;
10+
use stacks::DerefAdapter;
1011
use super::QUANTUM_MICROSECS;
11-
use super::STACK_SIZE_BYTES;
1212
use std::cell::Cell;
1313
use std::cell::RefCell;
1414
use std::io::Result;
@@ -87,7 +87,7 @@ struct Task {
8787
// * None at end of resume() means it has completed.
8888
// * Some at either point means it timed out and is currently paused.
8989
errno: Option<c_int>,
90-
checkpoint: Option<Context<Box<[u8]>>>,
90+
checkpoint: Option<Context<DerefAdapter<'static, ReusableSync<'static, Box<[u8]>>>>>,
9191
yielded: bool,
9292
}
9393

@@ -153,7 +153,7 @@ pub fn launch<T: Send>(fun: impl FnOnce() -> T + Send, us: u64)
153153
}
154154
});
155155

156-
let checkpoint = setup_stack(STACK_SIZE_BYTES)?;
156+
let checkpoint = setup_stack()?;
157157
let mut linger = Linger::Continuation(Continuation {
158158
functional: fun,
159159
stateful: Task {
@@ -232,12 +232,14 @@ pub fn resume<T>(fun: &mut Linger<T, impl FnMut(*mut Option<ThdResult<T>>) + Sen
232232

233233
/// Set up the oneshot execution stack. Always returns a Some when things are Ok.
234234
#[inline(never)]
235-
fn setup_stack(bytes: usize) -> Result<Option<Context<Box<[u8]>>>> {
235+
fn setup_stack()
236+
-> Result<Option<Context<DerefAdapter<'static, ReusableSync<'static, Box<[u8]>>>>>> {
237+
use stacks::alloc_stack;
236238
use timetravel::makecontext;
237239

238240
let mut checkpoint = None;
239241
makecontext(
240-
vec![0; bytes].into_boxed_slice(),
242+
DerefAdapter::from(alloc_stack()),
241243
|goto| drop(checkpoint.replace(goto)),
242244
schedule,
243245
)?;

src/stacks.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
use std::marker::PhantomData;
2+
use std::ops::Deref;
3+
use std::ops::DerefMut;
4+
use super::STACK_SIZE_BYTES;
5+
use timetravel::stable::StableAddr;
6+
use timetravel::stable::StableMutAddr;
7+
use reusable::ReusableSync;
8+
9+
pub fn alloc_stack() -> ReusableSync<'static, Box<[u8]>> {
10+
use compile_assert::assert_sync;
11+
use reusable::SyncPool;
12+
use std::convert::TryInto;
13+
use std::sync::Once;
14+
15+
static mut STACKS: Option<SyncPool<Box<[u8]>>> = None;
16+
static INIT: Once = Once::new();
17+
INIT.call_once(|| unsafe {
18+
STACKS.replace(SyncPool::new(|| Some(vec![0; STACK_SIZE_BYTES].into_boxed_slice())));
19+
});
20+
21+
let stacks = unsafe {
22+
STACKS.as_ref()
23+
}.unwrap();
24+
assert_sync(&stacks);
25+
stacks.try_into().expect("libinger: stack allocator lock is poisoned")
26+
}
27+
28+
pub struct DerefAdapter<'a, T> (T, PhantomData<&'a ()>);
29+
30+
impl<T> From<T> for DerefAdapter<'_, T> {
31+
fn from(t: T) -> Self {
32+
Self (t, PhantomData::default())
33+
}
34+
}
35+
36+
impl<'a, T: Deref<Target = U>, U: Deref<Target = V> + 'a, V: ?Sized> Deref for DerefAdapter<'a, T> {
37+
type Target = V;
38+
39+
fn deref(&self) -> &Self::Target {
40+
let Self (t, _) = self;
41+
&***t
42+
}
43+
}
44+
45+
impl<'a, T: DerefMut<Target = U>, U: DerefMut<Target = V> + 'a, V: ?Sized> DerefMut for DerefAdapter<'a, T> {
46+
fn deref_mut(&mut self) -> &mut Self::Target {
47+
let Self (t, _) = self;
48+
&mut ***t
49+
}
50+
}
51+
52+
unsafe impl<'a, T: Deref<Target = U>, U: StableAddr + 'a> StableAddr for DerefAdapter<'a, T> {}
53+
unsafe impl<'a, T: DerefMut<Target = U>, U: StableMutAddr + 'a> StableMutAddr for DerefAdapter<'a, T> {}

0 commit comments

Comments
 (0)