閱讀691 返回首頁    go 阿裏雲 go 技術社區[雲棲]


linux驅動開發--內核鏈表

1、內核鏈表定義

在<linux/list.h>中定義

struct list_head{
  struct list_head *next, *prev;
};
在list_head結構中包含兩個指向list_head結構的指針next和prev,在實際使用中,它通常被組織成雙向循環鏈表。

內核鏈表結構體不包含數據域,隻包含維護鏈表的指針域。

內核鏈表被包含在其他數據結構體中使用。

初始化鏈表頭INIT_LIST_HEAD函數
void INIT_LIST_HEAD(struct list_head *list);
list:待初始化鏈表頭
插入節點list_add函數
void list_add(struct list_head *new, struct list_head *head);
void list_add_tail(struct list_head *new, struct list_head *head);

new:待插入到鏈表的新節點
head:待插入到鏈表的鏈表頭

刪除節點list_del函數
void list_del(struct list_head *entry);
entry:待刪除的節點
提取數據結構list_entry宏
#define list_entry(ptr, type, member) container_of(ptr, type, member)
ptr:當前鏈表節點指針
type:包含該鏈表的數據結構體類型
member:在數據結構體類型中的list_head成員名稱
返回:獲取的數據結構體指針
實際是通過已知數據結構體中鏈表節點指針ptr,獲取包含該鏈表節點的數據結構體指針

遍曆鏈表list_for_each宏
#define list_for_each(pos, head) for(pos = (head)->next; prefetch(pos->next), pos != (head); pos = pos->next)
#define list_for_each_safe(pos, n, head) for(pos = (head)->next, n= pos->next; pos !=(head); pos = n, n = pos->next)

pos:list_head指針類型的循環變量
n:list_head指針類型的循環變量
head:待遍曆鏈表的鏈表頭

2、實例代碼:

/**
*Copyright (c) 2013.TianYuan
*All rights reserved.
*
*文件名稱: listtest.c
*文件標識: 內核鏈表的使用
*
*當前版本:1.0
*作者:wuyq 
*
*取代版本:xxx
*原作者:xxx
*完成日期:2013-11-18
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/list.h>

MODULE_LICENSE("GPL");

#define EMPLOYEE_NUM	10

struct employee
{
	char name[20];
	int id;
	int salary;
	int age;
	struct list_head list;
};

/*定義鏈表頭節點*/
struct list_head  employee_list;
struct employee *employeep = NULL;/*保存首地址*/
struct list_head *pos = NULL;/*list_for_each*/
struct employee *employee_tmp = NULL;
static int __init listtest_init(void)
{
	int i = 0;
	
	/*初始化鏈表頭節點*/
	INIT_LIST_HEAD(&employee_list);
	
	/*申請employee空間*/
	employeep = kmalloc(sizeof(struct employee)*EMPLOYEE_NUM, GFP_KERNEL);
	if(IS_ERR(employeep)){
		printk("kmalloc failed!\n");
		return -ENOMEM;
	}
	memset(employeep, 0, sizeof(struct employee)*EMPLOYEE_NUM);
	/*初始化每個struct*/
	for(i=0; i<EMPLOYEE_NUM; i++){
		sprintf(employeep[i].name, "employee%d", i);
		/*true*/sprintf((employeep+i)->name, "employee%d", i);
		employeep[i].id = 10000 + i;
		employeep[i].salary = 10000 + 1000*i;
		/*添加節點到鏈表中*/
		list_add(&(employeep[i].list), &employee_list);
	}
	/*鏈表節點的遍曆*/	
	list_for_each(pos, &employee_list){
		employee_tmp = list_entry(pos, struct employee, list);
		printk("employee name :T=%s\tID:%d\tSalary:%d!\n",
				employee_tmp->name,
				employee_tmp->id,
				employee_tmp->salary);
	}	
		
	return 0;
}

static void __exit listtest_exit(void)
{
	int i = 0;
	for(i=0; i<EMPLOYEE_NUM; i++){
		list_del(&(employeep[i].list));
	}
	
	kfree(employeep);
}

module_init(listtest_init);
module_exit(listtest_exit);

KERNELDIR ?=/root/Desktop/work/ldd3/linux-2.6.31_TX2440A
PWD := $(shell pwd)
obj-m += listtest.o

default:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

clean:
	@rm -f *.o *.ord* *.sy* *.mod.* *.ko



最後更新:2017-04-03 12:53:59

  上一篇:go linux驅動開發--字符設備:自動創建設備節點
  下一篇:go Java to download a file from internet