Linux | 数据结构之内核链表

这篇博客详细介绍了Linux内核链表的数据结构,包括链表的源码解析、节点类型、初始化、插入、删除、移动节点的操作,以及相关的宏定义。通过实例和拓展问题,帮助读者深入掌握内核链表的使用。

Linux | 数据结构之内核链表


时间:2023年12月20日15:42:45

1.参考

1.数据结构与算法教程,数据结构C语言版教程! (biancheng.net)

2.双向链表及创建(C语言)详解 (biancheng.net)

3.内核数据结构 —— 内核链表_内核链表长度怎么表示-CSDN博客

4.内核链表 - 搜索 (bing.com)

5.Linux | 内核链表-CSDN博客

6.structure/1_kernellist · cProgram/100Example - 码云 - 开源中国 (gitee.com)

2.内核链表

2-1.源码

[fly@752fac4b02e9 kernel]$ find ./ -name list.h
./include/linux/list.h
./include/config/debug/pi/list.h
./include/config/defconfig/list.h
./tools/perf/util/include/linux/list.h
#ifndef _LINUX_LIST_H
#define _LINUX_LIST_H

#ifndef ARCH_HAS_PREFETCH
#define ARCH_HAS_PREFETCH
static inline void prefetch(const void *x) {;}
#endif

/*
 * Simple doubly linked list implementation.
 *
 * Some of the internal functions ("__xxx") are useful when
 * manipulating whole lists rather than single entries, as
 * sometimes we already know the next/prev entries and we can
 * generate better code by using them directly rather than
 * using the generic single-entry routines.
 */

struct list_head {
	struct list_head *next, *prev;
};

#define LIST_HEAD_INIT(name) { &(name), &(name) }

#define LIST_HEAD(name) \
	struct list_head name = LIST_HEAD_INIT(name)

#define INIT_LIST_HEAD(ptr) do { \
	(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)

/*
 * Insert a new entry between two known consecutive entries.
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 */
static inline void __list_add(struct list_head *new,
			      struct list_head *prev,
			      struct list_head *next)
{
	next->prev = new;
	new->next = next;
	new->prev = prev;
	prev->next = new;
}

/**
 * list_add - add a new entry
 * @new: new entry to be added
 * @head: list head to add it after
 *
 * Insert a new entry after the specified head.
 * This is good for implementing stacks.
 */
static inline void list_add(struct list_head *new, struct list_head *head)
{
	__list_add(new, head, head->next);
}

/**
 * list_add_tail - add a new entry
 * @new: new entry to be added
 * @head: list head to add it before
 *
 * Insert a new entry before the specified head.
 * This is useful for implementing queues.
 */
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
	__list_add(new, head->prev, head);
}

/*
 * Delete a list entry by making the prev/next entries
 * point to each other.
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 */
static inline void __list_del(struct list_head *prev, struct list_head *next)
{
	next->prev = prev;
	prev->next = next;
}

/**
 * list_del - deletes entry from list.
 * @entry: the element to delete from the list.
 * Note: list_empty on entry does not return true after this, the entry is in an undefined state.
 */
static inline void list_del(struct list_head *entry)
{
	__list_del(entry->prev, entry->next);
	entry->next = (void *) 0;
	entry->prev = (void *) 0;
}

/**
 * list_del_init - deletes entry from list and reinitialize it.
 * @entry: the element to delete from the list.
 */
static inline void list_del_init(struct list_head *entry)
{
	__list_del(entry->prev, entry->next);
	INIT_LIST_HEAD(entry);
}

/**
 * list_move - delete from one list and add as another's head
 * @list: the entry to move
 * @head: the head that will precede our entry
 */
static inline void list_move(struct list_head *list, struct list_head *head)
{
	__list_del(list->prev, list->next);
	list_add(list, head);
}

/**
 * list_move_tail - delete from one list and add as another's tail
 * @list: the entry to move
 * @head: the head that will follow our entry
 */
static inline void list_move_tail(struct list_head *list,
				  struct list_head *head)
{
	__list_del(list->prev, list->next);
	list_add_tail(list, head);
}

/**
 * list_empty - tests whether a list is empty
 * @head: the list to test.
 */
static inline int list_empty(struct list_head *head)
{
	return head->next == head;
}

static inline void __list_splice(struct list_head *list,
				 struct list_head *head)
{
	struct list_head *first = list->next;
	struct list_head *last = list->prev;
	struct list_head *at = head->next;

	first->prev = head;
	head->next = first;

	last->next = at;
	at->prev = last;
}

/**
 * list_splice - join two lists
 * @list: the new list to add.
 * @head: the place to add it in the first list.
 */
