@@ -152,7 +152,7 @@ for the rust task is plenty for the C function to have.
152
152
153
153
A planned future improvement (net yet implemented at the time of this writing)
154
154
is to have a guard page at the end of every rust stack. No rust function will
155
- hit this guard page (due to rust 's usage of LLVM's __ morestack). The intention
155
+ hit this guard page (due to Rust 's usage of LLVM's ` __morestack ` ). The intention
156
156
for this unmapped page is to prevent infinite recursion in C from overflowing
157
157
onto other rust stacks. If the guard page is hit, then the process will be
158
158
terminated with a message saying that the guard page was hit.
@@ -166,30 +166,39 @@ the stack of the task which is spawned.
166
166
167
167
# Destructors
168
168
169
- Foreign libraries often hand off ownership of resources to the calling code,
170
- which should be wrapped in a destructor to provide safety and guarantee their
171
- release.
169
+ Foreign libraries often hand off ownership of resources to the calling code.
170
+ When this occurs, we must use Rust's destructors to provide safety and guarantee
171
+ the release of these resources (especially in the case of failure) .
172
172
173
- A type with the same functionality as owned boxes can be implemented by
174
- wrapping ` malloc ` and ` free ` :
173
+ As an example, we give a reimplementation of owned boxes by wrapping ` malloc `
174
+ and ` free ` :
175
175
176
176
~~~~
177
177
use std::cast;
178
178
use std::libc::{c_void, size_t, malloc, free};
179
179
use std::ptr;
180
180
use std::unstable::intrinsics;
181
181
182
- // a wrapper around the handle returned by the foreign code
182
+ // Define a wrapper around the handle returned by the foreign code.
183
+ // Unique<T> has the same semantics as ~T
183
184
pub struct Unique<T> {
185
+ // It contains a single raw, mutable pointer to the object in question.
184
186
priv ptr: *mut T
185
187
}
186
188
189
+ // Implement methods for creating and using the values in the box.
190
+ // NB: For simplicity and correctness, we require that T has kind Send
191
+ // (owned boxes relax this restriction, and can contain managed (GC) boxes).
192
+ // This is because, as implemented, the garbage collector would not know
193
+ // about any shared boxes stored in the malloc'd region of memory.
187
194
impl<T: Send> Unique<T> {
188
195
pub fn new(value: T) -> Unique<T> {
189
196
unsafe {
190
197
let ptr = malloc(std::mem::size_of::<T>() as size_t) as *mut T;
191
198
assert!(!ptr::is_null(ptr));
192
199
// `*ptr` is uninitialized, and `*ptr = value` would attempt to destroy it
200
+ // move_val_init moves a value into this memory without
201
+ // attempting to drop the original value.
193
202
intrinsics::move_val_init(&mut *ptr, value);
194
203
Unique{ptr: ptr}
195
204
}
@@ -206,12 +215,20 @@ impl<T: Send> Unique<T> {
206
215
}
207
216
}
208
217
218
+ // The key ingredient for safety, we associate a destructor with
219
+ // Unique<T>, making the struct manage the raw pointer: when the
220
+ // struct goes out of scope, it will automatically free the raw pointer.
221
+ // NB: This is an unsafe destructor, because rustc will not normally
222
+ // allow destructors to be associated with parametrized types, due to
223
+ // bad interaction with managed boxes. (With the Send restriction,
224
+ // we don't have this problem.)
209
225
#[unsafe_destructor]
210
226
impl<T: Send> Drop for Unique<T> {
211
227
fn drop(&mut self) {
212
228
unsafe {
213
- let x = intrinsics::init(); // dummy value to swap in
214
- // moving the object out is needed to call the destructor
229
+ let x = intrinsics::uninit(); // dummy value to swap in
230
+ // We need to move the object out of the box, so that
231
+ // the destructor is called (at the end of this scope.)
215
232
ptr::replace_ptr(self.ptr, x);
216
233
free(self.ptr as *c_void)
217
234
}
0 commit comments