1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
use memory::bucket::Bucket;
use memory::bucket::BUCKET_PAGES;
use memory::page::Page;
use memory::page::PAGE_SIZE;
use memory::pool::Pool;
use std::mem::align_of;
use std::mem::size_of;
use std::usize::MAX;

pub struct HeapBucket {
    pub pool: *mut Pool,
    pub map: usize,
}

impl HeapBucket {
    pub fn allocate_page(&mut self) -> *mut Page {
        // println!("HeapBucket self:{:X}", self as *const HeapBucket as usize);
        // println!("HeapBucket map:{:X}", self.map);
        if self.map == 0 {
            unsafe {
                // println!("self.pool: {:X}", self.pool as usize);
                (*self.pool).mark_as_full(Page::get(self as *const HeapBucket as usize) as usize);
                return (*self.pool).allocate_page();
            }
        }

        let position = Bucket::find_least_position(self.map);
        // println!("HeapBucket position: {}", position);
        let bit = 1 << (BUCKET_PAGES - position);
        // println!("Bit for allocation: {:X}", bit);
        self.map = self.map & !bit;

        let page = (Page::get(self as *const HeapBucket as usize) as usize
            + (position - 1) * PAGE_SIZE) as *mut Page;
        // println!("HeapBucket allocated page:{:X}", page as usize);

        unsafe {
            (*page).reset();

            if position == 1 {
                (*page).allocate_raw(size_of::<Bucket>(), align_of::<Bucket>());
            }

            if page == Page::get(self.pool as usize) {
                (*page).allocate_raw(size_of::<Pool>(), align_of::<Pool>());
            }
        }
        page
    }

    pub fn deallocate_page(&mut self, page: &Page) {
        let base_page = Page::get(self as *const HeapBucket as usize) as usize;
        // println!("HeapBucket about to de-allocate a page:{:X}", base_page);
        let distance = page as *const Page as usize - base_page;
        let index = distance / PAGE_SIZE;
        if index > BUCKET_PAGES - 1 {
            panic!("Position invalid for page {:X}", base_page)
        };
        let position = index + 1;
        // println!("Index to de-allocate: {}", position);
        let bit = 1 << (BUCKET_PAGES - position);
        // println!("Bit for deallocation: {:X}", bit);
        if self.map & bit != 0 {
            panic!("Page {:X} was not allocated!", base_page)
        }
        // println!("self.map before deallocation: {:X}", self.map);
        self.map = self.map | bit;
        // println!("self.map after deallocation: {:X}", self.map);
        if self.map == MAX {
            unsafe {
                (*self.pool).mark_as_free(base_page);
            }
        }
    }
}

