diff --git a/.vscode/settings.json b/.vscode/settings.json index 5ea0ca164..21352bc2c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -140,6 +140,8 @@ "chardev.h": "c", "rootfs.h": "c", "tty.h": "c", + "idr.h": "c", + "ktest_utils.h": "c", "kthread.h": "c", "lockref.h": "c", "compiler_attributes.h": "c" diff --git a/kernel/common/idr.h b/kernel/common/idr.h new file mode 100644 index 000000000..a631f914d --- /dev/null +++ b/kernel/common/idr.h @@ -0,0 +1,139 @@ + + +#include <common/errno.h> +#include <common/spinlock.h> + +/** + * idr: 基于radix-tree的ID-pointer的数据结构 + * 主要功能: + * 1. 获取一个ID, 并且将该ID与一个指针绑定 - 需要外部加锁 + * 2. 删除一个已分配的ID - 需要外部加锁 + * 3. 根据ID查找对应的指针 (读操作,看情况加锁) + * 4. 根据ID使用新的ptr替换旧的ptr - 需要外部加锁 + * + * 附加功能: + * 1. 给定starting_id, 查询下一个已分配的next_id (即:next_id>starting_id) + * 2. 销毁整个idr + * + * + * .... 待实现 + */ + +// 默认64位机器 +#define IDR_BITS 6 +#define IDR_FULL 0xfffffffffffffffful + +// size = 64 +#define IDR_SIZE (1 << IDR_BITS) +#define IDR_MASK ((1 << IDR_BITS) - 1) + +// 能管理的ID范围[0:1<<31] +#define MAX_ID_SHIFT (sizeof(int) * 8 - 1) +#define MAX_ID_BIT (1U << MAX_ID_SHIFT) +#define MAX_ID_MASK (MAX_ID_BIT - 1) + +// IDR可能最大的层次 以及 IDR预分配空间的最大限制 +#define MAX_LEVEL (MAX_ID_SHIFT + IDR_BITS - 1) / IDR_BITS +#define IDR_FREE_MAX (MAX_LEVEL << 1) + +// 给定layer, 计算完全64叉树的大小 +#define TREE_SIZE(layer) ((layer >= 0) ? (1ull << ((layer + 1) * IDR_BITS)) : 1) + +// 计算最后(最低位)一个1的位置 (注意使用64位的版本) +#define __lowbit_id(x) ((x) ? (__builtin_ctzll(x)) : -1) + +// 计算最前(最高位)一个1的位置 (注意使用64位的版本) +#define __mostbit_id(x) ((x) ? (__builtin_clzll(x)) : -1) + +// radix-tree 节点定义 +struct idr_layer +{ + struct idr_layer *ary[IDR_SIZE]; // IDR_SIZE叉树 + unsigned long bitmap; // 每一位表示这个子树是否被使用 + unsigned long full; // 64个儿子子树, 每一位代表一个子树是否满了 + int layer; // 层数(从底向上) +}; + +// idr: 将id与pointer绑定的数据结构 +struct idr +{ + struct idr_layer *top; + struct idr_layer *free_list; + int id_free_cnt; + spinlock_t lock; +}; + +#define DECLARE_IDR(name) \ + struct idr name = {0}; \ + name.top = (NULL); \ + name.free_list = (NULL); \ + name.id_free_cnt = (0); \ + spin_init(&name.lock); + +#define DECLARE_IDR_LAYER(name) \ + struct idr_layer name = {0}; \ + memset(name, 0, sizeof(struct idr_layer)); + +/** + * 对外函数声明 + **/ +int idr_pre_get(struct idr *idp, gfp_t gfp_mask); +int idr_get_new(struct idr *idp, void *ptr, int *id); +void idr_remove(struct idr *idp, int id); +void idr_remove_all(struct idr *idp); +void idr_destroy(struct idr *idp); +void *idr_find(struct idr *idp, int id); +void *idr_find_next(struct idr *idp, int start_id); +void *idr_find_next_getid(struct idr *idp, int start_id, int *nextid); +int idr_replace_get_old(struct idr *idp, void *ptr, int id, void **oldptr); +int idr_replace(struct idr *idp, void *ptr, int id); +void idr_init(struct idr *idp); + +/** + * ida: 基于IDR实现的ID分配器 + * 主要功能: + * 1. 获取一个未分配的ID + * 2. 询问一个ID是否被分配 + * 3. 删除一个已分配ID + * + * 附加功能: + * 1. 暂定 + */ + +// 一个块的大小 - 即 sizeof(struct ida_bitmap) +#define IDA_CHUNK_SIZE 128 +// ida_bitmap的长度 +#define IDA_BITMAP_LONGS (IDA_CHUNK_SIZE / sizeof(long) - 1) +// 对应linux的IDA_BITMAP_BITS = 960 = 15 * 64 +#define IDA_FULL (IDA_BITMAP_LONGS * sizeof(long) * 8) +#define IDA_BITMAP_BITS IDA_FULL +#define IDA_BMP_SIZE (8 * sizeof(long)) + +// 自定义bitmap +struct ida_bitmap +{ + unsigned long count; // bitmap中已经分配的id数量 + unsigned long bitmap[IDA_BITMAP_LONGS]; // bitmap本身, 每一个bit代表一个ID +}; + +// id-allocater 管理+分配ID的数据结构 +struct ida +{ + struct idr idr; + struct ida_bitmap *free_list; // 预分配的数据块 +}; + +#define DECLARE_IDA(name) \ + struct ida name = {0}; \ + idr_init(&name.idr); \ + name.free_list = (NULL); + +/** + * 对外函数声明 + */ +void ida_init(struct ida *ida_p); +int ida_pre_get(struct ida *ida_p, gfp_t gfp_mask); +int ida_get_new(struct ida *ida_p, int *p_id); +bool ida_count(struct ida *ida_p, int id); +void ida_remove(struct ida *ida_p, int id); +void ida_destroy(struct ida *ida_p); \ No newline at end of file diff --git a/kernel/ktest/Makefile b/kernel/ktest/Makefile index df7ec2aff..2509f0ce1 100644 --- a/kernel/ktest/Makefile +++ b/kernel/ktest/Makefile @@ -2,7 +2,7 @@ CFLAGS += -I . -all: ktest.o bitree.o kfifo.o mutex.o +all: ktest.o bitree.o kfifo.o mutex.o idr.o ktest.o: ktest.c gcc $(CFLAGS) -c ktest.c -o ktest.o @@ -14,4 +14,7 @@ kfifo.o: test-kfifo.c gcc $(CFLAGS) -c test-kfifo.c -o test-kfifo.o mutex.o: test-mutex.c - gcc $(CFLAGS) -c test-mutex.c -o test-mutex.o \ No newline at end of file + gcc $(CFLAGS) -c test-mutex.c -o test-mutex.o + +idr.o: test-idr.c + gcc $(CFLAGS) -c test-idr.c -o test-idr.o \ No newline at end of file diff --git a/kernel/ktest/ktest.h b/kernel/ktest/ktest.h index b1a699361..cd6b041f5 100644 --- a/kernel/ktest/ktest.h +++ b/kernel/ktest/ktest.h @@ -4,6 +4,7 @@ int ktest_test_bitree(void* arg); int ktest_test_kfifo(void* arg); int ktest_test_mutex(void* arg); +int ktest_test_idr(void* arg); /** * @brief 开启一个新的内核线程以进行测试 diff --git a/kernel/ktest/test-idr.c b/kernel/ktest/test-idr.c new file mode 100644 index 000000000..cec3c3f50 --- /dev/null +++ b/kernel/ktest/test-idr.c @@ -0,0 +1,529 @@ + + +#include "ktest.h" +#include "ktest_utils.h" +#include <common/idr.h> + +/** + * @brief 测试idr的构建,预获取空间是否成功 + * + * 以下函数将被测试: + * 1. idr_pre_get + * 2. DECLARE_IDR + * 3. idr_init + * 4. idr_destroy + * + * 同时还会(间接)测试一些内部函数: + * 1. move_to_free_list + * + * @param arg0 + * @param arg1 + */ +static long ktest_idr_case0(uint64_t arg0, uint64_t arg1) +{ + unsigned long bitmap = -1; + assert((int)(bitmap == IDR_FULL)); + + DECLARE_IDR(k_idr); + assert(k_idr.top == NULL); // 刚被创建,必须是NULL + assert(k_idr.id_free_cnt == 0); // 必须是0 + assert(k_idr.free_list == NULL); + + k_idr.id_free_cnt = arg1; + idr_init(&k_idr); + assert(k_idr.id_free_cnt == 0); + + assert(idr_pre_get(&k_idr, 0) == 1); + assert(k_idr.id_free_cnt == IDR_FREE_MAX); + + for (int i = 1; i < 64; i++) + { + int id = __lowbit_id(i), chk_id = -1; + for (int j = 0; j < 64; j++) + if ((i >> j) & 1) + { + chk_id = j; + break; + } + assert(id == chk_id); + } + + // 销毁 + idr_destroy(&k_idr); + assert(k_idr.id_free_cnt == 0); + assert(k_idr.free_list == NULL); + assert(k_idr.top == NULL); + + return 0; +} + +/** + * @brief 测试id的获取,id的删除,id的全体删除, idr的find函数 + * + * @param arg0 + * @param arg1 + */ +static long ktest_idr_case1(uint64_t arg0, uint64_t arg1) +{ + DECLARE_IDR(k_idr); + int a[128]; + + // 获取128个id + for (int i = 0; i < 128; i++) + { + assert(idr_get_new(&k_idr, &a[i], &a[i]) == 0); + assert(a[i] == i); + } + + // 查询128个ptr + for (int i = 0; i < 128; i++) + { + int *ptr = idr_find(&k_idr, a[i]); + assert(ptr == &a[i]); + assert(ptr != NULL); + assert(*ptr == a[i]); + } + + // 倒序:删除64个id + for (int i = 127; i >= 64; i--) + { + idr_remove(&k_idr, a[i]); + assert(idr_find(&k_idr, a[i]) == NULL); + } + + // 正序:删除64个id + for (int i = 0; i <= 63; i++) + { + idr_remove(&k_idr, a[i]); + assert(idr_find(&k_idr, a[i]) == NULL); + } + + // 重新申请128个id, 值域范围应该仍然是[0,127] + for (int i = 0; i < 128; i++) + { + assert(idr_get_new(&k_idr, &a[i], &a[i]) == 0); + assert(a[i] == i); + } + + // 正序:删除32个id + for (int i = 0; i <= 31; i++) + { + idr_remove(&k_idr, a[i]); + assert(idr_find(&k_idr, a[i]) == NULL); + } + + // 倒序:删除32个id + for (int i = 127; i >= 96; i--) + { + idr_remove(&k_idr, a[i]); + assert(idr_find(&k_idr, a[i]) == NULL); + } + + // 整体删除 + idr_remove_all(&k_idr); + assert(k_idr.top == NULL); + + // 获取128个id + for (int i = 0; i < 128; i++) + { + assert(idr_get_new(&k_idr, &a[i], &a[i]) == 0); + assert(a[i] == i); + } + + // 查询128个ptr + for (int i = 0; i < 128; i++) + { + int *ptr = idr_find(&k_idr, a[i]); + assert(ptr == &a[i]); + assert(*ptr == a[i]); + } + + // 正序:删除64个id + for (int i = 0; i <= 63; i++) + { + idr_remove(&k_idr, a[i]); + assert(idr_find(&k_idr, a[i]) == NULL); + } + + // 倒序:删除64个id + for (int i = 127; i >= 64; i--) + { + idr_remove(&k_idr, a[i]); + assert(idr_find(&k_idr, a[i]) == NULL); + } + + // 销毁 + idr_destroy(&k_idr); + assert(k_idr.id_free_cnt == 0); + assert(k_idr.free_list == NULL); + + return 0; +} + +/** + * @brief case1 的大数据测试 + * + * @param arg0 + * @param arg1 + */ +static long ktest_idr_case2(uint64_t arg0, uint64_t arg1) +{ + DECLARE_IDR(k_idr); + + // 获取 1000‘000 个ID + const int N = 1e7; + const int M = 3e6; + + int tmp; + for (int i = 0; i < N; i++) + { + assert(idr_get_new(&k_idr, &tmp, &tmp) == 0); + assert(tmp == i); + + int *ptr = idr_find(&k_idr, i); + assert(ptr != NULL); + assert(*ptr == i); + } + + // 正向: M 个ID + for (int i = 0; i < M; i++) + { + int *ptr = idr_find(&k_idr, i); + assert(ptr != NULL); + assert(*ptr == N - 1); + idr_remove(&k_idr, i); + assert(idr_find(&k_idr, i) == NULL); + } + + // 倒序: N-M 个ID + for (int i = (N)-1; i >= M; i--) + { + int *ptr = idr_find(&k_idr, i); + assert(*ptr == N - 1); + idr_remove(&k_idr, i); + assert(idr_find(&k_idr, i) == NULL); + } + + // 重新插入数据 + for (int i = 0; i < N; i++) + { + assert(idr_get_new(&k_idr, &tmp, &tmp) == 0); + assert(tmp == i); + assert(k_idr.top != NULL); + + int *ptr = idr_find(&k_idr, i); + assert(ptr != NULL); + assert(*ptr == i); + } + + assert(k_idr.top != NULL); + + for (int i = 0; i < M; i++) + { + assert(idr_replace(&k_idr, NULL, i) == 0); + } + + // 销毁 + idr_destroy(&k_idr); + assert(k_idr.id_free_cnt == 0); + assert(k_idr.free_list == NULL); + + return 0; +} + +/** + * @brief case1 的大数据测试 + * + * @param arg0 + * @param arg1 + */ +static long ktest_idr_case3(uint64_t arg0, uint64_t arg1) +{ + DECLARE_IDR(k_idr); + + const int N = 1949; + int tmp; + + // 获取ID + for (int i = 0; i < N; i++) + { + assert(idr_get_new(&k_idr, &tmp, &tmp) == 0); + assert(tmp == i); + + int *ptr = idr_find(&k_idr, i); + assert(ptr != NULL); + assert(*ptr == i); + } + + // 查询 nextid + for (int i = 1; i <= N; i++) + { + int nextid; + int *ptr = idr_find_next_getid(&k_idr, i - 1, &nextid); + if (likely(i < N)) + { + assert(ptr != NULL); + assert(*ptr == N - 1); + assert(nextid == i); + } + else + { + assert(ptr == NULL); + assert(nextid == -1); + } + } + + int sz = N; + // 删掉某一段 + for (int i = N / 3, j = 2 * (N / 3), k = 0; i <= j; k++, i++) + { + int *ptr = idr_find(&k_idr, i); + assert(ptr != NULL); + assert(*ptr == N - 1); + idr_remove(&k_idr, i); + + assert(idr_find(&k_idr, i) == NULL); + sz--; + assert(k_idr.top != NULL); + } + + // 查询 nextid + for (int i = 1; i <= N; i++) + { + int nextid; + int *ptr = idr_find_next_getid(&k_idr, i - 1, &nextid); + if (likely(i < N)) + { + int target = i < N / 3 ? i : max(i, 2 * (N / 3) + 1); + assert(ptr != NULL); + assert(*ptr == N - 1); + assert(nextid == target); + } + else + { + assert(ptr == NULL); + assert(nextid == -1); + } + } + + // 销毁 + idr_destroy(&k_idr); + assert(k_idr.id_free_cnt == 0); + assert(k_idr.free_list == NULL); + + return 0; +} + +/** + * @brief 更加全面覆盖所有函数 - 小数据测试 + * + * @param arg0 + * @param arg1 + */ +static long ktest_idr_case4(uint64_t arg0, uint64_t arg1) +{ + DECLARE_IDR(k_idr); + idr_init(&k_idr); + + const int N =91173; + int tmp; + + for (int i = 1; i <= 20; i++) + { + int M = N / i, T = M / 3, O = 2 * T; + for (int j = 0; j < M; j++) + { + assert(idr_get_new(&k_idr, &tmp, &tmp) == 0); + assert(tmp == j); + } + + for (int j = O; j >= T; j--) + { + int *ptr = idr_find(&k_idr, j); + assert(ptr != NULL); + assert(*ptr == M - 1); + idr_remove(&k_idr, j); + } + + for (int j = O + 1; j < M; j++) + { + int *ptr = idr_find(&k_idr, j); + assert(ptr != NULL); + assert(*ptr == M - 1); + idr_remove(&k_idr, j); + } + + for (int j = T - 1; j >= 0; j--) + { + int *ptr = idr_find(&k_idr, j); + assert(ptr != NULL); + assert(*ptr == M - 1); + idr_remove(&k_idr, j); + } + + assert(k_idr.top == NULL); + } + + // 销毁 + idr_destroy(&k_idr); + assert(k_idr.id_free_cnt == 0); + assert(k_idr.free_list == NULL); + + return 0; +} + +/** + * @brief 测试id的获取,id的删除,id的全体删除, idr的find函数 + * + * @param arg0 + * @param arg1 + */ +static long ktest_idr_case5(uint64_t arg0, uint64_t arg1) +{ + DECLARE_IDR(k_idr); + const int N = 128; + int a[N]; + + // 获取128个id + for (int i = 0; i < N; i++) + { + assert(idr_get_new(&k_idr, &a[i], &a[i]) == 0); + assert(a[i] == i); + } + + // 把id指向的指针向后移动一个单位 + for (int i = 0; i < N; i++) + { + int *ptr; + int flags = idr_replace_get_old(&k_idr, &a[(i + 1) % N], i, (void*)&ptr); + assert(flags == 0); // 0 是成功 + assert(ptr != NULL); + assert(*ptr == i); + + // 测试是否替换成功 + ptr = idr_find(&k_idr, i); + assert(ptr != NULL); + assert(*ptr == (i + 1) % N); + } + + // 销毁 + idr_destroy(&k_idr); + assert(k_idr.id_free_cnt == 0); + assert(k_idr.free_list == NULL); + + // destroy之后,再获取128个id + for (int i = 0; i < N; i++) + { + assert(idr_get_new(&k_idr, &a[i], &a[i]) == 0); + assert(a[i] == i); + } + + // 销毁 + idr_destroy(&k_idr); + assert(k_idr.id_free_cnt == 0); + assert(k_idr.free_list == NULL); + + return 0; +} + +/** + * @brief 测试ida的插入/删除 + * + * @param arg0 + * @param arg1 + * @return long + */ +static long ktest_idr_case6(uint64_t arg0, uint64_t arg1) +{ + assert(IDA_BITMAP_LONGS != 0); + assert(IDA_BMP_SIZE != 0); + assert(IDA_FULL != 0); + assert(IDA_BITMAP_BITS != 0); + + DECLARE_IDA(k_ida); + ida_init(&k_ida); + + const int N = IDA_FULL * IDR_SIZE + 1; + + for (int i = 0; i < N; i++) + { + int p_id; + assert(ida_get_new(&k_ida, &p_id) == 0); + assert(p_id == i); + } + + for (int i = 0; i < N; i++) + { + assert(ida_count(&k_ida, i) == 1); + } + + for (int i = N - 1; i >= 0; i--) + { + ida_remove(&k_ida, i); + assert(ida_count(&k_ida, i) == 0); + } + + assert(k_ida.idr.top == NULL); + + for (int i = 0; i < N; i++) + { + int p_id; + assert(ida_get_new(&k_ida, &p_id) == 0); + assert(p_id == i); + } + + assert(k_ida.idr.top != NULL); + ida_destroy(&k_ida); + assert(k_ida.idr.top == NULL); + assert(k_ida.free_list == NULL); + + // 测试destroy之后能否重新获取ID + for (int i = 0; i < N; i++) + { + int p_id; + assert(ida_get_new(&k_ida, &p_id) == 0); + assert(p_id == i); + } + + for (int i = 0; i < N / 3; i++) + { + ida_remove(&k_ida, i); + assert(ida_count(&k_ida, i) == 0); + } + + for (int i = 2 * N / 3; i < N; i++) + { + ida_remove(&k_ida, i); + assert(ida_count(&k_ida, i) == 0); + } + + assert(k_ida.idr.top != NULL); + ida_destroy(&k_ida); + assert(k_ida.idr.top == NULL); + assert(k_ida.free_list == NULL); + + return 0; +} + +static ktest_case_table kt_idr_func_table[] = { + ktest_idr_case0, + ktest_idr_case1, + // ktest_idr_case2, // 为了加快启动速度, 暂时注释掉这个测试 + ktest_idr_case3, + ktest_idr_case4, + ktest_idr_case5, + ktest_idr_case6, +}; + +int ktest_test_idr(void* arg) +{ + kTEST("Testing idr..."); + unsigned int sz = sizeof(kt_idr_func_table) / sizeof(ktest_case_table); + for (int i = 0; i < sz; ++i) + { + kTEST("Testing case %d", i); + kt_idr_func_table[i](i, i + 1); + } + kTEST("idr Test done."); + return 0; +} \ No newline at end of file diff --git a/kernel/lib/idr.c b/kernel/lib/idr.c new file mode 100644 index 000000000..b0a9539cf --- /dev/null +++ b/kernel/lib/idr.c @@ -0,0 +1,883 @@ +#include <common/idr.h> +#include <mm/slab.h> + +/** + * @brief 更换两个idr_layer指针 + * + * @param a + * @param b + */ +static void __swap(struct idr_layer **a, struct idr_layer **b) +{ + struct idr_layer *t = *a; + *a = *b, *b = t; +} + +/** + * @brief 初始化idr - 你需要保证函数调用之前 free_list指针 为空 + * + * @param idp + */ +void idr_init(struct idr *idp) +{ + memset(idp, 0, sizeof(struct idr)); + spin_init(&idp->lock); +} + +/** + * @brief 向idr的free_list中添加一个节点(空节点) + * + * @param idp + * @param p + */ +static void __move_to_free_list(struct idr *idp, struct idr_layer *p) +{ + unsigned long flags; + spin_lock_irqsave(&idp->lock, flags); + + // 插入free_list + p->ary[0] = idp->free_list; + idp->free_list = p; + ++(idp->id_free_cnt); + + spin_unlock_irqrestore(&idp->lock, flags); +} + +/** + * @brief Get the free_idr_layer from free list object + * + * @param idp + * @return void* + */ +static void *__get_from_free_list(struct idr *idp) +{ + if (idp->id_free_cnt == 0) + { + if (idr_pre_get(idp, 0) != 0) + { + kBUG("idr-module find a BUG: get free node fail.(Possible ENOMEM error)"); + return NULL; + } + } + + unsigned long flags; + spin_lock_irqsave(&idp->lock, flags); + + // free_list还有节点 + struct idr_layer *item = idp->free_list; + idp->free_list = idp->free_list->ary[0]; + item->ary[0] = NULL; // 记得清空原来的数据 + --(idp->id_free_cnt); + + spin_unlock_irqrestore(&idp->lock, flags); + + return item; +} + +/** + * @brief 为idr预分配空间 + * + * @param idp + * @param gfp_mask + * @return int (如果分配成功,将返回0; 否则返回负数 -ENOMEM, 有可能是内存空间不够) + */ +int idr_pre_get(struct idr *idp, gfp_t gfp_mask) +{ + int timer = 0; + while (idp->id_free_cnt < IDR_FREE_MAX) + { + struct idr_layer *new_one; + new_one = kzalloc(sizeof(struct idr_layer), gfp_mask); // 默认清空? + if (NULL == new_one) + return -ENOMEM; + __move_to_free_list(idp, new_one); + timer++; + } + return 0; +} + +/** + * @brief 释放一个layer的空间 + * + * @param p + */ +static void __idr_layer_free(struct idr_layer *p) +{ + kfree(p); +} + +/** + * @brief 向上生长一层idr_layer + * + * @param idp + * @return int (0生长成功, 否则返回错误码) + */ +static int __idr_grow(struct idr *idp) +{ + struct idr_layer *new_node = __get_from_free_list(idp); + if (NULL == new_node) + return -ENOMEM; + + __swap(&new_node, &idp->top); + + idp->top->ary[0] = new_node; + idp->top->layer = new_node ? (new_node->layer + 1) : 0; // 注意特判空指针 + idp->top->bitmap = 0; + idp->top->full = 0; // clear + + if (new_node != NULL) // 设置第0位 = 1, 同时维护树的大小 + { + idp->top->bitmap = 1; + } + if (new_node != NULL && new_node->full == IDR_FULL) + { + idp->top->full = 1; // 别忘了初始化 full + } + + return 0; +} + +/** + * @brief 获取一个没有被占领的ID + * + * @param idp + * @param stk 栈空间 + * @return int (负数表示获取ID失败, [0 <= id && id <= INT_MAX] 则获取ID成功) + */ +static int __idr_get_empty_slot(struct idr *idp, struct idr_layer **stk) +{ + // 注意特判 idp->top == NULL + while (NULL == idp->top || idp->top->full == IDR_FULL) + if (__idr_grow(idp) != 0) + return -ENOMEM; + + int id = 0; + int layer = idp->top->layer; + + stk[layer + 1] = NULL; // 标志为数组末尾 + + struct idr_layer *cur_layer = idp->top; + while (layer >= 0) + { + stk[layer] = cur_layer; + int pos = __lowbit_id(~cur_layer->full); + + if (unlikely(pos < 0)) + { + kBUG("Value 'cur_layer->full' had been full;" + "but __idr_get_empty_slot still try to insert a value."); + } + + id = (id << IDR_BITS) | pos; + cur_layer = cur_layer->ary[pos]; + + if (layer > 0 && NULL == cur_layer) // 只有非叶子节点才需要开辟儿子节点 + { + // 初始化儿子节点 + cur_layer = __get_from_free_list(idp); + if (NULL == cur_layer) + return -ENOMEM; + cur_layer->layer = layer - 1; // 儿子节点的layer + cur_layer->full = 0; + cur_layer->bitmap = 0; + + stk[layer]->ary[pos] = cur_layer; // 最后别忘了记录儿子节点 + } + + --layer; + } + + return id; +} + +/** + * @brief 更新full对象 (辅助函数,内部没有边界特判) + * + * @param idp + * @param id + * @param stk 需要保证stk数组末尾是NULL + * @param mark 0代表叶子空, 1代表叶子非空但未满, 2代表满 + */ +static __always_inline void __idr_mark_full(struct idr *idp, int id, struct idr_layer **stk, int mark) +{ + if (unlikely(NULL == stk[0] || NULL == idp->top)) + { + kBUG("idr-module find a BUG: idp->top can't be NULL."); + return; + } + + // 处理叶子节点的full/bitmap标记 + int layer_id = id & IDR_MASK; + if (mark == 2) + stk[0]->full |= (1ull << layer_id); + if (mark >= 1) + stk[0]->bitmap |= (1ull << layer_id); + + for (int i = 1; stk[i]; ++i) + { + id >>= IDR_BITS; + layer_id = id & IDR_MASK; + + stk[i]->bitmap |= (1ull << layer_id); + if (stk[i - 1]->full == IDR_FULL) + stk[i]->full |= (1ull << layer_id); + } +} + +/** + * @brief 提取一条已存在的路径 + * + * @param idp + * @param id + * @param stk + * @return int (0表示没有这条路径, 1表示找到这条路径) + */ +static __always_inline int __idr_get_path(struct idr *idp, int id, struct idr_layer **stk) +{ + if (unlikely(idp->top == NULL || id < 0)) + { + kBUG("idr-module find a BUG: idp->top can't be NULL and id must be non-negative."); + return 0; + } + + struct idr_layer *cur_layer = idp->top; + int layer = cur_layer->layer; + stk[layer + 1] = NULL; // 标志数组结尾 + + // 提取路径 + while (layer >= 0) + { + stk[layer] = cur_layer; + int layer_id = (id >> (layer * IDR_BITS)) & IDR_MASK; + + if (unlikely(((cur_layer->bitmap >> layer_id) & 1) == 0)) + { + kBUG("idr-module find a BUG: no-such son."); + return 0; // 没有这一个儿子 + } + + cur_layer = cur_layer->ary[layer_id]; + --layer; + } + + return 1; +} + +/** + * @brief 更新full对象 (辅助函数,内部没有边界特判) + * + * @param idp + * @param id + * @param stk 需要保证stk数组末尾是NULL + * @param mark 0代表叶子空, 1代表叶子非空但未满, 2代表满 + */ +static __always_inline void __idr_erase_full(struct idr *idp, int id, struct idr_layer **stk, int mark) +{ + if (unlikely(NULL == stk[0] || NULL == idp->top)) + { + kBUG("idr-module find a BUG: idp->top can't be NULL."); + return; + } + + // 处理叶子节点的full/bitmap标记 + int layer_id = id & IDR_MASK; + if (mark == 0) // 叶子的某个插槽为空 + { + stk[0]->ary[layer_id] = NULL; + stk[0]->bitmap ^= (1ull << layer_id); + } + if (mark != 2 && ((stk[0]->full >> layer_id) & 1)) + stk[0]->full ^= (1ull << layer_id); + + // 删除节点 + for (int layer = 1; stk[layer]; ++layer) + { + id >>= IDR_BITS; + layer_id = id & IDR_MASK; + + if (NULL == stk[layer - 1]->bitmap) // 儿子是空节点 + { + stk[layer]->ary[layer_id] = NULL; + stk[layer]->bitmap ^= (1ull << layer_id); + + if ((stk[layer]->full >> layer_id) & 1) + stk[layer]->full ^= (1ull << layer_id); + + __idr_layer_free(stk[layer - 1]); + stk[layer - 1] = NULL; // 释放空间记得设置为 NULL + } + else if (stk[layer - 1]->full != IDR_FULL) + { + if ((stk[layer]->full >> layer_id) & 1) + stk[layer]->full ^= (1ull << layer_id); + } + } + + // 特判根节点是否只剩0号儿子节点 (注意还要layer > 0) + // (注意,有可能出现idp->top=NULL) + // bitmap: 1000...000/00.....000 + while (idp->top != NULL && + ((idp->top->bitmap <= 1 && idp->top->layer > 0) || // 一条链的情况 + (idp->top->layer == 0 && idp->top->bitmap == 0))) // 最后一个点的情况 + { + struct idr_layer *t = idp->top->layer ? idp->top->ary[0] : NULL; + __idr_layer_free(idp->top); + idp->top = t; + } +} + +/** + * @brief 内部的分配ID函数 (辅助函数) + * + * @param idp + * @param ptr + * @param starting_id 暂时没用 + * @return (0 <= id <= INT_MAX 表示申请的ID;否则是负数错误码, 可能是内存空间不够或者程序逻辑有误); + */ +static int __idr_get_new_above_int(struct idr *idp, void *ptr, int starting_id) +{ + struct idr_layer *stk[MAX_LEVEL + 1]; // 你可以选择memset(0) + int id = __idr_get_empty_slot(idp, stk); + + if (id >= 0) + { + stk[0]->ary[IDR_MASK & id] = ptr; + __idr_mark_full(idp, id, stk, 2); + } + + return id; +} + +/** + * @brief 从[0,INT_MAX]区间内返回一个最小的空闲ID + * + * @param idp + * @param ptr - id 所对应的指针 + * @param int* id - 传入int指针,获取到的NEW_ID存在id里 + * @return int (0表示获取id成功, 负数代表错误 - 可能是内存空间不够) + */ +int idr_get_new(struct idr *idp, void *ptr, int *id) +{ + int rv = __idr_get_new_above_int(idp, ptr, 0); + if (rv < 0) + return rv; // error + *id = rv; + return 0; +} + +/** + * @brief 删除一个id,但是不释放对应的ptr指向的空间 + * + * @param idp + * @param id + */ +void idr_remove(struct idr *idp, int id) +{ + if (unlikely(idp->top == NULL || id < 0)) + return; + + struct idr_layer *stk[MAX_LEVEL + 1]; + if (0 == __idr_get_path(idp, id, stk)) + return; // 找不到路径 + + __idr_erase_full(idp, id, stk, 0); +} + +/** + * @brief 移除IDR中所有的节点,如果free=true,则同时释放所有数据指针的空间(kfree) + * + * @param idp + * @param free + */ +static void __idr_remove_all_with_free(struct idr *idp, bool free) +{ + if (unlikely(NULL == idp->top)) + { + kBUG("idr-module find a BUG: idp->top can't be NULL."); + return; + } + + int sz = sizeof(struct idr_layer); + struct idr_layer *stk[MAX_LEVEL + 1]; + struct idr_layer *cur_layer = idp->top; + int layer = cur_layer->layer; + stk[layer + 1] = NULL; // 标记数组结尾 + + while (cur_layer != NULL) + { + if (layer > 0 && cur_layer->bitmap) // 非叶子节点 + { + stk[layer] = cur_layer; // 入栈 + int id = __lowbit_id(cur_layer->bitmap); + + cur_layer->bitmap ^= (1ull << id); + cur_layer = cur_layer->ary[id]; + stk[layer]->ary[id] = NULL; + --layer; + } + else + { + if (free) + { + for (int i = 0; i < IDR_SIZE; i++) // 释放数据指针的空间 + { + kfree(cur_layer->ary[i]); + cur_layer->ary[i] = NULL; + } + } + + __idr_layer_free(cur_layer); // 释放空间记得设置为NULL + ++layer; + + cur_layer = stk[layer]; // 出栈 + } + } + idp->top = NULL; +} + +/** + * @brief 删除idr的所有节点,同时释放数据指针的空间,回收free_list的所有空间 - (数据指针指ID所绑定的pointer) + * @param idp + */ +static void __idr_destroy_with_free(struct idr *idp) +{ + if (likely(idp->top)) + __idr_remove_all_with_free(idp, 1); + idp->top = NULL; + while (idp->id_free_cnt) + __idr_layer_free(__get_from_free_list(idp)); + idp->free_list = NULL; +} + +/** + * @brief 删除所有的ID + * + * @param idp + */ +void idr_remove_all(struct idr *idp) +{ + if (unlikely(NULL == idp->top)) + return; + + __idr_remove_all_with_free(idp, 0); +} + +/** + * @brief 释放一个idr占用的所有空间 + * + * @param idp + */ +void idr_destroy(struct idr *idp) +{ + idr_remove_all(idp); + idp->top = NULL; + while (idp->id_free_cnt) + __idr_layer_free(__get_from_free_list(idp)); + idp->free_list = NULL; +} + +/** + * @brief 返回id对应的数据指针 + * + * @param idp + * @param id + * @return void* (如果id不存在返回NULL;否则返回对应的指针ptr; 注意: 有可能用户的数据本来就是NULL) + */ +void *idr_find(struct idr *idp, int id) +{ + if (unlikely(idp->top == NULL || id < 0)) + return NULL; + + struct idr_layer *cur_layer = idp->top; + int layer = cur_layer->layer; // 特判NULL + + // 如果查询的ID的bit数量比layer*IDR_BITS还大, 直接返回NULL + if ((id >> ((layer + 1) * IDR_BITS)) > 0) + return NULL; + + while (layer >= 0 && cur_layer) + { + int layer_id = (id >> (IDR_BITS * layer)) & IDR_MASK; + cur_layer = cur_layer->ary[layer_id]; + --layer; + } + return cur_layer; +} + +/** + * @brief 返回id大于 start_id 的数据指针(即非空闲id对应的指针), 如果没有则返回NULL; 可以传入nextid指针,获取下一个id; 时间复杂度O(log_64(n)), 空间复杂度O(log_64(n)) 约为 6; + * + * @param idp + * @param start_id + * @param nextid + * @return void* + */ +void *idr_find_next_getid(struct idr *idp, int start_id, int *nextid) +{ + if (unlikely(idp->top == NULL)) + { + *nextid = -1; + return NULL; + } + + ++start_id; + start_id = max(0, start_id); // 特判负数 + *nextid = 0; + + struct idr_layer *stk[MAX_LEVEL + 1]; + bool state[MAX_LEVEL + 1]; // 标记是否大于等于] + int pos_i[MAX_LEVEL + 1]; + + memset(pos_i, 0, sizeof(pos_i)); // 必须清空 + + struct idr_layer *cur_layer = idp->top; + bool cur_state = false; + bool init_flag = true; + int layer = cur_layer->layer; + stk[layer + 1] = NULL; // 标记数组结尾 + + // 如果查询的ID的bit数量比layer*IDR_BITS还大, 直接返回NULL + if ((start_id >> ((layer + 1) * IDR_BITS)) > 0) + { + *nextid = -1; + return NULL; + } + + while (cur_layer) // layer < top->layer + 1 + { + if (init_flag) // 第一次入栈 + { + stk[layer] = cur_layer; + state[layer] = cur_state; + pos_i[layer] = cur_state ? 0 : ((start_id >> (layer * IDR_BITS)) & IDR_MASK); + } + else + { + pos_i[layer]++; + state[layer] = cur_state = true; + } + + unsigned long t_bitmap = (cur_layer->bitmap >> pos_i[layer]); + if (t_bitmap) // 进一步递归到儿子下面去 + { + int layer_id = __lowbit_id(t_bitmap) + pos_i[layer]; + + // 特别情况 + if (NULL == cur_state && layer_id > pos_i[layer] > 0) + cur_state = true; + + pos_i[layer] = layer_id; + + *nextid = (((uint64_t)*nextid) << IDR_BITS) | layer_id; // 更新答案 + if (layer == 0) + { + // 找到下一个id: nextid + return cur_layer->ary[layer_id]; + } + + cur_layer = cur_layer->ary[layer_id]; + init_flag = true; // 儿子节点第一次入栈, 需要init + --layer; + } + else // 子树搜索完毕,向上回溯 + { + (*nextid) >>= IDR_BITS; // 维护答案 + + ++layer; + cur_layer = stk[layer]; + init_flag = false; // 不是第一次入栈, 不需要init + } + } + + *nextid = -1; + return NULL; // 找不到 +} + +/** + * @brief 返回id大于 start_id 的数据指针(即非空闲id对应的指针), 如果没有则返回NULL + * + * @param idp + * @param start_id + * @return void* + */ +void *idr_find_next(struct idr *idp, int start_id) +{ + int nextid; + void *ptr = idr_find_next_getid(idp, start_id, &nextid); + + return ptr; // 当 nextid == -1 时, 出现错误 +} + +/** + * @brief 根据id替换指针,你需要保证这个id存在于idr中,否则将会出现错误 + * + * @param idp + * @param ptr (要替换旧指针的新指针 - new_ptr) + * @param id + * @param old_ptr (返回旧指针, 注意NULL不一定是出现错误,有可能是数据本来就是NULL) + * @return int (0代表成功,否则就是负数 - 代表错误) + */ +int idr_replace_get_old(struct idr *idp, void *ptr, int id, void **old_ptr) +{ + *old_ptr = NULL; + + if (unlikely(idp->top == NULL || id < 0)) + return -EDOM; // 参数错误 + + struct idr_layer *cur_layer = idp->top; + int layer = cur_layer->layer; + + // 如果查询的ID的bit数量比layer*IDR_BITS还大, 直接返回NULL + if ((id >> ((layer + 1) * IDR_BITS)) > 0) + return -EDOM; + + while (layer > 0) + { + int layer_id = (id >> (layer * IDR_BITS)) & IDR_MASK; + + if (unlikely(NULL == cur_layer->ary[layer_id])) + return -ENOMEM; + + cur_layer = cur_layer->ary[layer_id]; + layer--; + } + + id &= IDR_MASK; + *old_ptr = cur_layer->ary[id]; + cur_layer->ary[id] = ptr; + + return 0; +} + +/** + * @brief 根据id替换指针,你需要保证这个id存在于idr中,否则将会出现错误 + * + * @param idp + * @param ptr (要替换 '旧数据指针' 的 '新数据指针' - new_ptr) + * @param id + * @return int (0代表成功,否则就是错误码 - 代表错误) + */ +int idr_replace(struct idr *idp, void *ptr, int id) +{ + if (id < 0) + return -EDOM; + + void *old_ptr; + int flags = idr_replace_get_old(idp, ptr, id, &old_ptr); + + return flags; +} + +/** + * @brief 初始化IDA, 你需要保证调用函数之前, ida的free_list为空, 否则会导致内存泄漏 + * @param ida_p + */ +void ida_init(struct ida *ida_p) +{ + memset(ida_p, 0, sizeof(struct ida)); + idr_init(&ida_p->idr); +} + +/** + * @brief 释放bitmap空间 + * + */ +static void __ida_bitmap_free(struct ida_bitmap *bitmap) +{ + kfree(bitmap); +} + +/** + * @brief 为ida预分配空间 + * + * @param ida_p + * @param gfp_mask + * @return int (如果分配成功,将返回0; 否则返回负数错误码, 有可能是内存空间不够) + */ +int ida_pre_get(struct ida *ida_p, gfp_t gfp_mask) +{ + if (idr_pre_get(&ida_p->idr, gfp_mask) != 0) + return -ENOMEM; + + unsigned long flags; + spin_lock_irqsave(&ida_p->idr.lock, flags); + + if (NULL == ida_p->free_list) + { + struct ida_bitmap *bitmap; + bitmap = kzalloc(sizeof(struct ida_bitmap), gfp_mask); + if (NULL == bitmap) + { + spin_unlock_irqrestore(&ida_p->idr.lock, flags); + return -ENOMEM; + } + ida_p->free_list = bitmap; + } + + spin_unlock_irqrestore(&ida_p->idr.lock, flags); + return 0; +} + +/** + * @brief Get the ida bitmap object + * + * @param ida_p + * @return void* + */ +static void *__get_ida_bitmap(struct ida *ida_p, gfp_t gfp_mask) +{ + if (NULL == ida_p->free_list) + if (ida_pre_get(ida_p, gfp_mask) < 0) + return NULL; + + struct ida_bitmap *tmp = ida_p->free_list; + ida_p->free_list = NULL; + return tmp; +} + +/** + * @brief 从bitmap中获取id, 并且标记这个ID已经被使用 + * @return int + */ +static int __get_id_from_bitmap(struct ida_bitmap *bmp) +{ + int ret = 0; + for (int ary_id = 0; ary_id < IDA_BITMAP_LONGS; ary_id++) + { + if (bmp->bitmap[ary_id] != IDR_FULL) + { + int bmp_id = __lowbit_id(~bmp->bitmap[ary_id]); + bmp->bitmap[ary_id] |= (1ull << bmp_id); + bmp->count++; // 注意, 这里已经标记这一位已经使用, 同时更新了ida_count + + if (unlikely((unsigned long long)ary_id * IDA_BMP_SIZE + bmp_id > INT32_MAX)) + { + kBUG("ida设置id范围为[0, INT32_MAX], 但ida获取的id数值超过INT32_MAX."); + return -EDOM; + } + + return ary_id * IDA_BMP_SIZE + bmp_id; + } + } + + return -EDOM; // 不合法 +} + +/** + * @brief 获取一个ID + * + * @param ida_p + * @param p_id + * @return int (0表示获取ID成功, 否则是负数 - 错误码) + */ +int ida_get_new(struct ida *ida_p, int *p_id) +{ + *p_id = -1; + + struct idr_layer *stk[MAX_LEVEL + 1]; // 你可以选择memset(0) + memset(stk, 0, sizeof(stk)); + int idr_id = __idr_get_empty_slot(&ida_p->idr, stk); + + // 如果stk[0]=NULL,可能是idr内部出错/内存空间不够 + if (unlikely(NULL == stk[0])) + return -ENOMEM; + + if (unlikely(idr_id < 0)) + return idr_id; + + int layer_id = idr_id & IDR_MASK; + + if (NULL == stk[0]->ary[layer_id]) + stk[0]->ary[layer_id] = __get_ida_bitmap(ida_p, 0); + + if (unlikely(NULL == stk[0]->ary[layer_id])) + return -ENOMEM; + + struct ida_bitmap *bmp = (struct ida_bitmap *)stk[0]->ary[layer_id]; + int low_id = __get_id_from_bitmap(bmp); + + if (unlikely(low_id < 0)) + return low_id; + + *p_id = idr_id * IDA_BITMAP_BITS + low_id; + __idr_mark_full(&ida_p->idr, idr_id, stk, (bmp->count == IDA_FULL ? 2 : 1)); + + return 0; +} + +/** + * @brief 查询ID是否已经被分配 + * + * @param ida_p + * @param id + * @return true + * @return false + */ +bool ida_count(struct ida *ida_p, int id) +{ + if (unlikely(NULL == ida_p || NULL == ida_p->idr.top || id < 0)) + return false; + + int idr_id = id / IDA_BITMAP_BITS; + int ary_id = (id % IDA_BITMAP_BITS) / IDA_BMP_SIZE; + int bmp_id = (id % IDA_BITMAP_BITS) % IDA_BMP_SIZE; + + struct ida_bitmap *bmp = idr_find(&ida_p->idr, idr_id); + if (NULL == bmp) + return false; + + return ((bmp->bitmap[ary_id] >> bmp_id) & 1); +} + +/** + * @brief 删除一个ID + * + * @param ida_p + * @param id + */ +void ida_remove(struct ida *ida_p, int id) +{ + if (unlikely(NULL == ida_p || NULL == ida_p->idr.top || id < 0)) + return; + + int idr_id = id / IDA_BITMAP_BITS; + int ary_id = (id % IDA_BITMAP_BITS) / IDA_BMP_SIZE; + int bmp_id = (id % IDA_BITMAP_BITS) % IDA_BMP_SIZE; + + struct idr_layer *stk[MAX_LEVEL + 1]; + memset(stk, 0, sizeof(stk)); + if (0 == __idr_get_path(&ida_p->idr, idr_id, stk)) + return; + + struct ida_bitmap *b_p = (struct ida_bitmap *)stk[0]->ary[idr_id & IDR_MASK]; + + // 不存在这个ID 或者 b_p == NULL + if (unlikely(NULL == b_p || 0 == ((b_p->bitmap[ary_id] >> bmp_id) & 1))) + return; + + b_p->count--; // 更新了ida_count + b_p->bitmap[ary_id] ^= (1ull << bmp_id); + + __idr_erase_full(&ida_p->idr, idr_id, stk, (b_p->count > 0 ? 1 : 0)); + if (0 == b_p->count) + { + __ida_bitmap_free(b_p); + if (stk[0]) // stk[0] 有可能在 __idr_erase_full 里面已经kfree了 + stk[0]->ary[idr_id & IDR_MASK] = NULL; // 记得设置为空 + } +} + +/** + * @brief 释放所有空间(包括: idr + ida_bitmap + free_list) + * @param ida_p + */ +void ida_destroy(struct ida *ida_p) +{ + if (unlikely(ida_p == NULL)) + return; + + __idr_destroy_with_free(&ida_p->idr); + ida_p->idr.top = NULL; + __ida_bitmap_free(ida_p->free_list); + ida_p->free_list = NULL; +} \ No newline at end of file diff --git a/kernel/process/process.c b/kernel/process/process.c index 9dbc2249b..a311292bc 100644 --- a/kernel/process/process.c +++ b/kernel/process/process.c @@ -496,6 +496,7 @@ ul initial_kernel_thread(ul arg) ktest_start(ktest_test_bitree, 0), ktest_start(ktest_test_kfifo, 0), ktest_start(ktest_test_mutex, 0), + ktest_start(ktest_test_idr, 0), // usb_pid, }; kinfo("Waiting test thread exit...");