static inline void list_splice(struct list_head *list, struct list_head *head)
{
	if (!list_empty(list))
		__list_splice(list, head);
}

/**
 * list_splice_init - join two lists and reinitialise the emptied list.
 * @list: the new list to add.
 * @head: the place to add it in the first list.
 *
 * The list at @list is reinitialised
 */
static inline void list_splice_init(struct list_head *list,
				    struct list_head *head)
{
	if (!list_empty(list)) {
		__list_splice(list, head);
		INIT_LIST_HEAD(list);
	}
}

/**
 * list_entry - get the struct for this entry
 * @ptr:	the &struct list_head pointer.
 * @type:	the type of the struct this is embedded in.
 * @member:	the name of the list_struct within the struct.
 */
#define list_entry(ptr, type, member) \
	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))

/**
 * list_for_each	-	iterate over a list
 * @pos:	the &struct list_head to use as a loop counter.
 * @head:	the head for your list.
 */
#define list_for_each(pos, head) \
	for (pos = (head)->next, prefetch(pos->next); pos != (head); \
		pos = pos->next, prefetch(pos->next))
/**
 * list_for_each_prev	-	iterate over a list backwards
 * @pos:	the &struct list_head to use as a loop counter.
 * @head:	the head for your list.
 */
#define list_for_each_prev(pos, head) \
	for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \
		pos = pos->prev, prefetch(pos->prev))

/**
 * list_for_each_safe	-	iterate over a list safe against removal of list entry
 * @pos:	the &struct list_head to use as a loop counter.
 * @n:		another &struct list_head to use as temporary storage
 * @head:	the head for your list.
 */
#define list_for_each_safe(pos, n, head) \
	for (pos = (head)->next, n = pos->next; pos != (head); \
		pos = n, n = pos->next)

/**
 * list_for_each_entry	-	iterate over list of given type
 * @pos:	the type * to use as a loop counter.
 * @head:	the head for your list.
 * @member:	the name of the list_struct within the struct.
 */
#define list_for_each_entry(pos, head, member)				\
	for (pos = list_entry((head)->next, typeof(*pos), member),	\
		     prefetch(pos->member.next);			\
	     &pos->member != (head);					\
	     pos = list_entry(pos->member.next, typeof(*pos), member),	\
		     prefetch(pos->member.next))

/**
 * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
 * @pos:	the type * to use as a loop counter.
 * @n:		another type * to use as temporary storage
 * @head:	the head for your list.
 * @member:	the name of the list_struct within the struct.
 */
#define list_for_each_entry_safe(pos, n, head, member)			\
	for (pos = list_entry((head)->next, typeof(*pos), member),	\
		n = list_entry(pos->member.next, typeof(*pos), member); \
	     &pos->member != (head);					\
	     pos = n, n = list_entry(n->member.next, typeof(*n), member))

/**
 * list_for_each_entry_continue -	iterate over list of given type
 *			continuing after existing point
 * @pos:	the type * to use as a loop counter.
 * @head:	the head for your list.
 * @member:	the name of the list_struct within the struct.
 */
#define list_for_each_entry_continue(pos, head, member)			\
	for (pos = list_entry(pos->member.next, typeof(*pos), member),	\
		     prefetch(pos->member.next);			\
	     &pos->member != (head);					\
	     pos = list_entry(pos->member.next, typeof(*pos), member),	\
		     prefetch(pos->member.next))

#endif

2-2.节点类型

在这里插入图片描述

2-3.内核链表相关算法

2-3-1.初始化
2-3-1-1.宏的实现

在这里插入图片描述

2-3-1-2.内联函数的实现

在这里插入图片描述

2-3-2.插入

在这里插入图片描述

2-3-2-1.将new指向的结点插入到head指向的结点后面(表头)

在这里插入图片描述

2-3-2-2.将new指向的结点插入到head指向的结点前面(表尾)

在这里插入图片描述

2-3-3.删除

在这里插入图片描述

2-3-4.移动链表中的某个结点
1)将链表中的某个结点list移动到head指向的结点后面(表头)

在这里插入图片描述

2)将链表中的某个结点list移动到head指向的结点前面(表尾)

在这里插入图片描述

2-3-5、内核链表相关的宏:
1》通过内核结点指针ptr获得内核结点所在的结构体的地址

在这里插入图片描述

2》基于内核结点指针向后循环

在这里插入图片描述

3》基于内核结点指针向后循环

在这里插入图片描述

4》基于数据结点指针向后循环

在这里插入图片描述

3.示例

structure/1_kernellist · cProgram/100Example - 码云 - 开源中国 (gitee.com)

