2021-05-13 20:29:44 +08:00

172 lines
3.7 KiB
C

/*
* Copyright (c) 2020 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
* OS-Lab-2020 (i.e., ChCore) is licensed under the Mulan PSL v1.
* You can use this software according to the terms and conditions of the Mulan PSL v1.
* You may obtain a copy of Mulan PSL v1 at:
* http://license.coscl.org.cn/MulanPSL
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
* PURPOSE.
* See the Mulan PSL v1 for more details.
*/
#ifdef CHCORE
#include <common/kmalloc.h>
#include <common/kprint.h>
#include <common/macro.h>
#include <common/radix.h>
#endif
#include <common/errno.h>
/* ceil(a/b) */
#define DIV_UP(a, b) (((a)+(b)-1)/(b))
#define RADIX_LEVELS (DIV_UP(RADIX_MAX_BITS, RADIX_NODE_BITS))
struct radix *new_radix(void)
{
struct radix *radix;
radix = kzalloc(sizeof(*radix));
BUG_ON(!radix);
return radix;
}
void init_radix(struct radix *radix)
{
radix->root = kzalloc(sizeof(*radix->root));
BUG_ON(!radix->root);
radix->value_deleter = NULL;
}
void init_radix_w_deleter(struct radix *radix, void (*value_deleter) (void *))
{
init_radix(radix);
radix->value_deleter = value_deleter;
}
static struct radix_node *new_radix_node(void)
{
struct radix_node *n = kzalloc(sizeof(struct radix_node));
// kdebug("radix_new_node: %p\n", n);
if (!n) {
return ERR_PTR(-ENOMEM);
}
return n;
}
int radix_add(struct radix *radix, u64 key, void *value)
{
struct radix_node *node;
struct radix_node *new;
u16 index[RADIX_LEVELS];
int i;
int k;
// kdebug("==============> radix= %p\n", radix);
if (!radix->root) {
new = new_radix_node();
if (IS_ERR(new))
return -ENOMEM;
radix->root = new;
}
node = radix->root;
// kdebug("radix->root = %p\n", node);
/* calculate index for each level */
for (i = 0; i < RADIX_LEVELS; ++i) {
index[i] = key & RADIX_NODE_MASK;
key >>= RADIX_NODE_BITS;
}
/* the intermediate levels */
for (i = RADIX_LEVELS - 1; i > 0; --i) {
k = index[i];
if (!node->children[k]) {
new = new_radix_node();
if (IS_ERR(new))
return -ENOMEM;
node->children[k] = new;
}
node = node->children[k];
}
/* the leaf level */
k = index[0];
node->values[k] = value;
return 0;
}
void *radix_get(struct radix *radix, u64 key)
{
struct radix_node *node;
u16 index[RADIX_LEVELS];
int i;
int k;
if (!radix->root)
return NULL;
node = radix->root;
/* calculate index for each level */
for (i = 0; i < RADIX_LEVELS; ++i) {
index[i] = key & RADIX_NODE_MASK;
key >>= RADIX_NODE_BITS;
}
/* the intermediate levels */
for (i = RADIX_LEVELS - 1; i > 0; --i) {
k = index[i];
if (!node->children[k])
return NULL;
node = node->children[k];
}
/* the leaf level */
k = index[0];
return node->values[k];
}
int radix_del(struct radix *radix, u64 key)
{
return radix_add(radix, key, NULL);
}
static void radix_free_node(struct radix_node *node, int node_level,
void (*value_deleter) (void *))
{
int i;
WARN_ON(!node, "should not try to free a node pointed by NULL");
if (node_level == RADIX_LEVELS - 1) {
if (value_deleter) {
for (i = 0; i < RADIX_NODE_SIZE; i++) {
if (node->values[i])
value_deleter(node->values[i]);
}
}
} else {
for (i = 0; i < RADIX_NODE_SIZE; i++) {
if (node->children[i])
radix_free_node(node->children[i],
node_level + 1, value_deleter);
}
}
}
int radix_free(struct radix *radix)
{
if (!radix || !radix->root) {
WARN("trying to free an empty radix tree");
return -EINVAL;
}
// recurssively free nodes and values (if value_deleter is not NULL)
radix_free_node(radix->root, 0, radix->value_deleter);
return 0;
}