Changeset e3ee9b9 in mainline
- Timestamp:
- 2010-07-02T12:44:00Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 7a0359b, cefb126, e2ea4ab1
- Parents:
- b5382d4f
- Location:
- kernel/generic/src
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/src/adt/btree.c
rb5382d4f re3ee9b9 33 33 /** 34 34 * @file 35 * @brief 35 * @brief B+tree implementation. 36 36 * 37 37 * This file implements B+tree type and operations. … … 54 54 #include <print.h> 55 55 56 static void btree_destroy_subtree(btree_node_t *root);57 static void _btree_insert(btree_t *t, btree_key_t key, void *value, btree_node_t *rsubtree, btree_node_t *node);58 static void _btree_remove(btree_t *t, btree_key_t key, btree_node_t *node);59 static void node_initialize(btree_node_t *node);60 static void node_insert_key_and_lsubtree(btree_node_t *node, btree_key_t key, void *value, btree_node_t *lsubtree);61 static void node_insert_key_and_rsubtree(btree_node_t *node, btree_key_t key, void *value, btree_node_t *rsubtree);62 static void node_remove_key_and_lsubtree(btree_node_t *node, btree_key_t key);63 static void node_remove_key_and_rsubtree(btree_node_t *node, btree_key_t key);64 static btree_node_t *node_split(btree_node_t *node, btree_key_t key, void *value, btree_node_t *rsubtree, btree_key_t *median);65 static btree_node_t *node_combine(btree_node_t *node);66 static size_t find_key_by_subtree(btree_node_t *node, btree_node_t *subtree, bool right);67 static void rotate_from_right(btree_node_t *lnode, btree_node_t *rnode, size_t idx);68 static void rotate_from_left(btree_node_t *lnode, btree_node_t *rnode, size_t idx);69 static bool try_insert_by_rotation_to_left(btree_node_t *node, btree_key_t key, void *value, btree_node_t *rsubtree);70 static bool try_insert_by_rotation_to_right(btree_node_t *node, btree_key_t key, void *value, btree_node_t *rsubtree);71 static bool try_rotation_from_left(btree_node_t *rnode);72 static bool try_rotation_from_right(btree_node_t *lnode);73 74 #define ROOT_NODE(n) (!(n)->parent)75 #define INDEX_NODE(n) ((n)->subtree[0] != NULL)76 #define LEAF_NODE(n) ((n)->subtree[0] == NULL)77 78 #define FILL_FACTOR ((BTREE_M-1)/2)79 80 #define MEDIAN_LOW_INDEX(n) (((n)->keys-1)/2)81 #define MEDIAN_HIGH_INDEX(n) ((n)->keys/2)82 #define MEDIAN_LOW(n) ((n)->key[MEDIAN_LOW_INDEX((n))]);83 #define MEDIAN_HIGH(n) ((n)->key[MEDIAN_HIGH_INDEX((n))]);84 85 56 static slab_cache_t *btree_node_slab; 57 58 #define ROOT_NODE(n) (!(n)->parent) 59 #define INDEX_NODE(n) ((n)->subtree[0] != NULL) 60 #define LEAF_NODE(n) ((n)->subtree[0] == NULL) 61 62 #define FILL_FACTOR ((BTREE_M - 1) / 2) 63 64 #define MEDIAN_LOW_INDEX(n) (((n)->keys-1) / 2) 65 #define MEDIAN_HIGH_INDEX(n) ((n)->keys / 2) 66 #define MEDIAN_LOW(n) ((n)->key[MEDIAN_LOW_INDEX((n))]); 67 #define MEDIAN_HIGH(n) ((n)->key[MEDIAN_HIGH_INDEX((n))]); 86 68 87 69 /** Initialize B-trees. */ 88 70 void btree_init(void) 89 71 { 90 btree_node_slab = slab_cache_create("btree_node_slab", sizeof(btree_node_t), 0, NULL, NULL, SLAB_CACHE_MAGDEFERRED); 72 btree_node_slab = slab_cache_create("btree_node_slab", 73 sizeof(btree_node_t), 0, NULL, NULL, SLAB_CACHE_MAGDEFERRED); 74 } 75 76 /** Initialize B-tree node. 77 * 78 * @param node B-tree node. 79 * 80 */ 81 static void node_initialize(btree_node_t *node) 82 { 83 unsigned int i; 84 85 node->keys = 0; 86 87 /* Clean also space for the extra key. */ 88 for (i = 0; i < BTREE_MAX_KEYS + 1; i++) { 89 node->key[i] = 0; 90 node->value[i] = NULL; 91 node->subtree[i] = NULL; 92 } 93 94 node->subtree[i] = NULL; 95 node->parent = NULL; 96 97 link_initialize(&node->leaf_link); 98 link_initialize(&node->bfs_link); 99 node->depth = 0; 91 100 } 92 101 … … 94 103 * 95 104 * @param t B-tree. 105 * 96 106 */ 97 107 void btree_create(btree_t *t) … … 103 113 } 104 114 105 /** Destroy empty B-tree. */106 void btree_destroy(btree_t *t)107 {108 btree_destroy_subtree(t->root);109 }110 111 /** Insert key-value pair into B-tree.112 *113 * @param t B-tree.114 * @param key Key to be inserted.115 * @param value Value to be inserted.116 * @param leaf_node Leaf node where the insertion should begin.117 */118 void btree_insert(btree_t *t, btree_key_t key, void *value, btree_node_t *leaf_node)119 {120 btree_node_t *lnode;121 122 ASSERT(value);123 124 lnode = leaf_node;125 if (!lnode) {126 if (btree_search(t, key, &lnode)) {127 panic("B-tree %p already contains key %" PRIu64 ".", t, key);128 }129 }130 131 _btree_insert(t, key, value, NULL, lnode);132 }133 134 115 /** Destroy subtree rooted in a node. 135 116 * 136 117 * @param root Root of the subtree. 137 */ 138 void btree_destroy_subtree(btree_node_t *root) 118 * 119 */ 120 static void btree_destroy_subtree(btree_node_t *root) 139 121 { 140 122 size_t i; 141 123 142 124 if (root->keys) { 143 125 for (i = 0; i < root->keys + 1; i++) { … … 146 128 } 147 129 } 130 148 131 slab_free(btree_node_slab, root); 149 132 } 150 133 134 /** Destroy empty B-tree. */ 135 void btree_destroy(btree_t *t) 136 { 137 btree_destroy_subtree(t->root); 138 } 139 140 /** Insert key-value-rsubtree triplet into B-tree node. 141 * 142 * It is actually possible to have more keys than BTREE_MAX_KEYS. 143 * This feature is used during splitting the node when the 144 * number of keys is BTREE_MAX_KEYS + 1. Insert by left rotation 145 * also makes use of this feature. 146 * 147 * @param node B-tree node into wich the new key is to be inserted. 148 * @param key The key to be inserted. 149 * @param value Pointer to value to be inserted. 150 * @param rsubtree Pointer to the right subtree. 151 * 152 */ 153 static void node_insert_key_and_rsubtree(btree_node_t *node, btree_key_t key, 154 void *value, btree_node_t *rsubtree) 155 { 156 size_t i; 157 158 for (i = 0; i < node->keys; i++) { 159 if (key < node->key[i]) { 160 size_t j; 161 162 for (j = node->keys; j > i; j--) { 163 node->key[j] = node->key[j - 1]; 164 node->value[j] = node->value[j - 1]; 165 node->subtree[j + 1] = node->subtree[j]; 166 } 167 168 break; 169 } 170 } 171 172 node->key[i] = key; 173 node->value[i] = value; 174 node->subtree[i + 1] = rsubtree; 175 node->keys++; 176 } 177 178 /** Find key by its left or right subtree. 179 * 180 * @param node B-tree node. 181 * @param subtree Left or right subtree of a key found in node. 182 * @param right If true, subtree is a right subtree. If false, 183 * subtree is a left subtree. 184 * 185 * @return Index of the key associated with the subtree. 186 * 187 */ 188 static size_t find_key_by_subtree(btree_node_t *node, btree_node_t *subtree, 189 bool right) 190 { 191 size_t i; 192 193 for (i = 0; i < node->keys + 1; i++) { 194 if (subtree == node->subtree[i]) 195 return i - (int) (right != false); 196 } 197 198 panic("Node %p does not contain subtree %p.", node, subtree); 199 } 200 201 /** Remove key and its left subtree pointer from B-tree node. 202 * 203 * Remove the key and eliminate gaps in node->key array. 204 * Note that the value pointer and the left subtree pointer 205 * is removed from the node as well. 206 * 207 * @param node B-tree node. 208 * @param key Key to be removed. 209 * 210 */ 211 static void node_remove_key_and_lsubtree(btree_node_t *node, btree_key_t key) 212 { 213 size_t i; 214 size_t j; 215 216 for (i = 0; i < node->keys; i++) { 217 if (key == node->key[i]) { 218 for (j = i + 1; j < node->keys; j++) { 219 node->key[j - 1] = node->key[j]; 220 node->value[j - 1] = node->value[j]; 221 node->subtree[j - 1] = node->subtree[j]; 222 } 223 224 node->subtree[j - 1] = node->subtree[j]; 225 node->keys--; 226 227 return; 228 } 229 } 230 231 panic("Node %p does not contain key %" PRIu64 ".", node, key); 232 } 233 234 /** Remove key and its right subtree pointer from B-tree node. 235 * 236 * Remove the key and eliminate gaps in node->key array. 237 * Note that the value pointer and the right subtree pointer 238 * is removed from the node as well. 239 * 240 * @param node B-tree node. 241 * @param key Key to be removed. 242 * 243 */ 244 static void node_remove_key_and_rsubtree(btree_node_t *node, btree_key_t key) 245 { 246 size_t i, j; 247 248 for (i = 0; i < node->keys; i++) { 249 if (key == node->key[i]) { 250 for (j = i + 1; j < node->keys; j++) { 251 node->key[j - 1] = node->key[j]; 252 node->value[j - 1] = node->value[j]; 253 node->subtree[j] = node->subtree[j + 1]; 254 } 255 256 node->keys--; 257 return; 258 } 259 } 260 261 panic("Node %p does not contain key %" PRIu64 ".", node, key); 262 } 263 264 /** Insert key-value-lsubtree triplet into B-tree node. 265 * 266 * It is actually possible to have more keys than BTREE_MAX_KEYS. 267 * This feature is used during insert by right rotation. 268 * 269 * @param node B-tree node into wich the new key is to be inserted. 270 * @param key The key to be inserted. 271 * @param value Pointer to value to be inserted. 272 * @param lsubtree Pointer to the left subtree. 273 * 274 */ 275 static void node_insert_key_and_lsubtree(btree_node_t *node, btree_key_t key, 276 void *value, btree_node_t *lsubtree) 277 { 278 size_t i; 279 280 for (i = 0; i < node->keys; i++) { 281 if (key < node->key[i]) { 282 size_t j; 283 284 for (j = node->keys; j > i; j--) { 285 node->key[j] = node->key[j - 1]; 286 node->value[j] = node->value[j - 1]; 287 node->subtree[j + 1] = node->subtree[j]; 288 } 289 290 node->subtree[j + 1] = node->subtree[j]; 291 break; 292 } 293 } 294 295 node->key[i] = key; 296 node->value[i] = value; 297 node->subtree[i] = lsubtree; 298 299 node->keys++; 300 } 301 302 /** Rotate one key-value-rsubtree triplet from the left sibling to the right sibling. 303 * 304 * The biggest key and its value and right subtree is rotated 305 * from the left node to the right. If the node is an index node, 306 * than the parent node key belonging to the left node takes part 307 * in the rotation. 308 * 309 * @param lnode Left sibling. 310 * @param rnode Right sibling. 311 * @param idx Index of the parent node key that is taking part 312 * in the rotation. 313 * 314 */ 315 static void rotate_from_left(btree_node_t *lnode, btree_node_t *rnode, size_t idx) 316 { 317 btree_key_t key = lnode->key[lnode->keys - 1]; 318 319 if (LEAF_NODE(lnode)) { 320 void *value = lnode->value[lnode->keys - 1]; 321 322 node_remove_key_and_rsubtree(lnode, key); 323 node_insert_key_and_lsubtree(rnode, key, value, NULL); 324 lnode->parent->key[idx] = key; 325 } else { 326 btree_node_t *rsubtree = lnode->subtree[lnode->keys]; 327 328 node_remove_key_and_rsubtree(lnode, key); 329 node_insert_key_and_lsubtree(rnode, lnode->parent->key[idx], NULL, rsubtree); 330 lnode->parent->key[idx] = key; 331 332 /* Fix parent link of the reconnected right subtree. */ 333 rsubtree->parent = rnode; 334 } 335 } 336 337 /** Rotate one key-value-lsubtree triplet from the right sibling to the left sibling. 338 * 339 * The smallest key and its value and left subtree is rotated 340 * from the right node to the left. If the node is an index node, 341 * than the parent node key belonging to the right node takes part 342 * in the rotation. 343 * 344 * @param lnode Left sibling. 345 * @param rnode Right sibling. 346 * @param idx Index of the parent node key that is taking part 347 * in the rotation. 348 * 349 */ 350 static void rotate_from_right(btree_node_t *lnode, btree_node_t *rnode, size_t idx) 351 { 352 btree_key_t key = rnode->key[0]; 353 354 if (LEAF_NODE(rnode)) { 355 void *value = rnode->value[0]; 356 357 node_remove_key_and_lsubtree(rnode, key); 358 node_insert_key_and_rsubtree(lnode, key, value, NULL); 359 rnode->parent->key[idx] = rnode->key[0]; 360 } else { 361 btree_node_t *lsubtree = rnode->subtree[0]; 362 363 node_remove_key_and_lsubtree(rnode, key); 364 node_insert_key_and_rsubtree(lnode, rnode->parent->key[idx], NULL, lsubtree); 365 rnode->parent->key[idx] = key; 366 367 /* Fix parent link of the reconnected left subtree. */ 368 lsubtree->parent = lnode; 369 } 370 } 371 372 /** Insert key-value-rsubtree triplet and rotate the node to the left, if this operation can be done. 373 * 374 * Left sibling of the node (if it exists) is checked for free space. 375 * If there is free space, the key is inserted and the smallest key of 376 * the node is moved there. The index node which is the parent of both 377 * nodes is fixed. 378 * 379 * @param node B-tree node. 380 * @param inskey Key to be inserted. 381 * @param insvalue Value to be inserted. 382 * @param rsubtree Right subtree of inskey. 383 * 384 * @return True if the rotation was performed, false otherwise. 385 * 386 */ 387 static bool try_insert_by_rotation_to_left(btree_node_t *node, 388 btree_key_t inskey, void *insvalue, btree_node_t *rsubtree) 389 { 390 size_t idx; 391 btree_node_t *lnode; 392 393 /* 394 * If this is root node, the rotation can not be done. 395 */ 396 if (ROOT_NODE(node)) 397 return false; 398 399 idx = find_key_by_subtree(node->parent, node, true); 400 if ((int) idx == -1) { 401 /* 402 * If this node is the leftmost subtree of its parent, 403 * the rotation can not be done. 404 */ 405 return false; 406 } 407 408 lnode = node->parent->subtree[idx]; 409 if (lnode->keys < BTREE_MAX_KEYS) { 410 /* 411 * The rotaion can be done. The left sibling has free space. 412 */ 413 node_insert_key_and_rsubtree(node, inskey, insvalue, rsubtree); 414 rotate_from_right(lnode, node, idx); 415 return true; 416 } 417 418 return false; 419 } 420 421 /** Insert key-value-rsubtree triplet and rotate the node to the right, if this operation can be done. 422 * 423 * Right sibling of the node (if it exists) is checked for free space. 424 * If there is free space, the key is inserted and the biggest key of 425 * the node is moved there. The index node which is the parent of both 426 * nodes is fixed. 427 * 428 * @param node B-tree node. 429 * @param inskey Key to be inserted. 430 * @param insvalue Value to be inserted. 431 * @param rsubtree Right subtree of inskey. 432 * 433 * @return True if the rotation was performed, false otherwise. 434 * 435 */ 436 static bool try_insert_by_rotation_to_right(btree_node_t *node, 437 btree_key_t inskey, void *insvalue, btree_node_t *rsubtree) 438 { 439 size_t idx; 440 btree_node_t *rnode; 441 442 /* 443 * If this is root node, the rotation can not be done. 444 */ 445 if (ROOT_NODE(node)) 446 return false; 447 448 idx = find_key_by_subtree(node->parent, node, false); 449 if (idx == node->parent->keys) { 450 /* 451 * If this node is the rightmost subtree of its parent, 452 * the rotation can not be done. 453 */ 454 return false; 455 } 456 457 rnode = node->parent->subtree[idx + 1]; 458 if (rnode->keys < BTREE_MAX_KEYS) { 459 /* 460 * The rotaion can be done. The right sibling has free space. 461 */ 462 node_insert_key_and_rsubtree(node, inskey, insvalue, rsubtree); 463 rotate_from_left(node, rnode, idx); 464 return true; 465 } 466 467 return false; 468 } 469 470 /** Split full B-tree node and insert new key-value-right-subtree triplet. 471 * 472 * This function will split a node and return a pointer to a newly created 473 * node containing keys greater than or equal to the greater of medians 474 * (or median) of the old keys and the newly added key. It will also write 475 * the median key to a memory address supplied by the caller. 476 * 477 * If the node being split is an index node, the median will not be 478 * included in the new node. If the node is a leaf node, 479 * the median will be copied there. 480 * 481 * @param node B-tree node wich is going to be split. 482 * @param key The key to be inserted. 483 * @param value Pointer to the value to be inserted. 484 * @param rsubtree Pointer to the right subtree of the key being added. 485 * @param median Address in memory, where the median key will be stored. 486 * 487 * @return Newly created right sibling of node. 488 * 489 */ 490 static btree_node_t *node_split(btree_node_t *node, btree_key_t key, 491 void *value, btree_node_t *rsubtree, btree_key_t *median) 492 { 493 btree_node_t *rnode; 494 size_t i; 495 size_t j; 496 497 ASSERT(median); 498 ASSERT(node->keys == BTREE_MAX_KEYS); 499 500 /* 501 * Use the extra space to store the extra node. 502 */ 503 node_insert_key_and_rsubtree(node, key, value, rsubtree); 504 505 /* 506 * Compute median of keys. 507 */ 508 *median = MEDIAN_HIGH(node); 509 510 /* 511 * Allocate and initialize new right sibling. 512 */ 513 rnode = (btree_node_t *) slab_alloc(btree_node_slab, 0); 514 node_initialize(rnode); 515 rnode->parent = node->parent; 516 rnode->depth = node->depth; 517 518 /* 519 * Copy big keys, values and subtree pointers to the new right sibling. 520 * If this is an index node, do not copy the median. 521 */ 522 i = (size_t) INDEX_NODE(node); 523 for (i += MEDIAN_HIGH_INDEX(node), j = 0; i < node->keys; i++, j++) { 524 rnode->key[j] = node->key[i]; 525 rnode->value[j] = node->value[i]; 526 rnode->subtree[j] = node->subtree[i]; 527 528 /* 529 * Fix parent links in subtrees. 530 */ 531 if (rnode->subtree[j]) 532 rnode->subtree[j]->parent = rnode; 533 } 534 535 rnode->subtree[j] = node->subtree[i]; 536 if (rnode->subtree[j]) 537 rnode->subtree[j]->parent = rnode; 538 539 rnode->keys = j; /* Set number of keys of the new node. */ 540 node->keys /= 2; /* Shrink the old node. */ 541 542 return rnode; 543 } 544 151 545 /** Recursively insert into B-tree. 152 546 * 153 * @param t B-tree.154 * @param key Key to be inserted.155 * @param value Value to be inserted.547 * @param t B-tree. 548 * @param key Key to be inserted. 549 * @param value Value to be inserted. 156 550 * @param rsubtree Right subtree of the inserted key. 157 * @param node Start inserting into this node. 158 */ 159 void _btree_insert(btree_t *t, btree_key_t key, void *value, btree_node_t *rsubtree, btree_node_t *node) 551 * @param node Start inserting into this node. 552 * 553 */ 554 static void _btree_insert(btree_t *t, btree_key_t key, void *value, 555 btree_node_t *rsubtree, btree_node_t *node) 160 556 { 161 557 if (node->keys < BTREE_MAX_KEYS) { … … 183 579 * bigger keys (i.e. the new node) into its parent. 184 580 */ 185 581 186 582 rnode = node_split(node, key, value, rsubtree, &median); 187 583 188 584 if (LEAF_NODE(node)) { 189 585 list_prepend(&rnode->leaf_link, &node->leaf_link); … … 202 598 * Left-hand side subtree will be the old root (i.e. node). 203 599 * Right-hand side subtree will be rnode. 204 */ 600 */ 205 601 t->root->subtree[0] = node; 206 602 207 603 t->root->depth = node->depth + 1; 208 604 } 209 605 _btree_insert(t, median, NULL, rnode, node->parent); 210 } 211 212 } 213 214 /** Remove B-tree node. 215 * 216 * @param t B-tree. 217 * @param key Key to be removed from the B-tree along with its associated value. 218 * @param leaf_node If not NULL, pointer to the leaf node where the key is found. 219 */ 220 void btree_remove(btree_t *t, btree_key_t key, btree_node_t *leaf_node) 606 } 607 } 608 609 /** Insert key-value pair into B-tree. 610 * 611 * @param t B-tree. 612 * @param key Key to be inserted. 613 * @param value Value to be inserted. 614 * @param leaf_node Leaf node where the insertion should begin. 615 * 616 */ 617 void btree_insert(btree_t *t, btree_key_t key, void *value, 618 btree_node_t *leaf_node) 221 619 { 222 620 btree_node_t *lnode; 621 622 ASSERT(value); 223 623 224 624 lnode = leaf_node; 225 625 if (!lnode) { 226 if (!btree_search(t, key, &lnode)) { 227 panic("B-tree %p does not contain key %" PRIu64 ".", t, key); 228 } 229 } 230 231 _btree_remove(t, key, lnode); 626 if (btree_search(t, key, &lnode)) 627 panic("B-tree %p already contains key %" PRIu64 ".", t, key); 628 } 629 630 _btree_insert(t, key, value, NULL, lnode); 631 } 632 633 /** Rotate in a key from the left sibling or from the index node, if this operation can be done. 634 * 635 * @param rnode Node into which to add key from its left sibling 636 * or from the index node. 637 * 638 * @return True if the rotation was performed, false otherwise. 639 * 640 */ 641 static bool try_rotation_from_left(btree_node_t *rnode) 642 { 643 size_t idx; 644 btree_node_t *lnode; 645 646 /* 647 * If this is root node, the rotation can not be done. 648 */ 649 if (ROOT_NODE(rnode)) 650 return false; 651 652 idx = find_key_by_subtree(rnode->parent, rnode, true); 653 if ((int) idx == -1) { 654 /* 655 * If this node is the leftmost subtree of its parent, 656 * the rotation can not be done. 657 */ 658 return false; 659 } 660 661 lnode = rnode->parent->subtree[idx]; 662 if (lnode->keys > FILL_FACTOR) { 663 rotate_from_left(lnode, rnode, idx); 664 return true; 665 } 666 667 return false; 668 } 669 670 /** Rotate in a key from the right sibling or from the index node, if this operation can be done. 671 * 672 * @param lnode Node into which to add key from its right sibling 673 * or from the index node. 674 * 675 * @return True if the rotation was performed, false otherwise. 676 * 677 */ 678 static bool try_rotation_from_right(btree_node_t *lnode) 679 { 680 size_t idx; 681 btree_node_t *rnode; 682 683 /* 684 * If this is root node, the rotation can not be done. 685 */ 686 if (ROOT_NODE(lnode)) 687 return false; 688 689 idx = find_key_by_subtree(lnode->parent, lnode, false); 690 if (idx == lnode->parent->keys) { 691 /* 692 * If this node is the rightmost subtree of its parent, 693 * the rotation can not be done. 694 */ 695 return false; 696 } 697 698 rnode = lnode->parent->subtree[idx + 1]; 699 if (rnode->keys > FILL_FACTOR) { 700 rotate_from_right(lnode, rnode, idx); 701 return true; 702 } 703 704 return false; 705 } 706 707 /** Combine node with any of its siblings. 708 * 709 * The siblings are required to be below the fill factor. 710 * 711 * @param node Node to combine with one of its siblings. 712 * 713 * @return Pointer to the rightmost of the two nodes. 714 * 715 */ 716 static btree_node_t *node_combine(btree_node_t *node) 717 { 718 size_t idx; 719 btree_node_t *rnode; 720 size_t i; 721 722 ASSERT(!ROOT_NODE(node)); 723 724 idx = find_key_by_subtree(node->parent, node, false); 725 if (idx == node->parent->keys) { 726 /* 727 * Rightmost subtree of its parent, combine with the left sibling. 728 */ 729 idx--; 730 rnode = node; 731 node = node->parent->subtree[idx]; 732 } else 733 rnode = node->parent->subtree[idx + 1]; 734 735 /* Index nodes need to insert parent node key in between left and right node. */ 736 if (INDEX_NODE(node)) 737 node->key[node->keys++] = node->parent->key[idx]; 738 739 /* Copy the key-value-subtree triplets from the right node. */ 740 for (i = 0; i < rnode->keys; i++) { 741 node->key[node->keys + i] = rnode->key[i]; 742 node->value[node->keys + i] = rnode->value[i]; 743 744 if (INDEX_NODE(node)) { 745 node->subtree[node->keys + i] = rnode->subtree[i]; 746 rnode->subtree[i]->parent = node; 747 } 748 } 749 750 if (INDEX_NODE(node)) { 751 node->subtree[node->keys + i] = rnode->subtree[i]; 752 rnode->subtree[i]->parent = node; 753 } 754 755 node->keys += rnode->keys; 756 return rnode; 232 757 } 233 758 234 759 /** Recursively remove B-tree node. 235 760 * 236 * @param t B-tree.237 * @param key Key to be removed from the B-tree along with its associated value.761 * @param t B-tree. 762 * @param key Key to be removed from the B-tree along with its associated value. 238 763 * @param node Node where the key being removed resides. 239 */ 240 void _btree_remove(btree_t *t, btree_key_t key, btree_node_t *node) 764 * 765 */ 766 static void _btree_remove(btree_t *t, btree_key_t key, btree_node_t *node) 241 767 { 242 768 if (ROOT_NODE(node)) { 243 if ( node->keys == 1 && node->subtree[0]) {769 if ((node->keys == 1) && (node->subtree[0])) { 244 770 /* 245 771 * Free the current root and set new root. … … 257 783 node_remove_key_and_rsubtree(node, key); 258 784 } 785 259 786 return; 260 787 } … … 271 798 if (node->keys > FILL_FACTOR) { 272 799 size_t i; 273 800 274 801 /* 275 802 * The key can be immediatelly removed. … … 280 807 */ 281 808 node_remove_key_and_rsubtree(node, key); 809 282 810 for (i = 0; i < node->parent->keys; i++) { 283 811 if (node->parent->key[i] == key) 284 812 node->parent->key[i] = node->key[0]; 285 813 } 286 287 814 } else { 288 815 size_t idx; 289 btree_node_t *rnode, *parent; 290 816 btree_node_t *rnode; 817 btree_node_t *parent; 818 291 819 /* 292 820 * The node is below the fill factor as well as its left and right sibling. … … 298 826 node_remove_key_and_rsubtree(node, key); 299 827 rnode = node_combine(node); 828 300 829 if (LEAF_NODE(rnode)) 301 830 list_remove(&rnode->leaf_link); 831 302 832 idx = find_key_by_subtree(parent, rnode, true); 303 833 ASSERT((int) idx != -1); … … 307 837 } 308 838 839 /** Remove B-tree node. 840 * 841 * @param t B-tree. 842 * @param key Key to be removed from the B-tree along 843 * with its associated value. 844 * @param leaf_node If not NULL, pointer to the leaf node where 845 * the key is found. 846 * 847 */ 848 void btree_remove(btree_t *t, btree_key_t key, btree_node_t *leaf_node) 849 { 850 btree_node_t *lnode; 851 852 lnode = leaf_node; 853 if (!lnode) { 854 if (!btree_search(t, key, &lnode)) 855 panic("B-tree %p does not contain key %" PRIu64 ".", t, key); 856 } 857 858 _btree_remove(t, key, lnode); 859 } 860 309 861 /** Search key in a B-tree. 310 862 * 311 * @param t B-tree.312 * @param key Key to be searched.863 * @param t B-tree. 864 * @param key Key to be searched. 313 865 * @param leaf_node Address where to put pointer to visited leaf node. 314 866 * 315 867 * @return Pointer to value or NULL if there is no such key. 868 * 316 869 */ 317 870 void *btree_search(btree_t *t, btree_key_t key, btree_node_t **leaf_node) … … 323 876 */ 324 877 for (cur = t->root; cur; cur = next) { 325 326 /* Last iteration will set this with proper leaf node address. */ 878 /* 879 * Last iteration will set this with proper 880 * leaf node address. 881 */ 327 882 *leaf_node = cur; 328 883 … … 337 892 void *val; 338 893 size_t i; 339 894 340 895 /* 341 896 * Now if the key is smaller than cur->key[i] … … 347 902 next = cur->subtree[i]; 348 903 val = cur->value[i - 1]; 349 904 350 905 if (LEAF_NODE(cur)) 351 906 return key == cur->key[i - 1] ? val : NULL; 352 907 353 908 goto descend; 354 } 909 } 355 910 } 356 911 357 912 /* 358 * Last possibility is that the key is in the rightmost subtree. 913 * Last possibility is that the key is 914 * in the rightmost subtree. 359 915 */ 360 916 next = cur->subtree[i]; 361 917 val = cur->value[i - 1]; 918 362 919 if (LEAF_NODE(cur)) 363 920 return key == cur->key[i - 1] ? val : NULL; 364 921 } 365 922 descend: 366 367 } 368 923 ; 924 } 925 369 926 /* 370 * The key was not found in the *leaf_node and is smaller than any of its keys. 927 * The key was not found in the *leaf_node and 928 * is smaller than any of its keys. 371 929 */ 372 930 return NULL; … … 375 933 /** Return pointer to B-tree leaf node's left neighbour. 376 934 * 377 * @param t B-tree.935 * @param t B-tree. 378 936 * @param node Node whose left neighbour will be returned. 379 937 * 380 * @return Left neighbour of the node or NULL if the node does not have the left neighbour. 938 * @return Left neighbour of the node or NULL if the node 939 * does not have the left neighbour. 940 * 381 941 */ 382 942 btree_node_t *btree_leaf_node_left_neighbour(btree_t *t, btree_node_t *node) 383 943 { 384 944 ASSERT(LEAF_NODE(node)); 945 385 946 if (node->leaf_link.prev != &t->leaf_head) 386 947 return list_get_instance(node->leaf_link.prev, btree_node_t, leaf_link); … … 391 952 /** Return pointer to B-tree leaf node's right neighbour. 392 953 * 393 * @param t B-tree.954 * @param t B-tree. 394 955 * @param node Node whose right neighbour will be returned. 395 956 * 396 * @return Right neighbour of the node or NULL if the node does not have the right neighbour. 957 * @return Right neighbour of the node or NULL if the node 958 * does not have the right neighbour. 959 * 397 960 */ 398 961 btree_node_t *btree_leaf_node_right_neighbour(btree_t *t, btree_node_t *node) 399 962 { 400 963 ASSERT(LEAF_NODE(node)); 964 401 965 if (node->leaf_link.next != &t->leaf_head) 402 966 return list_get_instance(node->leaf_link.next, btree_node_t, leaf_link); … … 405 969 } 406 970 407 /** Initialize B-tree node.408 *409 * @param node B-tree node.410 */411 void node_initialize(btree_node_t *node)412 {413 int i;414 415 node->keys = 0;416 417 /* Clean also space for the extra key. */418 for (i = 0; i < BTREE_MAX_KEYS + 1; i++) {419 node->key[i] = 0;420 node->value[i] = NULL;421 node->subtree[i] = NULL;422 }423 node->subtree[i] = NULL;424 425 node->parent = NULL;426 427 link_initialize(&node->leaf_link);428 429 link_initialize(&node->bfs_link);430 node->depth = 0;431 }432 433 /** Insert key-value-lsubtree triplet into B-tree node.434 *435 * It is actually possible to have more keys than BTREE_MAX_KEYS.436 * This feature is used during insert by right rotation.437 *438 * @param node B-tree node into wich the new key is to be inserted.439 * @param key The key to be inserted.440 * @param value Pointer to value to be inserted.441 * @param lsubtree Pointer to the left subtree.442 */443 void node_insert_key_and_lsubtree(btree_node_t *node, btree_key_t key, void *value, btree_node_t *lsubtree)444 {445 size_t i;446 447 for (i = 0; i < node->keys; i++) {448 if (key < node->key[i]) {449 size_t j;450 451 for (j = node->keys; j > i; j--) {452 node->key[j] = node->key[j - 1];453 node->value[j] = node->value[j - 1];454 node->subtree[j + 1] = node->subtree[j];455 }456 node->subtree[j + 1] = node->subtree[j];457 break;458 }459 }460 node->key[i] = key;461 node->value[i] = value;462 node->subtree[i] = lsubtree;463 464 node->keys++;465 }466 467 /** Insert key-value-rsubtree triplet into B-tree node.468 *469 * It is actually possible to have more keys than BTREE_MAX_KEYS.470 * This feature is used during splitting the node when the471 * number of keys is BTREE_MAX_KEYS + 1. Insert by left rotation472 * also makes use of this feature.473 *474 * @param node B-tree node into wich the new key is to be inserted.475 * @param key The key to be inserted.476 * @param value Pointer to value to be inserted.477 * @param rsubtree Pointer to the right subtree.478 */479 void node_insert_key_and_rsubtree(btree_node_t *node, btree_key_t key, void *value, btree_node_t *rsubtree)480 {481 size_t i;482 483 for (i = 0; i < node->keys; i++) {484 if (key < node->key[i]) {485 size_t j;486 487 for (j = node->keys; j > i; j--) {488 node->key[j] = node->key[j - 1];489 node->value[j] = node->value[j - 1];490 node->subtree[j + 1] = node->subtree[j];491 }492 break;493 }494 }495 node->key[i] = key;496 node->value[i] = value;497 node->subtree[i + 1] = rsubtree;498 499 node->keys++;500 }501 502 /** Remove key and its left subtree pointer from B-tree node.503 *504 * Remove the key and eliminate gaps in node->key array.505 * Note that the value pointer and the left subtree pointer506 * is removed from the node as well.507 *508 * @param node B-tree node.509 * @param key Key to be removed.510 */511 void node_remove_key_and_lsubtree(btree_node_t *node, btree_key_t key)512 {513 size_t i, j;514 515 for (i = 0; i < node->keys; i++) {516 if (key == node->key[i]) {517 for (j = i + 1; j < node->keys; j++) {518 node->key[j - 1] = node->key[j];519 node->value[j - 1] = node->value[j];520 node->subtree[j - 1] = node->subtree[j];521 }522 node->subtree[j - 1] = node->subtree[j];523 node->keys--;524 return;525 }526 }527 panic("Node %p does not contain key %" PRIu64 ".", node, key);528 }529 530 /** Remove key and its right subtree pointer from B-tree node.531 *532 * Remove the key and eliminate gaps in node->key array.533 * Note that the value pointer and the right subtree pointer534 * is removed from the node as well.535 *536 * @param node B-tree node.537 * @param key Key to be removed.538 */539 void node_remove_key_and_rsubtree(btree_node_t *node, btree_key_t key)540 {541 size_t i, j;542 543 for (i = 0; i < node->keys; i++) {544 if (key == node->key[i]) {545 for (j = i + 1; j < node->keys; j++) {546 node->key[j - 1] = node->key[j];547 node->value[j - 1] = node->value[j];548 node->subtree[j] = node->subtree[j + 1];549 }550 node->keys--;551 return;552 }553 }554 panic("Node %p does not contain key %" PRIu64 ".", node, key);555 }556 557 /** Split full B-tree node and insert new key-value-right-subtree triplet.558 *559 * This function will split a node and return a pointer to a newly created560 * node containing keys greater than or equal to the greater of medians561 * (or median) of the old keys and the newly added key. It will also write562 * the median key to a memory address supplied by the caller.563 *564 * If the node being split is an index node, the median will not be565 * included in the new node. If the node is a leaf node,566 * the median will be copied there.567 *568 * @param node B-tree node wich is going to be split.569 * @param key The key to be inserted.570 * @param value Pointer to the value to be inserted.571 * @param rsubtree Pointer to the right subtree of the key being added.572 * @param median Address in memory, where the median key will be stored.573 *574 * @return Newly created right sibling of node.575 */576 btree_node_t *node_split(btree_node_t *node, btree_key_t key, void *value, btree_node_t *rsubtree, btree_key_t *median)577 {578 btree_node_t *rnode;579 size_t i, j;580 581 ASSERT(median);582 ASSERT(node->keys == BTREE_MAX_KEYS);583 584 /*585 * Use the extra space to store the extra node.586 */587 node_insert_key_and_rsubtree(node, key, value, rsubtree);588 589 /*590 * Compute median of keys.591 */592 *median = MEDIAN_HIGH(node);593 594 /*595 * Allocate and initialize new right sibling.596 */597 rnode = (btree_node_t *) slab_alloc(btree_node_slab, 0);598 node_initialize(rnode);599 rnode->parent = node->parent;600 rnode->depth = node->depth;601 602 /*603 * Copy big keys, values and subtree pointers to the new right sibling.604 * If this is an index node, do not copy the median.605 */606 i = (size_t) INDEX_NODE(node);607 for (i += MEDIAN_HIGH_INDEX(node), j = 0; i < node->keys; i++, j++) {608 rnode->key[j] = node->key[i];609 rnode->value[j] = node->value[i];610 rnode->subtree[j] = node->subtree[i];611 612 /*613 * Fix parent links in subtrees.614 */615 if (rnode->subtree[j])616 rnode->subtree[j]->parent = rnode;617 618 }619 rnode->subtree[j] = node->subtree[i];620 if (rnode->subtree[j])621 rnode->subtree[j]->parent = rnode;622 623 rnode->keys = j; /* Set number of keys of the new node. */624 node->keys /= 2; /* Shrink the old node. */625 626 return rnode;627 }628 629 /** Combine node with any of its siblings.630 *631 * The siblings are required to be below the fill factor.632 *633 * @param node Node to combine with one of its siblings.634 *635 * @return Pointer to the rightmost of the two nodes.636 */637 btree_node_t *node_combine(btree_node_t *node)638 {639 size_t idx;640 btree_node_t *rnode;641 size_t i;642 643 ASSERT(!ROOT_NODE(node));644 645 idx = find_key_by_subtree(node->parent, node, false);646 if (idx == node->parent->keys) {647 /*648 * Rightmost subtree of its parent, combine with the left sibling.649 */650 idx--;651 rnode = node;652 node = node->parent->subtree[idx];653 } else {654 rnode = node->parent->subtree[idx + 1];655 }656 657 /* Index nodes need to insert parent node key in between left and right node. */658 if (INDEX_NODE(node))659 node->key[node->keys++] = node->parent->key[idx];660 661 /* Copy the key-value-subtree triplets from the right node. */662 for (i = 0; i < rnode->keys; i++) {663 node->key[node->keys + i] = rnode->key[i];664 node->value[node->keys + i] = rnode->value[i];665 if (INDEX_NODE(node)) {666 node->subtree[node->keys + i] = rnode->subtree[i];667 rnode->subtree[i]->parent = node;668 }669 }670 if (INDEX_NODE(node)) {671 node->subtree[node->keys + i] = rnode->subtree[i];672 rnode->subtree[i]->parent = node;673 }674 675 node->keys += rnode->keys;676 677 return rnode;678 }679 680 /** Find key by its left or right subtree.681 *682 * @param node B-tree node.683 * @param subtree Left or right subtree of a key found in node.684 * @param right If true, subtree is a right subtree. If false, subtree is a left subtree.685 *686 * @return Index of the key associated with the subtree.687 */688 size_t find_key_by_subtree(btree_node_t *node, btree_node_t *subtree, bool right)689 {690 size_t i;691 692 for (i = 0; i < node->keys + 1; i++) {693 if (subtree == node->subtree[i])694 return i - (int) (right != false);695 }696 panic("Node %p does not contain subtree %p.", node, subtree);697 }698 699 /** Rotate one key-value-rsubtree triplet from the left sibling to the right sibling.700 *701 * The biggest key and its value and right subtree is rotated from the left node702 * to the right. If the node is an index node, than the parent node key belonging to703 * the left node takes part in the rotation.704 *705 * @param lnode Left sibling.706 * @param rnode Right sibling.707 * @param idx Index of the parent node key that is taking part in the rotation.708 */709 void rotate_from_left(btree_node_t *lnode, btree_node_t *rnode, size_t idx)710 {711 btree_key_t key;712 713 key = lnode->key[lnode->keys - 1];714 715 if (LEAF_NODE(lnode)) {716 void *value;717 718 value = lnode->value[lnode->keys - 1];719 node_remove_key_and_rsubtree(lnode, key);720 node_insert_key_and_lsubtree(rnode, key, value, NULL);721 lnode->parent->key[idx] = key;722 } else {723 btree_node_t *rsubtree;724 725 rsubtree = lnode->subtree[lnode->keys];726 node_remove_key_and_rsubtree(lnode, key);727 node_insert_key_and_lsubtree(rnode, lnode->parent->key[idx], NULL, rsubtree);728 lnode->parent->key[idx] = key;729 730 /* Fix parent link of the reconnected right subtree. */731 rsubtree->parent = rnode;732 }733 734 }735 736 /** Rotate one key-value-lsubtree triplet from the right sibling to the left sibling.737 *738 * The smallest key and its value and left subtree is rotated from the right node739 * to the left. If the node is an index node, than the parent node key belonging to740 * the right node takes part in the rotation.741 *742 * @param lnode Left sibling.743 * @param rnode Right sibling.744 * @param idx Index of the parent node key that is taking part in the rotation.745 */746 void rotate_from_right(btree_node_t *lnode, btree_node_t *rnode, size_t idx)747 {748 btree_key_t key;749 750 key = rnode->key[0];751 752 if (LEAF_NODE(rnode)) {753 void *value;754 755 value = rnode->value[0];756 node_remove_key_and_lsubtree(rnode, key);757 node_insert_key_and_rsubtree(lnode, key, value, NULL);758 rnode->parent->key[idx] = rnode->key[0];759 } else {760 btree_node_t *lsubtree;761 762 lsubtree = rnode->subtree[0];763 node_remove_key_and_lsubtree(rnode, key);764 node_insert_key_and_rsubtree(lnode, rnode->parent->key[idx], NULL, lsubtree);765 rnode->parent->key[idx] = key;766 767 /* Fix parent link of the reconnected left subtree. */768 lsubtree->parent = lnode;769 }770 771 }772 773 /** Insert key-value-rsubtree triplet and rotate the node to the left, if this operation can be done.774 *775 * Left sibling of the node (if it exists) is checked for free space.776 * If there is free space, the key is inserted and the smallest key of777 * the node is moved there. The index node which is the parent of both778 * nodes is fixed.779 *780 * @param node B-tree node.781 * @param inskey Key to be inserted.782 * @param insvalue Value to be inserted.783 * @param rsubtree Right subtree of inskey.784 *785 * @return True if the rotation was performed, false otherwise.786 */787 bool try_insert_by_rotation_to_left(btree_node_t *node, btree_key_t inskey, void *insvalue, btree_node_t *rsubtree)788 {789 size_t idx;790 btree_node_t *lnode;791 792 /*793 * If this is root node, the rotation can not be done.794 */795 if (ROOT_NODE(node))796 return false;797 798 idx = find_key_by_subtree(node->parent, node, true);799 if ((int) idx == -1) {800 /*801 * If this node is the leftmost subtree of its parent,802 * the rotation can not be done.803 */804 return false;805 }806 807 lnode = node->parent->subtree[idx];808 if (lnode->keys < BTREE_MAX_KEYS) {809 /*810 * The rotaion can be done. The left sibling has free space.811 */812 node_insert_key_and_rsubtree(node, inskey, insvalue, rsubtree);813 rotate_from_right(lnode, node, idx);814 return true;815 }816 817 return false;818 }819 820 /** Insert key-value-rsubtree triplet and rotate the node to the right, if this operation can be done.821 *822 * Right sibling of the node (if it exists) is checked for free space.823 * If there is free space, the key is inserted and the biggest key of824 * the node is moved there. The index node which is the parent of both825 * nodes is fixed.826 *827 * @param node B-tree node.828 * @param inskey Key to be inserted.829 * @param insvalue Value to be inserted.830 * @param rsubtree Right subtree of inskey.831 *832 * @return True if the rotation was performed, false otherwise.833 */834 bool try_insert_by_rotation_to_right(btree_node_t *node, btree_key_t inskey, void *insvalue, btree_node_t *rsubtree)835 {836 size_t idx;837 btree_node_t *rnode;838 839 /*840 * If this is root node, the rotation can not be done.841 */842 if (ROOT_NODE(node))843 return false;844 845 idx = find_key_by_subtree(node->parent, node, false);846 if (idx == node->parent->keys) {847 /*848 * If this node is the rightmost subtree of its parent,849 * the rotation can not be done.850 */851 return false;852 }853 854 rnode = node->parent->subtree[idx + 1];855 if (rnode->keys < BTREE_MAX_KEYS) {856 /*857 * The rotaion can be done. The right sibling has free space.858 */859 node_insert_key_and_rsubtree(node, inskey, insvalue, rsubtree);860 rotate_from_left(node, rnode, idx);861 return true;862 }863 864 return false;865 }866 867 /** Rotate in a key from the left sibling or from the index node, if this operation can be done.868 *869 * @param rnode Node into which to add key from its left sibling or from the index node.870 *871 * @return True if the rotation was performed, false otherwise.872 */873 bool try_rotation_from_left(btree_node_t *rnode)874 {875 size_t idx;876 btree_node_t *lnode;877 878 /*879 * If this is root node, the rotation can not be done.880 */881 if (ROOT_NODE(rnode))882 return false;883 884 idx = find_key_by_subtree(rnode->parent, rnode, true);885 if ((int) idx == -1) {886 /*887 * If this node is the leftmost subtree of its parent,888 * the rotation can not be done.889 */890 return false;891 }892 893 lnode = rnode->parent->subtree[idx];894 if (lnode->keys > FILL_FACTOR) {895 rotate_from_left(lnode, rnode, idx);896 return true;897 }898 899 return false;900 }901 902 /** Rotate in a key from the right sibling or from the index node, if this operation can be done.903 *904 * @param lnode Node into which to add key from its right sibling or from the index node.905 *906 * @return True if the rotation was performed, false otherwise.907 */908 bool try_rotation_from_right(btree_node_t *lnode)909 {910 size_t idx;911 btree_node_t *rnode;912 913 /*914 * If this is root node, the rotation can not be done.915 */916 if (ROOT_NODE(lnode))917 return false;918 919 idx = find_key_by_subtree(lnode->parent, lnode, false);920 if (idx == lnode->parent->keys) {921 /*922 * If this node is the rightmost subtree of its parent,923 * the rotation can not be done.924 */925 return false;926 }927 928 rnode = lnode->parent->subtree[idx + 1];929 if (rnode->keys > FILL_FACTOR) {930 rotate_from_right(lnode, rnode, idx);931 return true;932 }933 934 return false;935 }936 937 971 /** Print B-tree. 938 972 * 939 973 * @param t Print out B-tree. 974 * 940 975 */ 941 976 void btree_print(btree_t *t) … … 944 979 int depth = t->root->depth; 945 980 link_t head, *cur; 946 981 947 982 printf("Printing B-tree:\n"); 948 983 list_initialize(&head); 949 984 list_append(&t->root->bfs_link, &head); 950 985 951 986 /* 952 987 * Use BFS search to print out the tree. 953 988 * Levels are distinguished from one another by node->depth. 954 */ 989 */ 955 990 while (!list_empty(&head)) { 956 991 link_t *hlp; … … 968 1003 depth = node->depth; 969 1004 } 970 1005 971 1006 printf("("); 1007 972 1008 for (i = 0; i < node->keys; i++) { 973 1009 printf("%" PRIu64 "%s", node->key[i], i < node->keys - 1 ? "," : ""); … … 976 1012 } 977 1013 } 978 if (node->depth && node->subtree[i]) { 1014 1015 if (node->depth && node->subtree[i]) 979 1016 list_append(&node->subtree[i]->bfs_link, &head); 980 }1017 981 1018 printf(")"); 982 1019 } 1020 983 1021 printf("\n"); 984 1022 … … 990 1028 991 1029 ASSERT(node); 992 1030 993 1031 printf("("); 1032 994 1033 for (i = 0; i < node->keys; i++) 995 1034 printf("%" PRIu64 "%s", node->key[i], i < node->keys - 1 ? "," : ""); 1035 996 1036 printf(")"); 997 1037 } 1038 998 1039 printf("\n"); 999 1040 } -
kernel/generic/src/cpu/cpu.c
rb5382d4f re3ee9b9 119 119 /** @} 120 120 */ 121 -
kernel/generic/src/mm/as.c
rb5382d4f re3ee9b9 116 116 as_t *AS_KERNEL = NULL; 117 117 118 static unsigned int area_flags_to_page_flags(unsigned int);119 static as_area_t *find_area_and_lock(as_t *, uintptr_t);120 static bool check_area_conflicts(as_t *, uintptr_t, size_t, as_area_t *);121 static void sh_info_remove_reference(share_info_t *);122 123 118 static int as_constructor(void *obj, unsigned int flags) 124 119 { … … 296 291 if (atomic_predec(&as->refcount) == 0) 297 292 as_destroy(as); 293 } 294 295 /** Check area conflicts with other areas. 296 * 297 * @param as Address space. 298 * @param va Starting virtual address of the area being tested. 299 * @param size Size of the area being tested. 300 * @param avoid_area Do not touch this area. 301 * 302 * @return True if there is no conflict, false otherwise. 303 * 304 */ 305 static bool check_area_conflicts(as_t *as, uintptr_t va, size_t size, 306 as_area_t *avoid_area) 307 { 308 ASSERT(mutex_locked(&as->lock)); 309 310 /* 311 * We don't want any area to have conflicts with NULL page. 312 * 313 */ 314 if (overlaps(va, size, NULL, PAGE_SIZE)) 315 return false; 316 317 /* 318 * The leaf node is found in O(log n), where n is proportional to 319 * the number of address space areas belonging to as. 320 * The check for conflicts is then attempted on the rightmost 321 * record in the left neighbour, the leftmost record in the right 322 * neighbour and all records in the leaf node itself. 323 * 324 */ 325 btree_node_t *leaf; 326 as_area_t *area = 327 (as_area_t *) btree_search(&as->as_area_btree, va, &leaf); 328 if (area) { 329 if (area != avoid_area) 330 return false; 331 } 332 333 /* First, check the two border cases. */ 334 btree_node_t *node = 335 btree_leaf_node_left_neighbour(&as->as_area_btree, leaf); 336 if (node) { 337 area = (as_area_t *) node->value[node->keys - 1]; 338 339 mutex_lock(&area->lock); 340 341 if (overlaps(va, size, area->base, area->pages * PAGE_SIZE)) { 342 mutex_unlock(&area->lock); 343 return false; 344 } 345 346 mutex_unlock(&area->lock); 347 } 348 349 node = btree_leaf_node_right_neighbour(&as->as_area_btree, leaf); 350 if (node) { 351 area = (as_area_t *) node->value[0]; 352 353 mutex_lock(&area->lock); 354 355 if (overlaps(va, size, area->base, area->pages * PAGE_SIZE)) { 356 mutex_unlock(&area->lock); 357 return false; 358 } 359 360 mutex_unlock(&area->lock); 361 } 362 363 /* Second, check the leaf node. */ 364 btree_key_t i; 365 for (i = 0; i < leaf->keys; i++) { 366 area = (as_area_t *) leaf->value[i]; 367 368 if (area == avoid_area) 369 continue; 370 371 mutex_lock(&area->lock); 372 373 if (overlaps(va, size, area->base, area->pages * PAGE_SIZE)) { 374 mutex_unlock(&area->lock); 375 return false; 376 } 377 378 mutex_unlock(&area->lock); 379 } 380 381 /* 382 * So far, the area does not conflict with other areas. 383 * Check if it doesn't conflict with kernel address space. 384 * 385 */ 386 if (!KERNEL_ADDRESS_SPACE_SHADOWED) { 387 return !overlaps(va, size, 388 KERNEL_ADDRESS_SPACE_START, 389 KERNEL_ADDRESS_SPACE_END - KERNEL_ADDRESS_SPACE_START); 390 } 391 392 return true; 298 393 } 299 394 … … 357 452 358 453 return area; 454 } 455 456 /** Find address space area and lock it. 457 * 458 * @param as Address space. 459 * @param va Virtual address. 460 * 461 * @return Locked address space area containing va on success or 462 * NULL on failure. 463 * 464 */ 465 static as_area_t *find_area_and_lock(as_t *as, uintptr_t va) 466 { 467 ASSERT(mutex_locked(&as->lock)); 468 469 btree_node_t *leaf; 470 as_area_t *area = (as_area_t *) btree_search(&as->as_area_btree, va, &leaf); 471 if (area) { 472 /* va is the base address of an address space area */ 473 mutex_lock(&area->lock); 474 return area; 475 } 476 477 /* 478 * Search the leaf node and the righmost record of its left neighbour 479 * to find out whether this is a miss or va belongs to an address 480 * space area found there. 481 * 482 */ 483 484 /* First, search the leaf node itself. */ 485 btree_key_t i; 486 487 for (i = 0; i < leaf->keys; i++) { 488 area = (as_area_t *) leaf->value[i]; 489 490 mutex_lock(&area->lock); 491 492 if ((area->base <= va) && (va < area->base + area->pages * PAGE_SIZE)) 493 return area; 494 495 mutex_unlock(&area->lock); 496 } 497 498 /* 499 * Second, locate the left neighbour and test its last record. 500 * Because of its position in the B+tree, it must have base < va. 501 * 502 */ 503 btree_node_t *lnode = btree_leaf_node_left_neighbour(&as->as_area_btree, leaf); 504 if (lnode) { 505 area = (as_area_t *) lnode->value[lnode->keys - 1]; 506 507 mutex_lock(&area->lock); 508 509 if (va < area->base + area->pages * PAGE_SIZE) 510 return area; 511 512 mutex_unlock(&area->lock); 513 } 514 515 return NULL; 359 516 } 360 517 … … 553 710 } 554 711 712 /** Remove reference to address space area share info. 713 * 714 * If the reference count drops to 0, the sh_info is deallocated. 715 * 716 * @param sh_info Pointer to address space area share info. 717 * 718 */ 719 static void sh_info_remove_reference(share_info_t *sh_info) 720 { 721 bool dealloc = false; 722 723 mutex_lock(&sh_info->lock); 724 ASSERT(sh_info->refcount); 725 726 if (--sh_info->refcount == 0) { 727 dealloc = true; 728 link_t *cur; 729 730 /* 731 * Now walk carefully the pagemap B+tree and free/remove 732 * reference from all frames found there. 733 */ 734 for (cur = sh_info->pagemap.leaf_head.next; 735 cur != &sh_info->pagemap.leaf_head; cur = cur->next) { 736 btree_node_t *node 737 = list_get_instance(cur, btree_node_t, leaf_link); 738 btree_key_t i; 739 740 for (i = 0; i < node->keys; i++) 741 frame_free((uintptr_t) node->value[i]); 742 } 743 744 } 745 mutex_unlock(&sh_info->lock); 746 747 if (dealloc) { 748 btree_destroy(&sh_info->pagemap); 749 free(sh_info); 750 } 751 } 752 555 753 /** Destroy address space area. 556 754 * … … 805 1003 } 806 1004 1005 /** Convert address space area flags to page flags. 1006 * 1007 * @param aflags Flags of some address space area. 1008 * 1009 * @return Flags to be passed to page_mapping_insert(). 1010 * 1011 */ 1012 static unsigned int area_flags_to_page_flags(unsigned int aflags) 1013 { 1014 unsigned int flags = PAGE_USER | PAGE_PRESENT; 1015 1016 if (aflags & AS_AREA_READ) 1017 flags |= PAGE_READ; 1018 1019 if (aflags & AS_AREA_WRITE) 1020 flags |= PAGE_WRITE; 1021 1022 if (aflags & AS_AREA_EXEC) 1023 flags |= PAGE_EXEC; 1024 1025 if (aflags & AS_AREA_CACHEABLE) 1026 flags |= PAGE_CACHEABLE; 1027 1028 return flags; 1029 } 1030 807 1031 /** Change adress space area flags. 808 1032 * … … 1161 1385 } 1162 1386 1163 /** Convert address space area flags to page flags. 1164 * 1165 * @param aflags Flags of some address space area. 1166 * 1167 * @return Flags to be passed to page_mapping_insert(). 1168 * 1169 */ 1170 unsigned int area_flags_to_page_flags(unsigned int aflags) 1171 { 1172 unsigned int flags = PAGE_USER | PAGE_PRESENT; 1173 1174 if (aflags & AS_AREA_READ) 1175 flags |= PAGE_READ; 1176 1177 if (aflags & AS_AREA_WRITE) 1178 flags |= PAGE_WRITE; 1179 1180 if (aflags & AS_AREA_EXEC) 1181 flags |= PAGE_EXEC; 1182 1183 if (aflags & AS_AREA_CACHEABLE) 1184 flags |= PAGE_CACHEABLE; 1185 1186 return flags; 1187 } 1387 1188 1388 1189 1389 /** Compute flags for virtual address translation subsytem. … … 1272 1472 /** Test whether page tables are locked. 1273 1473 * 1274 * @param as 1275 * 1276 * @return 1277 * 1474 * @param as Address space where the page tables belong. 1475 * 1476 * @return True if the page tables belonging to the address soace 1477 * are locked, otherwise false. 1278 1478 */ 1279 1479 bool page_table_locked(as_t *as) … … 1283 1483 1284 1484 return as_operations->page_table_locked(as); 1285 }1286 1287 1288 /** Find address space area and lock it.1289 *1290 * @param as Address space.1291 * @param va Virtual address.1292 *1293 * @return Locked address space area containing va on success or1294 * NULL on failure.1295 *1296 */1297 as_area_t *find_area_and_lock(as_t *as, uintptr_t va)1298 {1299 ASSERT(mutex_locked(&as->lock));1300 1301 btree_node_t *leaf;1302 as_area_t *area = (as_area_t *) btree_search(&as->as_area_btree, va, &leaf);1303 if (area) {1304 /* va is the base address of an address space area */1305 mutex_lock(&area->lock);1306 return area;1307 }1308 1309 /*1310 * Search the leaf node and the righmost record of its left neighbour1311 * to find out whether this is a miss or va belongs to an address1312 * space area found there.1313 *1314 */1315 1316 /* First, search the leaf node itself. */1317 btree_key_t i;1318 1319 for (i = 0; i < leaf->keys; i++) {1320 area = (as_area_t *) leaf->value[i];1321 1322 mutex_lock(&area->lock);1323 1324 if ((area->base <= va) && (va < area->base + area->pages * PAGE_SIZE))1325 return area;1326 1327 mutex_unlock(&area->lock);1328 }1329 1330 /*1331 * Second, locate the left neighbour and test its last record.1332 * Because of its position in the B+tree, it must have base < va.1333 *1334 */1335 btree_node_t *lnode = btree_leaf_node_left_neighbour(&as->as_area_btree, leaf);1336 if (lnode) {1337 area = (as_area_t *) lnode->value[lnode->keys - 1];1338 1339 mutex_lock(&area->lock);1340 1341 if (va < area->base + area->pages * PAGE_SIZE)1342 return area;1343 1344 mutex_unlock(&area->lock);1345 }1346 1347 return NULL;1348 }1349 1350 /** Check area conflicts with other areas.1351 *1352 * @param as Address space.1353 * @param va Starting virtual address of the area being tested.1354 * @param size Size of the area being tested.1355 * @param avoid_area Do not touch this area.1356 *1357 * @return True if there is no conflict, false otherwise.1358 *1359 */1360 bool check_area_conflicts(as_t *as, uintptr_t va, size_t size,1361 as_area_t *avoid_area)1362 {1363 ASSERT(mutex_locked(&as->lock));1364 1365 /*1366 * We don't want any area to have conflicts with NULL page.1367 *1368 */1369 if (overlaps(va, size, NULL, PAGE_SIZE))1370 return false;1371 1372 /*1373 * The leaf node is found in O(log n), where n is proportional to1374 * the number of address space areas belonging to as.1375 * The check for conflicts is then attempted on the rightmost1376 * record in the left neighbour, the leftmost record in the right1377 * neighbour and all records in the leaf node itself.1378 *1379 */1380 btree_node_t *leaf;1381 as_area_t *area =1382 (as_area_t *) btree_search(&as->as_area_btree, va, &leaf);1383 if (area) {1384 if (area != avoid_area)1385 return false;1386 }1387 1388 /* First, check the two border cases. */1389 btree_node_t *node =1390 btree_leaf_node_left_neighbour(&as->as_area_btree, leaf);1391 if (node) {1392 area = (as_area_t *) node->value[node->keys - 1];1393 1394 mutex_lock(&area->lock);1395 1396 if (overlaps(va, size, area->base, area->pages * PAGE_SIZE)) {1397 mutex_unlock(&area->lock);1398 return false;1399 }1400 1401 mutex_unlock(&area->lock);1402 }1403 1404 node = btree_leaf_node_right_neighbour(&as->as_area_btree, leaf);1405 if (node) {1406 area = (as_area_t *) node->value[0];1407 1408 mutex_lock(&area->lock);1409 1410 if (overlaps(va, size, area->base, area->pages * PAGE_SIZE)) {1411 mutex_unlock(&area->lock);1412 return false;1413 }1414 1415 mutex_unlock(&area->lock);1416 }1417 1418 /* Second, check the leaf node. */1419 btree_key_t i;1420 for (i = 0; i < leaf->keys; i++) {1421 area = (as_area_t *) leaf->value[i];1422 1423 if (area == avoid_area)1424 continue;1425 1426 mutex_lock(&area->lock);1427 1428 if (overlaps(va, size, area->base, area->pages * PAGE_SIZE)) {1429 mutex_unlock(&area->lock);1430 return false;1431 }1432 1433 mutex_unlock(&area->lock);1434 }1435 1436 /*1437 * So far, the area does not conflict with other areas.1438 * Check if it doesn't conflict with kernel address space.1439 *1440 */1441 if (!KERNEL_ADDRESS_SPACE_SHADOWED) {1442 return !overlaps(va, size,1443 KERNEL_ADDRESS_SPACE_START,1444 KERNEL_ADDRESS_SPACE_END - KERNEL_ADDRESS_SPACE_START);1445 }1446 1447 return true;1448 1485 } 1449 1486 … … 1960 1997 } 1961 1998 1962 /** Remove reference to address space area share info.1963 *1964 * If the reference count drops to 0, the sh_info is deallocated.1965 *1966 * @param sh_info Pointer to address space area share info.1967 *1968 */1969 void sh_info_remove_reference(share_info_t *sh_info)1970 {1971 bool dealloc = false;1972 1973 mutex_lock(&sh_info->lock);1974 ASSERT(sh_info->refcount);1975 1976 if (--sh_info->refcount == 0) {1977 dealloc = true;1978 link_t *cur;1979 1980 /*1981 * Now walk carefully the pagemap B+tree and free/remove1982 * reference from all frames found there.1983 */1984 for (cur = sh_info->pagemap.leaf_head.next;1985 cur != &sh_info->pagemap.leaf_head; cur = cur->next) {1986 btree_node_t *node1987 = list_get_instance(cur, btree_node_t, leaf_link);1988 btree_key_t i;1989 1990 for (i = 0; i < node->keys; i++)1991 frame_free((uintptr_t) node->value[i]);1992 }1993 1994 }1995 mutex_unlock(&sh_info->lock);1996 1997 if (dealloc) {1998 btree_destroy(&sh_info->pagemap);1999 free(sh_info);2000 }2001 }2002 2003 1999 /* 2004 2000 * Address space related syscalls. -
kernel/generic/src/mm/page.c
rb5382d4f re3ee9b9 38 38 * mappings between virtual addresses and physical addresses. 39 39 * Functions here are mere wrappers that call the real implementation. 40 * They however, define the single interface. 40 * They however, define the single interface. 41 41 * 42 42 */ -
kernel/generic/src/proc/the.c
rb5382d4f re3ee9b9 33 33 /** 34 34 * @file 35 * @brief 35 * @brief THE structure functions. 36 36 * 37 37 * This file contains functions to manage the THE structure. … … 43 43 44 44 #include <arch.h> 45 46 45 47 46 /** Initialize THE structure
Note:
See TracChangeset
for help on using the changeset viewer.