请添加图片描述

4.拓展

1、用顺序栈实现整数的逆序输出。例如输入整数1,2,3,输出3,2,1.

2、用链栈实现十进制向八进制转换。例如输入123,输出0173.

3、分别用循环队列链式队列实现如下功能:用户从键盘输入整数,程序将其入队,用户输入字母,程序将队头元素出队,并在每一次出队和入队之后打印队列元素。

全国1:20万地质图打包卖【文件大小7.13GB】mapgis矢量地质数据分幅岩性断层数据库本数据来自中国地质调查局,目前是我国的、实测的、全国性的1:20万区域地质调查结果。数据格式:mapgis坐标系统:北京1954地理坐标系统20万地质图图例共计2083张涉及1043个图幅图 层 内 容 图层代码 图 层 含 义 图元类型 基本信息图层 L01J 图幅基本信息 弧段 水系图层 L02H 单线河流(含季节性河流和干沟)、海岸线等 弧段 L02S 双线河、湖泊、水库、雪线等 多边形 L02Z 沼泽地 多边形 地层图层 D01J 所有地质界线(包括地层界线、变质地层界线、火山岩性界线、非正式地层单位界线、侵入岩界线及水体界线和断层界线等) 弧段 D01D 沉积地层单位和火山沉积地层单位 多边形 D01B 变质岩系地层单位 多边形 火山岩岩性图层 D02H 火山岩岩性 多边形 非正式地层单位图层 D03D 非正式地层单位 多边形 侵入岩图层 D04N 侵入岩年代单位 多边形 D04P 侵入岩谱系单位 多边形 脉岩图层 D05M 脉岩 多边形 围岩蚀变图层 D06S 各种围岩蚀变带 多边形 混合岩化带、变质相带图层 D07H 各种混合岩化带 多边形 D07B 变质相带 多边形 断层图层 D08D 断层 弧段 构造变形带图层 D09G 构造变形带 多边形 矿产图层 D11K 矿产地 点 产状符号图层 D12C 产状符号 点 其它图元图层 D13H 化石采样点 点 D13T 同位素年龄采样点 点 D13K 钻孔点 点 D13S 各类火山口 点 D13Q 泉点 点 D13P 剖面线 弧段其中, 有部分图幅中脉岩以点图元表示,增加点图元脉岩图层,图层代码为D05T。 有部分图幅中围岩蚀变以点图元表示,增加点图元围岩蚀变图层,图层代码为D06T。 有部分图幅中构造变形带分别为不参与拓扑处理的多边形图元和弧段图元,增加不参与拓扑的多边形构造变形带图层和弧段图元的构造变形带图层,图层代码分别为D09R、D09L。 有部分图幅中产状符号以弧段图元表示,增加弧段图元产状图层,图层代码为D12L。 有部分图幅中火山口以多边形图元表示,增加多边形图元火山口图层,图层代码为D13SP。 图层命名 为图幅编号缩写加图层代码,如若尔盖县幅,图幅编号I-48-19,图幅编号缩写为I4819,对于地质界线图层,图层名即为I4819D01J,对于断层图层,图层名即为I4819D08D,以此类推。 图元编号规则 图元编号为图幅编号缩写加图层代码加5位顺序号。如若尔盖县幅,图幅编号I-48-19,图幅编号缩写为I4819,对于地质界线图层(D01J)中顺序码为00011的某一图元,其图元编号为I4819D01J00011。其中, 有部分图幅中脉岩以点图元表示,增加点图元脉岩图层,图层代码为D05T。 有部分图幅中围岩蚀变以点图元表示,增加点图元围岩蚀变图层,图层代码为D06T。 有部分图幅中构造变形带分别为不参与拓扑处理的多边形图元和弧段图元,增加不参与拓扑的多边形构造变形带图层和弧段图元的构造变形带图层,图层代码分别为D09R、D09L。 有部分图幅中产状符号以弧段图元表示,增加弧段图元产状图层,图层代码为D12L。 有部分图幅中火山口以多边形图元表示,增加多边形图元火山口图层,图层代码为D13SP。 图层命名 为图幅编号缩写加图层代码,如若尔盖县幅,图幅编号I-48-19,图幅编号缩写为I4819,对于地质界线图层,图层名即为I4819D01J,对于断层图层,图层名即为I4819D08D,以此类推。 图元编号规则 图元编号为图幅编号缩写加图层代码加5位顺序号。如若尔盖县幅,图幅编号I-48-19,图幅编号缩写为I4819,对于地质界线图层(D01J)中顺序码为00011的某一图元,其图元编号为I4819D01J00011。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值