赞
踩
下面是截取内核源码,有部分修改方便自己测试使用
#ifndef _LINUX_LIST_H #define _LINUX_LIST_H // include/linux/types.h 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) // 初始化链表,前驱和后继都指向自己 static inline void INIT_LIST_HEAD(struct list_head *list){ list->next = list; list->prev = list; } // 往链表插入节点内部方法 prv <=> new <=> next 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; } // 在head 节点插入 new 节点,head <=> new <=> head->next(利于堆栈实现) static inline void list_add(struct list_head *new, struct list_head *head){ __list_add(new, head, head->next); } // 在head 节点插入 new 节点,head->prev <=> new <=> head (利于队列实现) static inline void list_add_tail(struct list_head *new, struct list_head *head){ __list_add(new, head->prev, head); } // 删除节点内部方法 static inline void __list_del(struct list_head * prev, struct list_head * next){ next->prev = prev; prev->next = next; } // 删除entry节点,并时prev = NULL static inline void __list_del_clearprev(struct list_head *entry){ __list_del(entry->prev, entry->next); entry->prev = NULL; } // 删除entry节点 static inline void __list_del_entry(struct list_head *entry){ __list_del(entry->prev, entry->next); } // 删除entry节点, 使entry->next,prev 为null (在Linux内部为非法值,访问产生缺页中断) static inline void list_del(struct list_head *entry){ __list_del_entry(entry); entry->next = NULL; entry->prev = NULL; } // new 节点 替换 old 节点 static inline void list_replace(struct list_head *old,struct list_head *new){ new->next = old->next; new->next->prev = new; new->prev = old->prev; new->prev->next = new; } // new 节点 替换 old 节点,并初始化 old static inline void list_replace_init(struct list_head *old, struct list_head *new){ list_replace(old, new); INIT_LIST_HEAD(old); } // 交换两个节点位置 static inline void list_swap(struct list_head *entry1, struct list_head *entry2){ struct list_head *pos = entry2->prev; list_del(entry2); list_replace(entry1, entry2); if (pos == entry1) pos = entry2; list_add(entry1, pos); } // 删除entry节点,并初始化entry static inline void list_del_init(struct list_head *entry){ __list_del_entry(entry); INIT_LIST_HEAD(entry); } // 删除list 节点,并将其添加到head节点后 static inline void list_move(struct list_head *list, struct list_head *head){ __list_del_entry(list); list_add(list, head); } // 删除list 节点,并将其添加到head节点前 static inline void list_move_tail(struct list_head *list, struct list_head *head){ __list_del_entry(list); list_add_tail(list, head); } // 确定MEMBER 成员在TYPE 结构体的偏移量 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) // 知道type 结构体的 member 成员指针 ptr, 获取该结构体的指针 #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) #define list_entry(ptr, type, member) container_of(ptr, type, member) // 从链表ptr头 获取第一个元素 #define list_first_entry(ptr, type, member) list_entry((ptr)->next, type, member) // 从链表ptr头 获取最后一个元素 #define list_last_entry(ptr, type, member) list_entry((ptr)->prev, type, member) // 从链表ptr头 获取第一个元素,如果链表如空返回 NULL #define list_first_entry_or_null(ptr, type, member) ({ \ struct list_head *head__ = (ptr); \ struct list_head *pos__ = READ_ONCE(head__->next); \ pos__ != head__ ? list_entry(pos__, type, member) : NULL; \ }) // 从结构体pos 获取下一个元素 #define list_next_entry(pos, member) \ list_entry((pos)->member.next, typeof(*(pos)), member) // 从结构体pos 获取前一个元素 #define list_prev_entry(pos, member) \ list_entry((pos)->member.prev, typeof(*(pos)), member) // 链表节点遍历,从表头head开始,逐项向后(next方向)移动pos,直至又回到head,基于列表不变的基础上 #define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next) // 在当前pos 节点继续遍历 #define list_for_each_continue(pos, head) \ for (pos = pos->next; pos != (head); pos = pos->next) // 在当前pos 节点往前遍历 #define list_for_each_prev(pos, head) \ for (pos = (head)->prev; pos != (head); pos = pos->prev) // 安全遍历一个链表,通过传入两个参数pos,n 可以在链表中删除pos #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) #define list_for_each_prev_safe(pos, n, head) \ for (pos = (head)->prev, n = pos->prev; \ pos != (head); \ pos = n, n = pos->prev) #define list_entry_is_head(pos, head, member) \ (&pos->member == (head)) // 遍历链表,但是获得是结构体 #define list_for_each_entry(pos, head, member) \ for (pos = list_first_entry(head, typeof(*pos), member); \ !list_entry_is_head(pos, head, member); \ pos = list_next_entry(pos, member)) // 反向遍历链表 #define list_for_each_entry_reverse(pos, head, member) \ for (pos = list_last_entry(head, typeof(*pos), member); \ !list_entry_is_head(pos, head, member); \ pos = list_prev_entry(pos, member)) // 以安全的方式遍历链表 #define list_for_each_entry_safe(pos, n, head, member) \ for (pos = list_first_entry(head, typeof(*pos), member), \ n = list_next_entry(pos, member); \ !list_entry_is_head(pos, head, member); \ pos = n, n = list_next_entry(n, member)) #endif
形成的数据结果如图
#include <stdio.h> #include <stdlib.h> #include "list.h" /* 整体需求: type2 组成一条链表,里面的每个节点包含 type1 类型的链表 */ struct type1{ int value; struct list_head list; }; struct type2 { int id; struct type1 item; struct list_head list; }; int id_count = 0; struct type2 src; int find_by_id (int id,struct type2 **tmp) { struct list_head *pos; list_for_each(pos, &(src.list)){ *tmp = list_entry(pos, struct type2, list); if ((*tmp)->id == id) { return 0; } } return -1; } int add_type2(int * id) { struct type2 *tmp; tmp = malloc(sizeof(struct type2)); INIT_LIST_HEAD(&(tmp->item.list)); id_count ++; tmp->id = id_count; *id = id_count; list_add(&(tmp->list),&(src.list)); return 0; } int del_type2(int id){ struct type2 *tmp; struct type1 *prev, *next; int ret = find_by_id(id,&tmp); if (ret) return ret; list_for_each_entry_safe(prev, next, &(tmp->item.list), list) { if(prev) { list_del(&(prev->list)); free(prev); } } list_del(&(tmp->list)); free(tmp); return 0; } int add_type1(int id,int value) { struct type2 *tmp; struct type1 *item_tmp; int ret = find_by_id(id,&tmp); if (ret) return ret; item_tmp = malloc(sizeof(struct type1)); item_tmp->value = value; list_add(&(item_tmp->list),&(tmp->item.list)); return 0; } int del_type1(int id,int value) { struct type2 *tmp; struct list_head *type1_ptr; struct type1 *item_tmp; int ret = find_by_id(id,&tmp); if (ret) return ret; // 释放 plr_sync_item list_for_each(type1_ptr, &(tmp->item.list)){ item_tmp = list_entry(type1_ptr, struct type1, list); if (item_tmp->value == value) { list_del(type1_ptr); free(item_tmp); return 0; } } return -1; } // 销毁数据 int del() { struct type2 *tmp_prev,*tmp_next; struct type1 *type2_prev,*type2_next; list_for_each_entry_safe(tmp_prev,tmp_next,&(src.list),list) { if (!tmp_prev) { printf("error\n"); continue; } list_for_each_entry_safe(type2_prev,type2_next,&(tmp_prev->item.list),list) { if (type2_prev) { list_del(&(type2_prev->list)); free(type2_prev); } } list_del(&(tmp_prev->list)); free(tmp_prev); } return 0; } int print_list() { struct type2 *tmp; struct type1 *type1_tmp; printf("----------------------------\n"); list_for_each_entry(tmp,&(src.list),list) { printf("id=%d:",tmp->id); list_for_each_entry(type1_tmp,&(tmp->item.list),list) { printf("%d, ",type1_tmp->value); } printf("\n"); } return 0; } int main() { int opt; int type1_id; int value; INIT_LIST_HEAD(&(src.list)); while(~scanf("%d",&opt)) { switch (opt) { case 1: { add_type2(&type1_id); break; } case 2: { scanf("%d",&value); del_type2(value); break; } case 3: { scanf("%d",&value); add_type1(type1_id,value); break; } case 4: { scanf("%d",&value); del_type1(type1_id,value); break; } } print_list(); } del(); print_list(); return 0; }
输入测试
# test.log
1
3 1
3 2
1
3 3
3 4
4 4
2 1
#include <linux/init.h> // __init,__exit macro #include <linux/module.h> // included for all kernel modules #include <linux/ioctl.h> #include <linux/uaccess.h> // copy_from_user #include <linux/list.h> #include <linux/slab.h> #include <linux/fs.h> // file_operation is defined in this header #include <linux/device.h> #include <linux/err.h> // PTR_ERR /* 整体需求: type2 组成一条链表,里面的每个节点包含 type1 类型的链表 */ #define ERR(fmt, args...) printk(KERN_ERR "%s()-%d: " fmt "\n", __func__, __LINE__, ##args) #define DBG(fmt, args...) printk(KERN_DEBUG "%s()-%d: " fmt "\n", __func__, __LINE__, ##args) struct type1{ int value; struct list_head list; }; struct type2 { int id; struct type1 item; struct list_head list; }; struct param{ int value; int id; }; int majorNumber; struct class* list_test_module_class = NULL; struct device* list_test_module_device = NULL; //define device name #define DEVICE_NAME "list_test" #define CLASS_NAME "list_test_module" int id_count = 0; struct type2 src; // iotcl 命令相关定义 #define PLR_SYNC_MAGIC 'l' #define ADD_TYPE2 _IOR(PLR_SYNC_MAGIC, 1,int) #define DEL_TYPE2 _IOW(PLR_SYNC_MAGIC, 2,int) #define ADD_TYPE1 _IOW(PLR_SYNC_MAGIC, 3,struct param) #define DEL_TYPE1 _IOW(PLR_SYNC_MAGIC, 4,struct param) #define PRINT _IO(PLR_SYNC_MAGIC,5) // 用户态调用ioctl 回调函数 static long list_test_module_ioctl(struct file *, unsigned int, unsigned long); struct file_operations ply_sync_ops = { .owner = THIS_MODULE, .unlocked_ioctl = list_test_module_ioctl }; // 模块初始化,退出函数 static int __init list_test_init(void); static void __exit list_test_exit(void); // 链表操作相关函数 int add_type2(int *id); int del_type2(int id); int add_type1(int id,int value); int del_type1(int id,int value); int del(void); int print_list(void); static int __init list_test_init(void) { DBG("list_test_init enter"); majorNumber = register_chrdev(0, DEVICE_NAME, &ply_sync_ops); if(majorNumber < 0){ ERR("[TestModule:] Failed to register a major number."); return majorNumber; } DBG("[TestModule:] Successful to register a major number %d.", majorNumber); //接下来,注册设备类 list_test_module_class = class_create(THIS_MODULE, CLASS_NAME); if(IS_ERR(list_test_module_class)){ unregister_chrdev(majorNumber, DEVICE_NAME); ERR("[TestModule:] Class device register failed!"); return PTR_ERR(list_test_module_class); } DBG("[TestModule:] Class device register success!"); //最后,使用device_create函数注册设备驱动 list_test_module_device = device_create(list_test_module_class, NULL, MKDEV(majorNumber, 0), NULL, DEVICE_NAME); if (IS_ERR(list_test_module_device)){ class_destroy(list_test_module_class); unregister_chrdev(majorNumber, DEVICE_NAME); ERR("Failed to create the device"); return PTR_ERR(list_test_module_device); } // 初始化链表 INIT_LIST_HEAD(&(src.list)); DBG("list_test_init exit"); return 0; } static void __exit list_test_exit(void) { DBG("list_test_exit enter"); // 退出时,依次清理生成的device, class和chrdev // 这样就将系统/dev下的设备文件删除,并自动注销了/proc/devices的设备 device_destroy(list_test_module_class, MKDEV(majorNumber, 0)); class_destroy(list_test_module_class); unregister_chrdev(majorNumber, DEVICE_NAME); // 销毁链表 del(); DBG("list_test_init exot"); } //本模块ioctl回调函数的实现 static long list_test_module_ioctl(struct file *file, /* ditto */ unsigned int cmd, /* number and param for ioctl */ unsigned long param) { /* ioctl回调函数中一般都使用switch结构来处理不同的输入参数(cmd) */ int ret = -EINVAL; // 表示 无效的参数,包括参数值、类型或数目无效等 struct param info; switch(cmd){ case ADD_TYPE2:{ ret = add_type2((int *)param); break; } case DEL_TYPE2: { ret = del_type2(param); break; } case ADD_TYPE1: { // 先从用户态复制数据 ret = copy_from_user(&info, (struct param __user *)param, sizeof(info)); // 拷贝发生错误 if (ret) return -EFAULT; ret = add_type1(info.id,info.value); break; } case DEL_TYPE1: { // 先从用户态复制数据 ret = copy_from_user(&info, (struct param __user *)param, sizeof(info)); // 拷贝发生错误 if (ret) return -EFAULT; ret = del_type1(info.id,info.value); break; } case PRINT: { print_list(); break; } default: ERR("[TestModule:] Unknown ioctl cmd!"); } return ret; } int find_by_id (int id,struct type2 **tmp) { struct list_head *pos; list_for_each(pos, &(src.list)){ *tmp = list_entry(pos, struct type2, list); if ((*tmp)->id == id) { return 0; } } return -1; } int add_type2(int *id) { struct type2 *tmp; tmp = kmalloc(sizeof(struct type2),GFP_KERNEL); INIT_LIST_HEAD(&(tmp->item.list)); id_count ++; tmp->id = id_count; *id = id_count; list_add(&(tmp->list),&(src.list)); return 0; } int del_type2(int id){ struct type2 *tmp; struct type1 *prev, *next; int ret = find_by_id(id,&tmp); if (ret) return ret; list_for_each_entry_safe(prev, next, &(tmp->item.list), list) { if(prev) { list_del(&(prev->list)); kfree(prev); } } list_del(&(tmp->list)); kfree(tmp); return 0; } int add_type1(int id,int value) { struct type2 *tmp; struct type1 *item_tmp; int ret = find_by_id(id,&tmp); if (ret) return ret; item_tmp = kmalloc(sizeof(struct type1),GFP_KERNEL); item_tmp->value = value; list_add(&(item_tmp->list),&(tmp->item.list)); return 0; } int del_type1(int id,int value) { struct type2 *tmp; struct list_head *type1_ptr; struct type1 *item_tmp; int ret = find_by_id(id,&tmp); if (ret) return ret; // 释放 list_test_item list_for_each(type1_ptr, &(tmp->item.list)){ item_tmp = list_entry(type1_ptr, struct type1, list); if (item_tmp->value == value) { list_del(type1_ptr); kfree(item_tmp); return 0; } } return -1; } int del() { struct type2 *tmp_prev,*tmp_next; struct type1 *type2_prev,*type2_next; list_for_each_entry_safe(tmp_prev,tmp_next,&(src.list),list) { if (!tmp_prev) { printk("error\n"); continue; } list_for_each_entry_safe(type2_prev,type2_next,&(tmp_prev->item.list),list) { if (type2_prev) { list_del(&(type2_prev->list)); kfree(type2_prev); } } list_del(&(tmp_prev->list)); kfree(tmp_prev); } return 0; } int print_list() { struct type2 *tmp; struct type1 *type1_tmp; printk("----------------------------\n"); list_for_each_entry(tmp,&(src.list),list) { printk("id=%d:",tmp->id); list_for_each_entry(type1_tmp,&(tmp->item.list),list) { printk("%d, ",type1_tmp->value); } printk("\n"); } return 0; } module_init(list_test_init); module_exit(list_test_exit); MODULE_AUTHOR("antrain"); MODULE_DESCRIPTION("kernel list test"); MODULE_LICENSE("GPL");
makefile
MODULE_NAME := test_list #MODCFLAGS:=-O2 -Wall -DMODULE -D__KERNEL__ -DLINUX -std=c99 #EXTRA_CFLAGS += $(MODULE_FLAGS) $(CFG_INC) $(CFG_INC) EXTRA_CFLAGS += -g -std=gnu99 -Wfatal-errors ifneq ($(KERNELRELEASE),) # kernelspace obj-m := $(MODULE_NAME).o else # userspace CURRENT_PATH ?= $(shell pwd) LINUX_KERNEL ?= $(shell uname -r) LINUX_KERNEL_PATH ?= /lib/modules/$(LINUX_KERNEL)/build CURRENT_PATH := $(shell pwd) modules: make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules modules_install: make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules_install clean: make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean rm -f modules.order Module.symvers Module.markers .PHNOY: modules modules_install clean endif
#include <stdlib.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> #include <sys/ioctl.h> #include <stdio.h> #define PLR_SYNC_MAGIC 'l' #define ADD_TYPE2 _IOR(PLR_SYNC_MAGIC, 1,int) #define DEL_TYPE2 _IOW(PLR_SYNC_MAGIC, 2,int) #define ADD_TYPE1 _IOW(PLR_SYNC_MAGIC, 3,struct param) #define DEL_TYPE1 _IOW(PLR_SYNC_MAGIC, 4,struct param) #define PRINT _IO(PLR_SYNC_MAGIC,5) struct param{ int value; int id; }; int main(){ // 打开设备 int opt; int type1_id; int value; int ret; int fd = open("/dev/list_test",O_RDWR); if (fd<0) { perror("Failed to open the device..."); return -1; } struct param p; while(~scanf("%d",&opt)) { switch (opt) { case 1: { ioctl(fd, ADD_TYPE2,&type1_id); break; } case 2: { scanf("%d",&value); ioctl(fd, DEL_TYPE2,value); break; } case 3: { scanf("%d",&value); p.id = type1_id; p.value = value; ioctl(fd, ADD_TYPE1,&p); break; } case 4: { scanf("%d",&value); p.id = type1_id; p.value = value; ioctl(fd, DEL_TYPE1,&p); break; } case 5: { ioctl(fd,PRINT); } } } close(fd); return 0; }
在虚拟机进行测试
# 删除缓存数据 sudo dmesg -C # 编译 make # 加载模块 sudo insmod test_list.ko # 编译 gcc -o test test.c # 测试数据 test.log 1 3 1 3 2 1 3 3 3 4 5 4 4 5 2 1 5 # 测试, 使用sudo 因为默认添加的设备可能需要权限 sudo ./test < test.log # 卸载模块 sudo rmmod test_list # 查看内核输出 dmesg
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。