链表
- 因为环形双向链表提供了最大的灵活性,所以Linux内核的标准链表就是采用环形双向链表形式实现的。
- 相比较传统的将数据结构塞入链表的实现,Linux采用将链表节点塞入数据结构的实现方式实现链表,链表的数据结构为struct list_head。
- 使用container_of(ptr,type,member)或者list_entry(ptr,type,member)宏,便可以返回包含list_head的父类型结构体。
- 内核提供了一组函数来操作链表,例如list_add()向指定节点后插入一个节点,list_add_tail()向指定节点前插入一个节点。list_del()该函数从链表中删除元素,单该操作并不会释放entry或释放包含entry的数据结构体所占用的内存。list_move()从链表中移除一个节点,然后将其加入到另一个链表的指定节点后面。list_empty()检查指定的链表是否为空。list_splice()合并两个链表。
- 使用list_for_each(p,list)宏可以遍历链表中的每个list_head节点。使用list_for_each_entry(type,list,member)宏可以遍历链表中的每个list_head节点指向的对象指针。list_for_each_entry_reverse()宏和list_for_each_entry()宏类似,区别在于其为反向遍历链表。
队列
- Linux内核通用队列实现成为kfifo,其数据结构为struct __kfifo。使用kfifo_alloc(fifo,size,gfp_mask)宏可以申请一个大小为size,页面分配标识为gfp_mask的队列。
- kfifo_in(fifo,buf,n)宏把buf指向的内容中的大小为n字节的数据推送到fifo中,kfifo_out(fifo,buf,n)宏把fifo队列中长度为n字节的数据拷贝出到buf中。
- kfifo_size(fifo)宏返回fifo队列的空间总大小,kfifo_len(fifo)宏返回fifo队列已退入的数据大小。
- kfifo_free(fifo)用于撤销使用kfifo_alloc()分配的队列。
映射
- Linux内核提供了简单、有效的映射数据结构,但是它并非一个通用的映射。它的目标是:映射一个唯一的标识数(UID)到一个指针,idr数据结构用于映射用户空间的UID。
- idr_init()宏用来初始化idr结构,一旦建立了idr,就可以分配新的UID了。这个过程分两步完成:首先调用idr_pre_get()方法告诉idr分配新的UID;然后调用idr_get_new(struct idr*idp,void* ptr,int* id)方法请求新的UID,将其保存在id指向的内存中,并将id和ptr指向的对象相关联。
- void* idr_find(struct idr*idp,int id)函数返回id关联的对象指针。
- void idr_remove(struct idr*idp,int id)将id关联的指针一起从映射中删除。void idr_destroy(struct idr*idp)函数撤销一个idr,它只释放idr中未使用的内存,并不释放分配给UID使用的任何内存。
红黑树
- Linux主要的平衡二叉树数据结构就是红黑树,红黑树的属性主要有五个:所有的节点要么是红色要么是黑色,叶节点都是黑色,叶节点不包含数据,如果一个节点是红色则其子节点都是黑色, 任意一个节点到其各个叶子节点的黑色节点数是相同的。以上条件保证了最深的叶子节点的深度不会大于两倍的最浅叶子节点的深度。
- Linux实现的红黑树称为rbtree,其根节点的结构体为rb_root,其他子节点的结构体为rb_node。
- rb_link_node()方法再给定位置插入新的节点,rb_insert_color()执行复杂的再平衡动作。rb_entry(ptr,type,member)方法返回包含rb_ndoe的父类型结构体。