Linux内核数据结构移植(list和rbtree)

  • 简介
    • list 介绍
      • 修改部分
      • list.h 对外的接口
      • 使用示例 - 测试 list.h 中所有的list操作
    • rbtree 介绍
      • 修改部分
      • rbtree.h 对外接口
      • 使用示例

简介

主要移植了内核中的 list,rbtree。使得这2个数据结构在用户态程序中也能使用。同时用 cpputest 对移植后的代码进行了测试。(测试代码其实也是使用这2个数据结构的方法)

内核代码的如下文件:(内核版本 v3.2 debian 7.5源码)
include/linux/list.h (删除了 hlist 相关内容)
include/linux/rbtree.h
lib/rbtree.c
对上面的代码进行了一些简化,只留了常用的函数。同时删除了其中和内核相关的部分。

list 介绍

Linux中的链表用法与一般数据结构书中介绍的用法有些不一样。

Linux内核中,为了保证链表的通用性,将链表的节点结构单独抽取了出来,也就是将链表的结构和链表的数据分开定义。

一般数据结构的书中介绍到的链表都是将链表的数据和链表的结构一起定义的。

里面很重要的一点就是:链表结构和数据分开后,是如何通过链表节点结构来获取数据的?

带有safe的函数或者宏都是可以用于多线程的

修改部分

删除了hlist相关内容
修改了 list_del 函数: 将 LIST_POISON1 和 LIST_POISON2 改成了 NULL
删除了 list_empty_careful: 用户空间用不上
删除 __list_for_each: 和 list_for_each 重复
删除 list_prepare_entry: 暂时不需要
删除 list_safe_reset_next: 暂时不需要
删除 list_rotate_left: 暂时不需要
所有变量 new 改为了 newnode: new 是 c++ 关键字,用CppUTest进行测试时无法编译

list.h 对外的接口

主要函数 说明
list_add 在 head 之后追加一个节点
list_add_tail 在 head 之前追加一个节点, 也就是在末尾追加一个节点
list_del 删除一个节点, 并将这个节点的next, prev 置为 NULL
list_del_init 删除一个节点并初始化删除的节点
list_replace 替换一个节点
list_replace_init 替换一个节点, 并初始化被替换的节点
list_move 移动节点到 head 之后
list_move_tail 移动节点到 head 之前
list_is_last 判断节点是否是链表中最后一个
list_empty 判断链表是否为空 (即, 是否只有 head 节点)
list_is_singular 判断链表中是否只有一个节点 (除了 head 之外)
list_cut_position 将1个链表截断为2个链表
list_splice 将2个链表合并为1个链表, @list中的所有节点(不包括list)加入到 head 之后
list_splice_tail 将2个链表合并为1个链表, @list中的所有节点(不包括list)加入到 head 之前
list_splice_init 同 list_splice, 最后会初始化 @list
list_splice_tail_init 同 list_splice_tail, 最后会初始化 @list
主要宏 说明
list_entry 获取包含此节点的 struct
list_first_entry 获取包含此节点的 首个 struct
list_for_each 从 head节点之后一个节点开始向后循环
list_for_each_prev 从 head节点之前一个节点开始向前循环
list_for_each_safe list_for_each 的安全版本, 即, 循环时即使有其它线程删除节点也可正常运行
list_for_each_prev_safe list_for_each_prev 的安全版本
list_for_each_entry 同 list_for_each, 只是参数不同
list_for_each_entry_reverse 同 list_for_each_prev, 只是参数不同
list_for_each_entry_continue 同 list_for_each_entry, 但不是从头(head)开始循环的
list_for_each_entry_continue_reverse 同 list_for_each_entry_reverse, 但不是从头(head)开始循环的
list_for_each_entry_from 从指定位置开始向后循环
list_for_each_entry_safe list_for_each_entry 的安全版本
list_for_each_entry_safe_continue list_for_each_entry_continue 的安全版本
list_for_each_entry_safe_from list_for_each_entry_from 的安全版本
list_for_each_entry_safe_reverse list_for_each_entry_reverse 的安全版本

使用示例 - 测试 list.h 中所有的list操作

构造如下场景,用来测试上述列出的所有的 list 操作:
1、构造用来测试的 struct:(为了使得测试结果一目了然,struct尽量简单)

struct test_struct {
int num;
    struct list_head head;
};

2、逐个函数进行测试,使用测试框架 cppUTest
3、宏 相关的暂时没有测试
4、运行测试非常简单(前提是得安装 cpputest)
make
./test_list -v

rbtree 介绍

红黑树是一种自平衡的二叉搜索树。红黑树是有序的。

这里只补充一点,红黑树虽然有些复杂,但是它的查找,插入,删除操作的效率还不错。查找,插入,删除的时间复杂度都是O(log n) n是树中元素数目

修改部分

为了是 rbtree 更加简单,暂时删除了以下内容:

删除了函数指针的定义 typedef rb_augment_f
删除了 rb_augment_insert
删除了 rb_augment_erase_begin
删除了 rb_augment_erase_end
删除了 rb_link_node

rbtree.h 对外接口

主要函数 说明
rb_set_parent 设置父节点的地址
rb_set_color 设置节点颜色
rb_init_node 初始化节点
rb_insert_color 设置新插入节点的颜色
rb_erase 删除一个节点
rb_next 返回当前节点的下一个节点
rb_prev 返回当前节点的上一个节点
rb_first 返回第一个叶子节点(也就是最左边的叶子节点)
rb_last 返回最后一个叶子节点(也就是最右边的叶子节点)
rb_replace_node 替换rbtree中的一个node(只是简单的替换,没有管替换的颜色对不对,数据的顺序对不对)
主要宏 说明
rb_parent 获取父节点的地址
rb_color 节点的颜色
rb_is_red 是否红节点
rb_is_black 是否黑节点
rb_set_red 设置节点为红色
rb_set_black 设置节点为黑色
RB_ROOT 初始化根节点
rb_entry 获取包含rbtree node的struct
RB_EMPTY_ROOT 判断是否只有根节点
RB_EMPTY_NODE 判断节点是否刚初始化,还没有加到树中
RB_CLEAR_NODE 设置节点的父节点也指向自己

使用示例

构造如下场景,用来测试上述列出的所有的 rbtree 操作:
1、构造用来测试的 struct:(为了使得测试结果一目了然,struct尽量简单)

struct test_struct {
    int num;
    struct rb_node node;
};

2、逐个函数进行测试,使用测试框架 cppUTest
3、宏 相关的暂时没有测试
4、运行测试非常简单(前提是得安装 cpputest)
make
./test_rbtree -v

转自:Kernel数据结构移植(list和rbtree)

你可能感兴趣的:(linux)