(index<- ) ./libstd/cleanup.rs
git branch: * master 5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
modified: Wed Apr 9 17:27:02 2014
1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 #![doc(hidden)]
12
13 use ptr;
14 use raw;
15
16 static RC_IMMORTAL : uint = 0x77777777;
17
18 /*
19 * Box annihilation
20 *
21 * This runs at task death to free all boxes.
22 */
23
24 unsafe fn each_live_alloc(read_next_before: bool,
25 f: |alloc: *mut raw::Box<()>| -> bool)
26 -> bool {
27 //! Walks the internal list of allocations
28
29 use rt::local_heap;
30
31 let mut alloc = local_heap::live_allocs();
32 while alloc != ptr::mut_null() {
33 let next_before = (*alloc).next;
34
35 if !f(alloc) {
36 return false;
37 }
38
39 if read_next_before {
40 alloc = next_before;
41 } else {
42 alloc = (*alloc).next;
43 }
44 }
45 return true;
46 }
47
48 #[cfg(unix)]
49 fn debug_mem() -> bool {
50 // FIXME: Need to port the environment struct to newsched
51 false
52 }
53
54 #[cfg(windows)]
55 fn debug_mem() -> bool {
56 false
57 }
58
59 /// Destroys all managed memory (i.e. @ boxes) held by the current task.
60 pub unsafe fn annihilate() {
61 use rt::local_heap::local_free;
62
63 let mut n_total_boxes = 0u;
64
65 // Pass 1: Make all boxes immortal.
66 //
67 // In this pass, nothing gets freed, so it does not matter whether
68 // we read the next field before or after the callback.
69 each_live_alloc(true, |alloc| {
70 n_total_boxes += 1;
71 (*alloc).ref_count = RC_IMMORTAL;
72 true
73 });
74
75 // Pass 2: Drop all boxes.
76 //
77 // In this pass, unique-managed boxes may get freed, but not
78 // managed boxes, so we must read the `next` field *after* the
79 // callback, as the original value may have been freed.
80 each_live_alloc(false, |alloc| {
81 let drop_glue = (*alloc).drop_glue;
82 let data = &mut (*alloc).data as *mut ();
83 drop_glue(data as *mut u8);
84 true
85 });
86
87 // Pass 3: Free all boxes.
88 //
89 // In this pass, managed boxes may get freed (but not
90 // unique-managed boxes, though I think that none of those are
91 // left), so we must read the `next` field before, since it will
92 // not be valid after.
93 each_live_alloc(true, |alloc| {
94 local_free(alloc as *u8);
95 true
96 });
97
98 if debug_mem() {
99 // We do logging here w/o allocation.
100 println!("total boxes annihilated: {}", n_total_boxes);
101 }
102 }