]> git.lizzy.rs Git - rust.git/blob - src/libstd/cleanup.rs
Convert most code to new inner attribute syntax.
[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 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 }