]> git.lizzy.rs Git - rust.git/blob - src/libstd/cleanup.rs
auto merge of #10977 : brson/rust/androidtest, r=brson
[rust.git] / src / libstd / cleanup.rs
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 libc::c_void;
14 use ptr;
15 use unstable::intrinsics::TyDesc;
16 use unstable::raw;
17
18 type DropGlue<'a> = 'a |**TyDesc, *c_void|;
19
20 /*
21  * Box annihilation
22  *
23  * This runs at task death to free all boxes.
24  */
25
26 struct AnnihilateStats {
27     n_total_boxes: uint,
28     n_unique_boxes: uint,
29     n_bytes_freed: uint
30 }
31
32 unsafe fn each_live_alloc(read_next_before: bool,
33                           f: |alloc: *mut raw::Box<()>, uniq: bool| -> bool)
34                           -> bool {
35     //! Walks the internal list of allocations
36
37     use managed;
38     use rt::local_heap;
39
40     let mut alloc = local_heap::live_allocs();
41     while alloc != ptr::mut_null() {
42         let next_before = (*alloc).next;
43         let uniq = (*alloc).ref_count == managed::RC_MANAGED_UNIQUE;
44
45         if !f(alloc as *mut raw::Box<()>, uniq) {
46             return false;
47         }
48
49         if read_next_before {
50             alloc = next_before;
51         } else {
52             alloc = (*alloc).next;
53         }
54     }
55     return true;
56 }
57
58 #[cfg(unix)]
59 fn debug_mem() -> bool {
60     // XXX: Need to port the environment struct to newsched
61     false
62 }
63
64 #[cfg(windows)]
65 fn debug_mem() -> bool {
66     false
67 }
68
69 /// Destroys all managed memory (i.e. @ boxes) held by the current task.
70 pub unsafe fn annihilate() {
71     use rt::local_heap::local_free;
72     use mem;
73     use managed;
74
75     let mut stats = AnnihilateStats {
76         n_total_boxes: 0,
77         n_unique_boxes: 0,
78         n_bytes_freed: 0
79     };
80
81     // Pass 1: Make all boxes immortal.
82     //
83     // In this pass, nothing gets freed, so it does not matter whether
84     // we read the next field before or after the callback.
85     each_live_alloc(true, |alloc, uniq| {
86         stats.n_total_boxes += 1;
87         if uniq {
88             stats.n_unique_boxes += 1;
89         } else {
90             (*alloc).ref_count = managed::RC_IMMORTAL;
91         }
92         true
93     });
94
95     // Pass 2: Drop all boxes.
96     //
97     // In this pass, unique-managed boxes may get freed, but not
98     // managed boxes, so we must read the `next` field *after* the
99     // callback, as the original value may have been freed.
100     each_live_alloc(false, |alloc, uniq| {
101         if !uniq {
102             let tydesc = (*alloc).type_desc;
103             let data = &(*alloc).data as *();
104             ((*tydesc).drop_glue)(data as *i8);
105         }
106         true
107     });
108
109     // Pass 3: Free all boxes.
110     //
111     // In this pass, managed boxes may get freed (but not
112     // unique-managed boxes, though I think that none of those are
113     // left), so we must read the `next` field before, since it will
114     // not be valid after.
115     each_live_alloc(true, |alloc, uniq| {
116         if !uniq {
117             stats.n_bytes_freed +=
118                 (*((*alloc).type_desc)).size
119                 + mem::size_of::<raw::Box<()>>();
120             local_free(alloc as *i8);
121         }
122         true
123     });
124
125     if debug_mem() {
126         // We do logging here w/o allocation.
127         debug!("annihilator stats:\n  \
128                        total boxes: {}\n  \
129                       unique boxes: {}\n  \
130                        bytes freed: {}",
131                 stats.n_total_boxes, stats.n_unique_boxes, stats.n_bytes_freed);
132     }
133 }