Github: list_for_each_prev_safe
Email: BuddyZhang1 buddy.zhang@aliyun.com
目录
源码分析
/**
* list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
* @pos: the &struct list_head to use as a loop cursor.
* @n: another &struct list_head to use as temporary storage
* @head: the head for your list.
*/
#define list_for_each_prev_safe(pos, n, head) \
for ( pos = ( head ) -> prev , n = pos -> prev ; \
pos != ( head ); \
pos = n , n = pos -> prev )
list_for_each_prev_safe() 函数用于倒叙遍历双链表中的节点。如果遍历节点的目的是为了
删除遍历到的节点,那么使用这个函数是安全的。参数 pos 指向当前遍历的节点;参数 n 指向前一个
遍历的节点;head 指向双链表的表头。函数使用 for 循环从 head 链表的末尾开始倒叙遍历链表,
以此将 n 指向当前遍历到节点的前一个,以防止当前节点删除后,前一个节点状态未知。
实践
驱动源码
/*
* bindirect-list
*
* (C) 20179.04.25 <buddy.zhang@aliyun.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/*
* bidirect-list
*
* +-----------+<--o +-----------+<--o +-----------+<--o +-----------+
* | | | | | | | | | | |
* | prev | o----| prev | o----| prev | o----| prev |
* | list_head | | list_head | | list_head | | list_head |
* | next |---o | next |---o | next |---o | next |
* | | | | | | | | | | |
* +-----------+ o--->+-----------+ o--->+-----------+ o--->+-----------+
*
*/
#include <linux/kernel.h>
#include <linux/init.h>
/* header of list */
#include <linux/list.h>
/* private structure */
struct node {
const char * name ;
struct list_head list ;
};
/* Initialize a group node structure */
static struct node node0 = { . name = "BiscuitOS_node0" , };
static struct node node1 = { . name = "BiscuitOS_node1" , };
static struct node node2 = { . name = "BiscuitOS_node2" , };
static struct node node3 = { . name = "BiscuitOS_node3" , };
static struct node node4 = { . name = "BiscuitOS_node4" , };
static struct node node5 = { . name = "BiscuitOS_node5" , };
static struct node node6 = { . name = "BiscuitOS_node6" , };
/* Declaration and implement a bindirect-list */
LIST_HEAD ( BiscuitOS_list );
static __init int bindirect_demo_init ( void )
{
struct list_head * np ;
struct list_head * n ;
/* add a new entry on special entry */
list_add_tail ( & node0 . list , & BiscuitOS_list );
list_add_tail ( & node1 . list , & BiscuitOS_list );
list_add_tail ( & node2 . list , & BiscuitOS_list );
list_add_tail ( & node3 . list , & BiscuitOS_list );
list_add_tail ( & node4 . list , & BiscuitOS_list );
list_add_tail ( & node5 . list , & BiscuitOS_list );
list_add_tail ( & node6 . list , & BiscuitOS_list );
printk ( "BiscuitOS_list: \n " );
/* Traverser all node on bindirect-list */
list_for_each_prev_safe ( np , n , & BiscuitOS_list ) {
printk ( "%s \n " , list_entry ( np , struct node , list ) -> name );
list_del ( np );
}
return 0 ;
}
device_initcall ( bindirect_demo_init );
驱动安装
驱动的安装很简单,首先将驱动放到 drivers/BiscuitOS/ 目录下,命名为 list.c,
然后修改 Kconfig 文件,添加内容参考如下:
diff --git a/drivers/BiscuitOS/Kconfig b/drivers/BiscuitOS/Kconfig
index 4edc5a5..1a9abee 100644
--- a/drivers/BiscuitOS/Kconfig
+++ b/drivers/BiscuitOS/Kconfig
@@ -6 ,4 +6,14 @@ if BISCUITOS_DRV
config BISCUITOS_MISC
bool "BiscuitOS misc driver"
+config BISCUITOS_LIST
+ bool "Bindirect-list"
+
+if BISCUITOS_LIST
+
+config DEBUG_BISCUITOS_LIST
+ bool "list_for_each_prev_safe"
+
+endif # BISCUITOS_LIST
+
endif # BISCUITOS_DRV
接着修改 Makefile,请参考如下修改:
diff --git a/drivers/BiscuitOS/Makefile b/drivers/BiscuitOS/Makefile
index 82004c9..9909149 100644
--- a/drivers/BiscuitOS/Makefile
+++ b/drivers/BiscuitOS/Makefile
@@ -1 +1,2 @@
obj-$( CONFIG_BISCUITOS_MISC) += BiscuitOS_drv.o
+obj-$( CONFIG_BISCUITOS_LIST) += list.o
--
驱动配置
驱动配置请参考下面文章中关于驱动配置一节。在配置中,勾选如下选项,如下:
Device Driver--->
[ * ] BiscuitOS Driver--->
[ * ] Bindirect-list
[ * ] list_for_each_prev_safe()
具体过程请参考:
Linux 5.0 开发环境搭建 – 驱动配置
驱动编译
驱动编译也请参考下面文章关于驱动编译一节:
Linux 5.0 开发环境搭建 – 驱动编译
驱动运行
驱动的运行,请参考下面文章中关于驱动运行一节:
Linux 5.0 开发环境搭建 – 驱动运行
启动内核,并打印如下信息:
ledtrig - cpu: registered to indicate activity on CPUs
usbcore: registered new interface driver usbhid
usbhid: USB HID core driver
BiscuitOS_list :
BiscuitOS_node6
BiscuitOS_node5
BiscuitOS_node4
BiscuitOS_node3
BiscuitOS_node2
BiscuitOS_node1
BiscuitOS_node0
aaci - pl041 10004000 . aaci : ARM AC ' 97 Interface PL041 rev0 at 0x10004000 , irq 24
aaci - pl041 10004000 . aaci : FIFO 512 entries
oprofile: using arm / armv7 - ca9
驱动分析
当遍历节点中涉及删除遍历到的节点,应该使用 list_for_each_prev_safe() 函数。这不会
引起内核 panic。
附录
BiscuitOS Home
BiscuitOS Driver
BiscuitOS Kernel Build
Linux Kernel
Bootlin: Elixir Cross Referencer
搭建高效的 Linux 开发环境
赞赏一下吧 🙂