学习linux内核(二)
来源:互联网 发布:超星网络课答案 编辑:程序博客网 时间:2024/05/23 14:37
这次学习一下linux内核里如何构建单链表。
单链表定义在include/linux目录下的llist.h,llist.c文件定义在lib目录下。
llist.h文件里开头“Lock-less NULL terminated single linked list”,告诉我们这个单链表是以NULL结束的。
全部介绍:
/* * Lock-less NULL terminated single linked list * * If there are multiple producers and multiple consumers, llist_add * can be used in producers and llist_del_all can be used in * consumers. They can work simultaneously without lock. But * llist_del_first can not be used here. Because llist_del_first * depends on list->first->next does not changed if list->first is not * changed during its operation, but llist_del_first, llist_add, * llist_add (or llist_del_all, llist_add, llist_add) sequence in * another consumer may violate that. * * If there are multiple producers and one consumer, llist_add can be * used in producers and llist_del_all or llist_del_first can be used * in the consumer. * * This can be summarized as follow: * * | add | del_first | del_all * add | - | - | - * del_first | | L | L * del_all | | | - * * Where "-" stands for no lock is needed, while "L" stands for lock * is needed. * * The list entries deleted via llist_del_all can be traversed with * traversing function such as llist_for_each etc. But the list * entries can not be traversed safely before deleted from the list. * The order of deleted entries is from the newest to the oldest added * one. If you want to traverse from the oldest to the newest, you * must reverse the order by yourself before traversing. * * The basic atomic operation of this list is cmpxchg on long. On * architectures that don't have NMI-safe cmpxchg implementation, the * list can NOT be used in NMI handlers. So code that uses the list in * an NMI handler should depend on CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG. * * Copyright 2010,2011 Intel Corp. * Author: Huang Ying <ying.huang@intel.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; * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */本人英语水平很差,上文就不翻译。
这次实现单链表的add与del_all。
实现代码
llist.h文件:
#ifndef LLIST_H#define LLIST_H#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))#define LLIST_HEAD_INIT(name) {NULL}#define LLIST_HEAD(name) struct llist_head name = LLIST_HEAD_INIT(name)#define container_of(ptr, type, member) ({ \const typeof( ((type *)0)->member ) *__mptr = (ptr); \(type *)( (char *)__mptr - offsetof(type, member) );})typedef _Bool bool;struct llist_head{struct llist_node *first;};struct llist_node{struct llist_node *next;};static unsigned long xchg(unsigned long *p, unsigned long val){return __atomic_exchange_n(p, val, __ATOMIC_SEQ_CST);}static unsigned long cmpxchg(unsigned long *p, unsigned long expected,unsigned long desired){unsigned long exp = expected;__atomic_compare_exchange_n(p, &exp, desired, 0,__ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);return exp;}bool llist_add_batch(struct llist_node *new_first, struct llist_node *new_last,struct llist_head *head){struct llist_node *first;do{new_last->next = first = ACCESS_ONCE(head->first);}while(cmpxchg(&head->first, first, new_first) != first);return !first;}static inline void init_llist_head(struct llist_head *list){list->first = NULL;}#endif
llist.c文件:
#include <stdio.h>#include <malloc.h>#include "llist.h" #define llist_entry(ptr, type, member)\container_of(ptr, type, member)struct student{int id;char *name;struct llist_node node;};extern bool llist_add_batch(struct llist_node *new_first, struct llist_node *new_last, struct llist_head *head);static inline bool llist_add(struct llist_node *new, struct llist_head *head){return llist_add_batch(new, new, head);}static inline struct llist_node *llist_del_all(struct llist_head *head){return xchg(&head->first, NULL);}int main(int argc, char *argv[]){LLIST_HEAD(head);init_llist_head(&head);for(int i = 0; i < 5; i++){struct student *data = (struct student *)malloc(sizeof(struct student));data->id = i + 1;printf("学生姓名:");scanf("%s", &data->name);llist_add(&data->node, &head);}struct llist_node *p = head.first;struct student *a;while(NULL != p){a = llist_entry(p, struct student, node);printf("学生id:%d,姓名:%s\n", a->id, &a->name);p = p->next;}printf("删除所有节点\n");llist_del_all(&head);p = head.first;while(NULL != p){a = llist_entry(p, struct student, node);printf("学生id:%d,姓名:%s\n", a->id, &a->name);p = p->next;}return 0;}
测试效果
学生姓名:z学生姓名:x学生姓名:c学生姓名:v学生姓名:b学生id:5,姓名:b学生id:4,姓名:v学生id:3,姓名:c学生id:2,姓名:x学生id:1,姓名:z删除所有节点
linux内核定义链表的方式跟我们定义的方式有很大的区别。
由于单链表与双链表形式差不多,所以用双链表的示例图文代替,体现区别在哪里。
传统的链表有个最大的缺点就是不好共通化,因为每个node中的data1,data2等等都是不确定的(无论是个数还是类型)。
linux中的链表巧妙的解决了这个问题,linux的链表不是将用户数据保存在链表节点中,而是将链表节点保存在用户数据中。
在后面的博客里再具体分析一下上面的代码。
注:编译代码需要gcc编译器(代码里包含了gcc的内嵌函数)。
阅读全文
0 0
- 学习linux内核(二)
- linux内核代码学习笔记(二)
- Linux 0.11内核学习(二)
- linux内核I2C子系统学习(二)
- Linux内核list_head学习(二)
- [LINUX内核编程]学习笔记(二)
- linux内核I2C子系统学习(二)
- Linux内核list_head学习(二)
- Linux 内核 list_head 学习(二)
- Linux内核list_head学习(二)
- Linux内核学习(二):数据结构
- Linux内核list_head学习(二)
- linux内核学习笔记(二)
- linux内核学习之二:编译内核
- Linux内核学习篇二:内核初始化
- Linux内核学习-Linux系统的初始化(二)
- Linux内核学习-字符设备驱动学习(二)
- Linux内核学习-字符设备驱动学习(二)
- python绘制神经网络(转载)
- 异常浅析
- 嵌入式系统概述(学习笔记)
- griview绑定数据源后显示调用update方法的实现
- CSS小功能
- 学习linux内核(二)
- 常用正则表达式
- Powershell命令笔记
- oracle 序列和触发器的联合使用
- mysql我所遇到的问题case when then的使用
- 常见浏览器兼容性
- 10-S3C2440驱动学习(六)嵌入式linux-触摸屏设备驱动
- String的subString()和toUpCase()用法
- MyBatis学习笔记