Skip to content

Commit 5fda139

Browse files
committed
📝 refine StackBox impl
1 parent 6122c6a commit 5fda139

File tree

3 files changed

+65
-90
lines changed

3 files changed

+65
-90
lines changed

src/gen_impl.rs

Lines changed: 23 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
use std::any::Any;
77
use std::fmt;
88
use std::marker::PhantomData;
9-
use std::mem::ManuallyDrop;
109
use std::panic;
1110
use std::thread;
1211

@@ -22,8 +21,7 @@ pub const DEFAULT_STACK_SIZE: usize = 0x1000;
2221

2322
/// the generator type
2423
pub struct Generator<'a, A, T> {
25-
_stack: StackBox<Stack>,
26-
gen: ManuallyDrop<StackBox<GeneratorImpl<'a, A, T>>>,
24+
gen: StackBox<GeneratorImpl<'a, A, T>>,
2725
}
2826

2927
unsafe impl<A, T> Send for Generator<'static, A, T> {}
@@ -38,11 +36,8 @@ impl<'a, A, T> Generator<'a, A, T> {
3836
/// function is called twice on the same raw pointer.
3937
#[inline]
4038
pub unsafe fn from_raw(raw: *mut usize) -> Self {
41-
let g = StackBox::from_raw(raw as *mut GeneratorImpl<'a, A, T>);
42-
let stack_ptr = raw.offset(g.size() as isize + 2);
4339
Generator {
44-
_stack: StackBox::from_raw(stack_ptr as *mut Stack),
45-
gen: ManuallyDrop::new(g),
40+
gen: StackBox::from_raw(raw as *mut GeneratorImpl<'a, A, T>),
4641
}
4742
}
4843

@@ -95,12 +90,6 @@ impl<'a, A, T> fmt::Debug for Generator<'a, A, T> {
9590
}
9691
}
9792

98-
impl<'a, A, T> Drop for Generator<'a, A, T> {
99-
fn drop(&mut self) {
100-
unsafe { ManuallyDrop::drop(&mut self.gen) }
101-
}
102-
}
103-
10493
/// Generator helper
10594
pub struct Gn<A = ()> {
10695
dummy: PhantomData<A>,
@@ -124,13 +113,9 @@ impl<A> Gn<A> {
124113
T: 'a,
125114
A: 'a,
126115
{
127-
let mut stack = Stack::new(size);
128-
let mut g = GeneratorImpl::<A, T>::new(&mut stack);
129-
g.scoped_init(f);
130-
Generator {
131-
_stack: stack,
132-
gen: ManuallyDrop::new(g),
133-
}
116+
let mut gen = GeneratorImpl::<A, T>::new(Stack::new(size));
117+
gen.scoped_init(f);
118+
Generator { gen }
134119
}
135120
}
136121

@@ -151,14 +136,10 @@ impl<A: Any> Gn<A> {
151136
where
152137
F: FnOnce() -> T + 'a,
153138
{
154-
let mut stack = Stack::new(size);
155-
let mut g = GeneratorImpl::<A, T>::new(&mut stack);
156-
g.init_context();
157-
g.init_code(f);
158-
Generator {
159-
_stack: stack,
160-
gen: ManuallyDrop::new(g),
161-
}
139+
let mut gen = GeneratorImpl::<A, T>::new(Stack::new(size));
140+
gen.init_context();
141+
gen.init_code(f);
142+
Generator { gen }
162143
}
163144
}
164145

@@ -167,6 +148,8 @@ impl<A: Any> Gn<A> {
167148
pub struct GeneratorImpl<'a, A, T> {
168149
// run time context
169150
context: Context,
151+
// stack
152+
stack: Stack,
170153
// save the input
171154
para: Option<A>,
172155
// save the output
@@ -192,17 +175,19 @@ impl<'a, A: Any, T: Any> GeneratorImpl<'a, A, T> {
192175

193176
impl<'a, A, T> GeneratorImpl<'a, A, T> {
194177
/// create a new generator with specified stack size
195-
fn new(stack: &mut Stack) -> StackBox<Self> {
178+
fn new(mut stack: Stack) -> StackBox<Self> {
179+
// the stack box would finally dealloc the stack!
196180
unsafe {
197181
let mut stack_box = stack
198182
.alloc_uninit_box::<GeneratorImpl<'a, A, T>>()
199183
.assume_init();
200184

201185
stack_box.init(GeneratorImpl {
202186
para: None,
187+
stack,
203188
ret: None,
204189
f: None,
205-
context: Context::new(stack),
190+
context: Context::new(),
206191
phantom: PhantomData,
207192
});
208193
stack_box
@@ -244,11 +229,10 @@ impl<'a, A, T> GeneratorImpl<'a, A, T> {
244229

245230
// init the ref to 0 means that it's ready to start
246231
self.context._ref = 0;
247-
let stack = unsafe { &mut *self.context.stack };
248232
let ret = &mut self.ret as *mut _;
249233
let context = &mut self.context as *mut Context;
250234
// alloc the function on stack
251-
let func = StackBox::new_fn_once(stack, move || {
235+
let func = StackBox::new_fn_once(&mut self.stack, move || {
252236
let r = f();
253237
let ret = unsafe { &mut *ret };
254238
let _ref = unsafe { (*context)._ref };
@@ -262,10 +246,12 @@ impl<'a, A, T> GeneratorImpl<'a, A, T> {
262246

263247
self.f = Some(func);
264248

265-
let stk = unsafe { &*self.context.stack };
266-
self.context
267-
.regs
268-
.init_with(gen_init, 0, &mut self.f as *mut _ as *mut usize, stk);
249+
self.context.regs.init_with(
250+
gen_init,
251+
0,
252+
&mut self.f as *mut _ as *mut usize,
253+
&self.stack,
254+
);
269255
}
270256

271257
/// resume the generator
@@ -411,8 +397,7 @@ impl<'a, A, T> GeneratorImpl<'a, A, T> {
411397

412398
/// get stack total size and used size in word
413399
pub fn stack_usage(&self) -> (usize, usize) {
414-
let stack = unsafe { &*self.context.stack };
415-
(stack.size(), stack.get_used_size())
400+
(self.stack.size(), self.stack.get_used_size())
416401
}
417402
}
418403

src/rt.rs

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,11 @@ use std::mem::MaybeUninit;
77
use std::ptr;
88

99
use crate::reg_context::RegContext;
10-
use crate::stack::Stack;
1110

1211
thread_local!(
1312
/// each thread has it's own generator context stack
1413
static ROOT_CONTEXT: Box<Context> = {
15-
let mut root = Box::new(Context::empty());
14+
let mut root = Box::new(Context::new());
1615
let p = &mut *root as *mut _;
1716
root.parent = p; // init top to current
1817
root
@@ -50,8 +49,6 @@ pub struct Context {
5049
child: *mut Context,
5150
/// parent context
5251
pub parent: *mut Context,
53-
/// generator execution stack
54-
pub stack: *mut Stack,
5552
/// passed in para for send
5653
pub para: MaybeUninit<*mut dyn Any>,
5754
/// this is just a buffer for the return value
@@ -65,26 +62,10 @@ pub struct Context {
6562
}
6663

6764
impl Context {
68-
// create for root empty context
69-
fn empty() -> Self {
70-
Context {
71-
regs: RegContext::empty(),
72-
stack: ptr::null_mut(),
73-
para: MaybeUninit::zeroed(),
74-
ret: MaybeUninit::zeroed(),
75-
_ref: 1, // none zero means it's not running
76-
err: None,
77-
child: ptr::null_mut(),
78-
parent: ptr::null_mut(),
79-
local_data: ptr::null_mut(),
80-
}
81-
}
82-
8365
/// return a default generator context
84-
pub fn new(stack: &mut Stack) -> Context {
66+
pub fn new() -> Context {
8567
Context {
8668
regs: RegContext::empty(),
87-
stack,
8869
para: MaybeUninit::zeroed(),
8970
ret: MaybeUninit::zeroed(),
9071
_ref: 1, // none zero means it's not running

src/stack/mod.rs

Lines changed: 40 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@ const ALIGN: usize = std::mem::size_of::<StackBoxHeader>();
2222
const HEADER_SIZE: usize = std::mem::size_of::<StackBoxHeader>() / std::mem::size_of::<usize>();
2323

2424
struct StackBoxHeader {
25-
// track the stack offset, saved on stack
26-
offset: *mut usize,
25+
// track the stack
26+
stack: Stack,
2727
// track how big the data is (in usize)
2828
data_size: usize,
29+
// non zero dealloc the stack
30+
need_drop: usize,
2931
}
3032

3133
/// A pointer type for stack allocation.
@@ -36,7 +38,7 @@ pub struct StackBox<T> {
3638

3739
impl<T> StackBox<T> {
3840
/// create uninit stack box
39-
fn new_unint(stack: &mut Stack) -> MaybeUninit<Self> {
41+
fn new_unint(stack: &mut Stack, need_drop: usize) -> MaybeUninit<Self> {
4042
let offset = unsafe { &mut *stack.get_offset() };
4143
// alloc the data
4244
let layout = std::alloc::Layout::new::<T>();
@@ -54,7 +56,8 @@ impl<T> StackBox<T> {
5456
let mut header = ptr::NonNull::new_unchecked(stack.end() as *mut StackBoxHeader);
5557
let header = header.as_mut();
5658
header.data_size = data_size;
57-
header.offset = offset;
59+
header.need_drop = need_drop;
60+
header.stack = stack.shadow_clone();
5861
std::mem::MaybeUninit::new(StackBox { ptr })
5962
}
6063
}
@@ -76,11 +79,6 @@ impl<T> StackBox<T> {
7679
self.ptr.as_ptr()
7780
}
7881

79-
// get the stack ptr
80-
pub(crate) fn size(&self) -> usize {
81-
self.get_header().data_size
82-
}
83-
8482
/// Constructs a StackBox from a raw pointer.
8583
///
8684
/// # Safety
@@ -125,7 +123,7 @@ impl Drop for Func {
125123
if !self.data.is_null() {
126124
(self.drop)(self.data);
127125
}
128-
unsafe { *self.offset -= self.size }
126+
unsafe { *self.offset -= self.size };
129127
}
130128
}
131129

@@ -148,13 +146,13 @@ impl<F: FnOnce()> StackBox<F> {
148146
/// create a functor on the stack
149147
pub(crate) fn new_fn_once(stack: &mut Stack, data: F) -> Func {
150148
unsafe {
151-
let mut d = Self::new_unint(stack).assume_init();
149+
let mut d = Self::new_unint(stack, 0).assume_init();
152150
d.init(data);
153151
let header = d.get_header();
154152
let f = Func {
155153
data: d.ptr.as_ptr() as *mut (),
156154
size: header.data_size + HEADER_SIZE,
157-
offset: header.offset,
155+
offset: stack.get_offset(),
158156
func: Self::call_once,
159157
drop: Self::drop_inner,
160158
};
@@ -182,8 +180,11 @@ impl<T> Drop for StackBox<T> {
182180
fn drop(&mut self) {
183181
let header = self.get_header();
184182
unsafe {
185-
*header.offset -= header.data_size + HEADER_SIZE;
183+
*header.stack.get_offset() -= header.data_size + HEADER_SIZE;
186184
ptr::drop_in_place(self.ptr.as_ptr());
185+
if header.need_drop != 0 {
186+
header.stack.drop_stack();
187+
}
187188
}
188189
}
189190
}
@@ -301,13 +302,15 @@ impl SysStack {
301302
unsafe impl Send for SysStack {}
302303

303304
/// generator stack
305+
/// this struct will not dealloc the memroy
306+
/// instead StackBox<> would track it's usage and dealloc it
304307
pub struct Stack {
305308
buf: SysStack,
306309
}
307310

308311
impl Stack {
309312
/// Allocate a new stack of `size`. If size = 0, this is a `dummy_stack`
310-
pub fn new(size: usize) -> StackBox<Stack> {
313+
pub fn new(size: usize) -> Stack {
311314
let track = (size & 1) != 0;
312315
let mut bytes = size * std::mem::size_of::<usize>();
313316
// the minimal size
@@ -319,7 +322,7 @@ impl Stack {
319322

320323
let buf = SysStack::allocate(bytes, true).expect("failed to alloc sys stack");
321324

322-
let mut stk = Stack { buf };
325+
let stk = Stack { buf };
323326

324327
// if size is not even we do the full foot print test
325328
let count = if track {
@@ -333,15 +336,12 @@ impl Stack {
333336
let buf = stk.buf.bottom as *mut usize;
334337
ptr::write_bytes(buf, 0xEE, count);
335338
}
339+
336340
// init the stack box usage
337341
let offset = stk.get_offset();
338342
unsafe { *offset = 1 };
339343

340-
unsafe {
341-
let mut stack = stk.alloc_uninit_box::<Stack>().assume_init();
342-
stack.init(stk);
343-
stack
344-
}
344+
stk
345345
}
346346

347347
/// get used stack size
@@ -380,24 +380,17 @@ impl Stack {
380380

381381
/// alloc buffer on this stack
382382
pub fn alloc_uninit_box<T>(&mut self) -> MaybeUninit<StackBox<T>> {
383-
StackBox::<T>::new_unint(self)
383+
// the first obj should set need drop to non zero
384+
StackBox::<T>::new_unint(self, 1)
384385
}
385386

386387
// get offset
387388
fn get_offset(&self) -> *mut usize {
388389
unsafe { (self.buf.top as *mut usize).offset(-1) }
389390
}
390-
}
391391

392-
impl fmt::Debug for Stack {
393-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
394-
let offset = self.get_offset();
395-
write!(f, "Statck<{:?}, Offset={}>", self.buf, unsafe { *offset })
396-
}
397-
}
398-
399-
impl Drop for Stack {
400-
fn drop(&mut self) {
392+
// dealloc the statck
393+
fn drop_stack(&self) {
401394
if self.buf.len() == 0 {
402395
return;
403396
}
@@ -408,4 +401,20 @@ impl Drop for Stack {
408401
sys::deallocate_stack(guard, size_with_guard);
409402
}
410403
}
404+
405+
fn shadow_clone(&self) -> Self {
406+
Stack {
407+
buf: SysStack {
408+
top: self.buf.top,
409+
bottom: self.buf.bottom,
410+
},
411+
}
412+
}
413+
}
414+
415+
impl fmt::Debug for Stack {
416+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
417+
let offset = self.get_offset();
418+
write!(f, "Statck<{:?}, Offset={}>", self.buf, unsafe { *offset })
419+
}
411420
}

0 commit comments

Comments
 (0)