Skip to content

Commit bc96ea2

Browse files
committed
libcore: Implement a box annihilator, not called yet
1 parent 7107b4e commit bc96ea2

File tree

3 files changed

+158
-0
lines changed

3 files changed

+158
-0
lines changed

src/libcore/cleanup.rs

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
use libc::{c_char, c_void, intptr_t, uintptr_t};
2+
use ptr::{mut_null, null, to_unsafe_ptr};
3+
use repr::BoxRepr;
4+
use rt::rt_free;
5+
use sys::TypeDesc;
6+
use unsafe::transmute;
7+
8+
/**
9+
* Runtime structures
10+
*
11+
* NB: These must match the representation in the C++ runtime.
12+
*/
13+
14+
type DropGlue = fn(**TypeDesc, *c_void);
15+
type FreeGlue = fn(**TypeDesc, *c_void);
16+
17+
type TaskID = uintptr_t;
18+
19+
struct StackSegment { priv opaque: () }
20+
struct Scheduler { priv opaque: () }
21+
struct SchedulerLoop { priv opaque: () }
22+
struct Kernel { priv opaque: () }
23+
struct Env { priv opaque: () }
24+
struct AllocHeader { priv opaque: () }
25+
struct MemoryRegion { priv opaque: () }
26+
27+
// XXX: i386
28+
struct Registers {
29+
data: [u64 * 22]
30+
}
31+
32+
struct Context {
33+
regs: Registers,
34+
next: *Context,
35+
pad: u64
36+
}
37+
38+
struct BoxedRegion {
39+
env: *Env,
40+
backing_region: *MemoryRegion,
41+
live_allocs: *BoxRepr
42+
}
43+
44+
struct Task {
45+
// Public fields
46+
refcount: intptr_t,
47+
id: TaskID,
48+
ctx: Context,
49+
stack_segment: *StackSegment,
50+
runtime_sp: uintptr_t,
51+
scheduler: *Scheduler,
52+
scheduler_loop: *SchedulerLoop,
53+
54+
// Fields known only to the runtime
55+
kernel: *Kernel,
56+
name: *c_char,
57+
list_index: *i32,
58+
rendezvous_ptr: *uintptr_t,
59+
boxed_region: BoxedRegion
60+
}
61+
62+
/*
63+
* Box annihilation
64+
*
65+
* This runs at task death to free all boxes.
66+
*/
67+
68+
/// Destroys all managed memory (i.e. @ boxes) held by the current task.
69+
pub unsafe fn annihilate() {
70+
let task: *Task = transmute(rustrt::rust_get_task());
71+
72+
// Pass 1: Make all boxes immortal.
73+
let box = (*task).boxed_region.live_allocs;
74+
let mut box: *mut BoxRepr = transmute(copy box);
75+
assert (*box).prev == null();
76+
while box != mut_null() {
77+
debug!("making box immortal: %x", box as uint);
78+
(*box).ref_count = 0x77777777;
79+
box = transmute(copy (*box).next);
80+
}
81+
82+
// Pass 2: Drop all boxes.
83+
let box = (*task).boxed_region.live_allocs;
84+
let mut box: *mut BoxRepr = transmute(copy box);
85+
assert (*box).prev == null();
86+
while box != mut_null() {
87+
debug!("calling drop glue for box: %x", box as uint);
88+
let tydesc: *TypeDesc = transmute(copy (*box).type_desc);
89+
let drop_glue: DropGlue = transmute(((*tydesc).drop_glue, 0));
90+
drop_glue(to_unsafe_ptr(&tydesc), transmute(&(*box).data));
91+
92+
box = transmute(copy (*box).next);
93+
}
94+
95+
// Pass 3: Free all boxes.
96+
loop {
97+
let box = (*task).boxed_region.live_allocs;
98+
if box == null() { break; }
99+
let mut box: *mut BoxRepr = transmute(copy box);
100+
assert (*box).prev == null();
101+
102+
debug!("freeing box: %x", box as uint);
103+
rt_free(transmute(box));
104+
}
105+
}
106+
107+
/// Bindings to the runtime
108+
extern mod rustrt {
109+
#[rust_stack]
110+
/*priv*/ fn rust_get_task() -> *c_void;
111+
}
112+
113+
/*
114+
* Tests
115+
*/
116+
117+
#[cfg(test)]
118+
mod tests {
119+
/*struct Knot {
120+
mut a: Option<@Knot>
121+
}
122+
123+
struct Blah {
124+
x: int,
125+
drop { io::println("Blah!"); }
126+
}
127+
128+
#[test]
129+
fn test_box_annihilation() {
130+
let knot = @Knot { a: None };
131+
knot.a = Some(knot);
132+
133+
let x = @~"foo";
134+
135+
let blah = @Blah { x: 3 };
136+
137+
let f_ref = @mut None;
138+
let f = || { util::ignore(f_ref); };
139+
*f_ref = Some(f);
140+
141+
unsafe { annihilate(); }
142+
143+
unsafe {
144+
unsafe::forget(knot);
145+
unsafe::forget(x);
146+
unsafe::forget(blah);
147+
unsafe::forget(f_ref);
148+
unsafe::forget(f);
149+
}
150+
}*/
151+
}
152+

src/libcore/core.rc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ mod unicode;
244244
mod private;
245245
mod cmath;
246246
mod stackwalk;
247+
mod cleanup;
247248

248249
// Local Variables:
249250
// mode: rust;

src/libcore/ptr.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export offset;
99
export const_offset;
1010
export mut_offset;
1111
export null;
12+
export mut_null;
1213
export is_null;
1314
export is_not_null;
1415
export memcpy;
@@ -98,6 +99,10 @@ unsafe fn position<T>(buf: *T, f: fn(T) -> bool) -> uint {
9899
#[inline(always)]
99100
pure fn null<T>() -> *T { unsafe { unsafe::reinterpret_cast(&0u) } }
100101

102+
/// Create an unsafe mutable null pointer
103+
#[inline(always)]
104+
pure fn mut_null<T>() -> *mut T { unsafe { unsafe::reinterpret_cast(&0u) } }
105+
101106
/// Returns true if the pointer is equal to the null pointer.
102107
pure fn is_null<T>(ptr: *const T) -> bool { ptr == null() }
103108

0 commit comments

Comments
 (0)