| | 1 | /* |
| | 2 | * Copyright (c) 1998, 2002 Michael J. Roberts. All Rights Reserved. |
| | 3 | * |
| | 4 | * Please see the accompanying license file, LICENSE.TXT, for information |
| | 5 | * on using and copying this software. |
| | 6 | */ |
| | 7 | /* |
| | 8 | Name |
| | 9 | vmpool.cpp - constant pool implementation |
| | 10 | Function |
| | 11 | |
| | 12 | Notes |
| | 13 | |
| | 14 | Modified |
| | 15 | 10/20/98 MJRoberts - Creation |
| | 16 | */ |
| | 17 | |
| | 18 | #include <stdlib.h> |
| | 19 | #include <memory.h> |
| | 20 | |
| | 21 | #include "t3std.h" |
| | 22 | #include "vmpool.h" |
| | 23 | |
| | 24 | |
| | 25 | /* ------------------------------------------------------------------------ */ |
| | 26 | /* |
| | 27 | * Basic pool implementation |
| | 28 | */ |
| | 29 | |
| | 30 | /* |
| | 31 | * Get the number of pages in the pool |
| | 32 | */ |
| | 33 | size_t CVmPool::get_page_count() const |
| | 34 | { |
| | 35 | /* get the page count from the backing store */ |
| | 36 | return backing_store_->vmpbs_get_page_count(); |
| | 37 | } |
| | 38 | |
| | 39 | /* |
| | 40 | * Attach to a backing store |
| | 41 | */ |
| | 42 | void CVmPool::attach_backing_store(CVmPoolBackingStore *backing_store) |
| | 43 | { |
| | 44 | /* remember the backing store */ |
| | 45 | backing_store_ = backing_store; |
| | 46 | |
| | 47 | /* get the page size from the backing store */ |
| | 48 | page_size_ = backing_store->vmpbs_get_common_page_size(); |
| | 49 | } |
| | 50 | |
| | 51 | /* ------------------------------------------------------------------------ */ |
| | 52 | /* |
| | 53 | * Base paged pool implementation |
| | 54 | */ |
| | 55 | |
| | 56 | /* |
| | 57 | * delete our page list |
| | 58 | */ |
| | 59 | void CVmPoolPaged::delete_page_list() |
| | 60 | { |
| | 61 | /* if there's a page list, delete it */ |
| | 62 | if (pages_ != 0) |
| | 63 | { |
| | 64 | /* free the page array */ |
| | 65 | t3free(pages_); |
| | 66 | |
| | 67 | /* forget it */ |
| | 68 | pages_ = 0; |
| | 69 | page_slots_ = 0; |
| | 70 | page_slots_max_ = 0; |
| | 71 | } |
| | 72 | |
| | 73 | /* we can no longer have a backing store */ |
| | 74 | backing_store_ = 0; |
| | 75 | } |
| | 76 | |
| | 77 | /* |
| | 78 | * Attach to a backing store |
| | 79 | */ |
| | 80 | void CVmPoolPaged::attach_backing_store(CVmPoolBackingStore *backing_store) |
| | 81 | { |
| | 82 | size_t cur; |
| | 83 | size_t log2; |
| | 84 | |
| | 85 | /* delete any existing page list */ |
| | 86 | delete_page_list(); |
| | 87 | |
| | 88 | /* inherit default handling */ |
| | 89 | CVmPool::attach_backing_store(backing_store); |
| | 90 | |
| | 91 | /* |
| | 92 | * if the page size is zero, there must not be any pages at all - |
| | 93 | * use a dummy default page size |
| | 94 | */ |
| | 95 | if (page_size_ == 0) |
| | 96 | page_size_ = 1024; |
| | 97 | |
| | 98 | /* |
| | 99 | * Compute log2 of the page size. If the page size isn't a power of |
| | 100 | * two, throw an error. |
| | 101 | */ |
| | 102 | for (cur = page_size_, log2 = 0 ; (cur & 1) == 0 ; cur >>= 1, ++log2) ; |
| | 103 | if (cur != 1) |
| | 104 | err_throw(VMERR_BAD_POOL_PAGE_SIZE); |
| | 105 | |
| | 106 | /* store log2(page_size_) in log2_page_size_ */ |
| | 107 | log2_page_size_ = log2; |
| | 108 | |
| | 109 | /* allocate the pages */ |
| | 110 | alloc_page_slots(backing_store_->vmpbs_get_page_count()); |
| | 111 | } |
| | 112 | |
| | 113 | /* |
| | 114 | * Allocate a page slot |
| | 115 | */ |
| | 116 | void CVmPoolPaged::alloc_page_slots(size_t slots) |
| | 117 | { |
| | 118 | size_t old_slots; |
| | 119 | size_t i; |
| | 120 | |
| | 121 | /* note the old slot count */ |
| | 122 | old_slots = page_slots_; |
| | 123 | |
| | 124 | /* if the new size isn't bigger than the old size, ignore the request */ |
| | 125 | if (slots <= page_slots_) |
| | 126 | return; |
| | 127 | |
| | 128 | /* if necessary, expand the master page array */ |
| | 129 | if (slots > page_slots_max_) |
| | 130 | { |
| | 131 | size_t siz; |
| | 132 | |
| | 133 | /* |
| | 134 | * Increase the maximum, leaving some room for dynamically added |
| | 135 | * pages. |
| | 136 | */ |
| | 137 | page_slots_max_ = slots + 10; |
| | 138 | |
| | 139 | /* calculate the new allocation size */ |
| | 140 | siz = page_slots_max_ * sizeof(pages_[0]); |
| | 141 | |
| | 142 | /* allocate or reallocate at the new size */ |
| | 143 | if (pages_ == 0) |
| | 144 | pages_ = (CVmPool_pg *)t3malloc(siz); |
| | 145 | else |
| | 146 | pages_ = (CVmPool_pg *)t3realloc(pages_, siz); |
| | 147 | } |
| | 148 | |
| | 149 | /* set the new size */ |
| | 150 | page_slots_ = slots; |
| | 151 | |
| | 152 | /* clear the new subarrays */ |
| | 153 | for (i = old_slots ; i < page_slots_ ; ++i) |
| | 154 | pages_[i].mem = 0; |
| | 155 | } |
| | 156 | |
| | 157 | /* ------------------------------------------------------------------------ */ |
| | 158 | /* |
| | 159 | * Two-level paged pool implementation. This is a variation of the regular |
| | 160 | * paged pool that uses a two-level page table. This implementation is not |
| | 161 | * currently used, because it is less efficient than the single-page pool |
| | 162 | * and is not needed for modern machines with large contiguous address |
| | 163 | * spaces; however, we retain it in the event it's needed for 16-bit |
| | 164 | * segmented architectures, where it might not be possible or convenient to |
| | 165 | * allocate a sufficiently large master page table and thus a two-level |
| | 166 | * table is needed. |
| | 167 | */ |
| | 168 | #if 0 |
| | 169 | |
| | 170 | /* |
| | 171 | * delete the pool - deletes all allocated pages |
| | 172 | */ |
| | 173 | CVmPoolPaged2::~CVmPoolPaged2() |
| | 174 | { |
| | 175 | /* free our page memory */ |
| | 176 | delete_page_list(); |
| | 177 | } |
| | 178 | |
| | 179 | /* |
| | 180 | * delete our page list |
| | 181 | */ |
| | 182 | void CVmPoolPaged2::delete_page_list() |
| | 183 | { |
| | 184 | /* if there's a page list, delete it */ |
| | 185 | if (pages_ != 0) |
| | 186 | { |
| | 187 | size_t i; |
| | 188 | size_t cnt; |
| | 189 | |
| | 190 | /* free each subarray */ |
| | 191 | cnt = get_subarray_count(); |
| | 192 | for (i = 0 ; i < cnt ; ++i) |
| | 193 | t3free(pages_[i]); |
| | 194 | |
| | 195 | /* free the master array */ |
| | 196 | t3free(pages_); |
| | 197 | |
| | 198 | /* forget about the page list */ |
| | 199 | pages_ = 0; |
| | 200 | } |
| | 201 | } |
| | 202 | |
| | 203 | /* |
| | 204 | * Attach to a backing store |
| | 205 | */ |
| | 206 | void CVmPoolPaged2::attach_backing_store(CVmPoolBackingStore *backing_store) |
| | 207 | { |
| | 208 | size_t cur; |
| | 209 | size_t log2; |
| | 210 | |
| | 211 | /* delete any existing page list */ |
| | 212 | delete_page_list(); |
| | 213 | |
| | 214 | /* remember the backing store */ |
| | 215 | backing_store_ = backing_store; |
| | 216 | |
| | 217 | /* get the page size from the backing store */ |
| | 218 | page_size_ = backing_store_->vmpbs_get_common_page_size(); |
| | 219 | |
| | 220 | /* |
| | 221 | * if the page size is zero, there must not be any pages at all - use a |
| | 222 | * dummy default page size |
| | 223 | */ |
| | 224 | if (page_size_ == 0) |
| | 225 | page_size_ = 1024; |
| | 226 | |
| | 227 | /* |
| | 228 | * Compute log2 of the page size. If the page size isn't a power of |
| | 229 | * two, throw an error. |
| | 230 | */ |
| | 231 | for (cur = page_size_, log2 = 0 ; (cur & 1) == 0 ; cur >>= 1, ++log2) ; |
| | 232 | if (cur != 1) |
| | 233 | err_throw(VMERR_BAD_POOL_PAGE_SIZE); |
| | 234 | |
| | 235 | /* store log2(page_size_) in log2_page_size_ */ |
| | 236 | log2_page_size_ = log2; |
| | 237 | |
| | 238 | /* allocate the pages */ |
| | 239 | alloc_page_slots(backing_store_->vmpbs_get_page_count()); |
| | 240 | } |
| | 241 | |
| | 242 | /* |
| | 243 | * Allocate a page slot |
| | 244 | */ |
| | 245 | void CVmPoolPaged2::alloc_page_slots(size_t slots) |
| | 246 | { |
| | 247 | size_t old_slots; |
| | 248 | size_t old_sub_cnt; |
| | 249 | size_t new_sub_cnt; |
| | 250 | |
| | 251 | /* note the old slot count */ |
| | 252 | old_slots = page_slots_; |
| | 253 | |
| | 254 | /* if the new size isn't bigger than the old size, ignore the request */ |
| | 255 | if (slots <= page_slots_) |
| | 256 | return; |
| | 257 | |
| | 258 | /* note the original subarray count */ |
| | 259 | old_sub_cnt = get_subarray_count(); |
| | 260 | |
| | 261 | /* set the new size */ |
| | 262 | page_slots_ = slots; |
| | 263 | |
| | 264 | /* note the new subarray count */ |
| | 265 | new_sub_cnt = get_subarray_count(); |
| | 266 | |
| | 267 | /* allocate or expand the master array */ |
| | 268 | if (new_sub_cnt > old_sub_cnt) |
| | 269 | { |
| | 270 | size_t siz; |
| | 271 | size_t i; |
| | 272 | |
| | 273 | /* figure the new size */ |
| | 274 | siz = new_sub_cnt * sizeof(pages_[0]); |
| | 275 | |
| | 276 | /* allocate or re-allocate the master array */ |
| | 277 | if (pages_ == 0) |
| | 278 | pages_ = (CVmPool_pg **)t3malloc(siz); |
| | 279 | else |
| | 280 | pages_ = (CVmPool_pg **)t3realloc(pages_, siz); |
| | 281 | |
| | 282 | /* throw an error if that failed */ |
| | 283 | if (pages_ == 0) |
| | 284 | err_throw(VMERR_OUT_OF_MEMORY); |
| | 285 | |
| | 286 | /* clear the new slots */ |
| | 287 | memset(pages_ + old_sub_cnt, 0, |
| | 288 | (new_sub_cnt - old_sub_cnt) * sizeof(pages_[0])); |
| | 289 | |
| | 290 | /* allocate the subarrays */ |
| | 291 | for (i = old_sub_cnt ; i < new_sub_cnt ; ++i) |
| | 292 | { |
| | 293 | /* allocate this subarray */ |
| | 294 | pages_[i] = (CVmPool_pg *)t3malloc(VMPOOL_SUBARRAY_SIZE |
| | 295 | * sizeof(pages_[i][0])); |
| | 296 | |
| | 297 | /* make sure we got the space */ |
| | 298 | if (pages_[i] == 0) |
| | 299 | err_throw(VMERR_OUT_OF_MEMORY); |
| | 300 | |
| | 301 | /* clear the page */ |
| | 302 | memset(pages_[i], 0, VMPOOL_SUBARRAY_SIZE * sizeof(pages_[i][0])); |
| | 303 | } |
| | 304 | } |
| | 305 | } |
| | 306 | |
| | 307 | #endif /* removed 2-paged pool */ |