// #[test]
// fn test_heapbucket() {
//     use memory::bucket::Bucket;
//     use memory::heap::Heap;
//     unsafe {
//         let mut heap = Heap::create();
//         let pool = Pool::create(&mut heap);
//         println!("pool: {:X}", pool as usize);
//         let bucket = Bucket::get(pool as usize);
//         let _page00 = (*bucket).allocate_page();
//         let _page01 = (*bucket).allocate_page();
//         let page02 = (*bucket).allocate_page();
//         let page03 = (*bucket).allocate_page();
//         let page04 = (*bucket).allocate_page();
//         let page05 = (*bucket).allocate_page();
//         let _page06 = (*bucket).allocate_page();
//         let _page07 = (*bucket).allocate_page();
//         let _page08 = (*bucket).allocate_page();
//         let _page09 = (*bucket).allocate_page();
//         let _page10 = (*bucket).allocate_page();
//         let _page11 = (*bucket).allocate_page();
//         let _page12 = (*bucket).allocate_page();
//         let _page13 = (*bucket).allocate_page();
//         let _page14 = (*bucket).allocate_page();
//         let _page15 = (*bucket).allocate_page();
//         let page16 = (*bucket).allocate_page();
//         let _page17 = (*bucket).allocate_page();
//         let page18 = (*bucket).allocate_page();
//         let _page19 = (*bucket).allocate_page();
//         let _page20 = (*bucket).allocate_page();
//         let _page21 = (*bucket).allocate_page();
//         let _page22 = (*bucket).allocate_page();
//         let _page23 = (*bucket).allocate_page();
//         let _page24 = (*bucket).allocate_page();
//         let _page25 = (*bucket).allocate_page();
//         let _page26 = (*bucket).allocate_page();
//         let _page27 = (*bucket).allocate_page();
//         let _page28 = (*bucket).allocate_page();
//         let _page29 = (*bucket).allocate_page();
//         let _page30 = (*bucket).allocate_page();
//         let _page31 = (*bucket).allocate_page();
//         let _page32 = (*bucket).allocate_page();
//         let _page33 = (*bucket).allocate_page();
//         let _page34 = (*bucket).allocate_page();
//         let _page35 = (*bucket).allocate_page();
//         let _page36 = (*bucket).allocate_page();
//         let _page37 = (*bucket).allocate_page();
//         let _page38 = (*bucket).allocate_page();
//         let _page39 = (*bucket).allocate_page();
//         let _page40 = (*bucket).allocate_page();
//         let _page41 = (*bucket).allocate_page();
//         let _page42 = (*bucket).allocate_page();
//         let _page43 = (*bucket).allocate_page();
//         let _page44 = (*bucket).allocate_page();
//         let _page45 = (*bucket).allocate_page();
//         let _page46 = (*bucket).allocate_page();
//         let _page47 = (*bucket).allocate_page();
//         let _page48 = (*bucket).allocate_page();
//         let _page49 = (*bucket).allocate_page();
//         let _page50 = (*bucket).allocate_page();
//         let _page51 = (*bucket).allocate_page();
//         let _page52 = (*bucket).allocate_page();
//         let _page53 = (*bucket).allocate_page();
//         let _page54 = (*bucket).allocate_page();
//         let _page55 = (*bucket).allocate_page();
//         let _page56 = (*bucket).allocate_page();
//         let _page57 = (*bucket).allocate_page();
//         let _page58 = (*bucket).allocate_page();
//         let _page59 = (*bucket).allocate_page();
//         let _page60 = (*bucket).allocate_page();
//         let _page61 = (*bucket).allocate_page();
//         let page62 = (*bucket).allocate_page();
//         let page63 = (*bucket).allocate_page();
//         assert_eq!(
//             match *bucket {
//                 Bucket::Stack(ref _s) => 0,
//                 Bucket::Heap(ref h) => h.map,
//             },
//             0
//         );
//         (*bucket).deallocate_page(&*page62);
//         let page62a = (*bucket).allocate_page();
//         assert_eq!(page62, page62a);
//         assert_eq!(
//             match *bucket {
//                 Bucket::Stack(ref _s) => 0,
//                 Bucket::Heap(ref h) => h.map,
//             },
//             0
//         );
//         (*bucket).deallocate_page(&*page02);
//         (*bucket).deallocate_page(&*page03);
//         (*bucket).deallocate_page(&*page04);
//         (*bucket).deallocate_page(&*page05);
//         let page02a = (*bucket).allocate_page();
//         let page03a = (*bucket).allocate_page();
//         let page04a = (*bucket).allocate_page();
//         let page05a = (*bucket).allocate_page();
//         assert_eq!(page02, page02a);
//         assert_eq!(page03, page03a);
//         assert_eq!(page04, page04a);
//         assert_eq!(page05, page05a);
//         assert_eq!(
//             match *bucket {
//                 Bucket::Stack(ref _s) => 0,
//                 Bucket::Heap(ref h) => h.map,
//             },
//             0
//         );
//         (*bucket).deallocate_page(&*page16);
//         (*bucket).deallocate_page(&*page18);
//         let page16a = (*bucket).allocate_page();
//         let page18a = (*bucket).allocate_page();
//         assert_eq!(page16, page16a);
//         assert_eq!(page18, page18a);
//         assert_eq!(
//             match *bucket {
//                 Bucket::Stack(ref _s) => 0,
//                 Bucket::Heap(ref h) => h.map,
//             },
//             0
//         );
//         (*bucket).deallocate_page(&*page63);
//         let page63a = (*bucket).allocate_page();
//         assert_eq!(page63, page63a);
//         assert_eq!(
//             match *bucket {
//                 Bucket::Stack(ref _s) => 0,
//                 Bucket::Heap(ref h) => h.map,
//             },
//             0
//         );
//     }
// }