如下为利用Linux内核链表创建,Linux内核中链表的实现与应用

链表(循环双向链表)是Linux内核中最简单、最常用的一种数据结构。

1、链表的定义

struct list_head {

struct list_head *next, *prev;

}

这个不含数据域的链表,可以嵌入到任何数据结构中,例如可按如下方式定义含有数据域的链表:

struct my_list {

void  * mydata;

struct list_head  list;

} ;

2、链表的声明和初始化宏

struct list_head 只定义了链表结点,并没有专门定义链表头.那么一个链表结点是如何建立起来的?

内核代码 list.h 中定义了两个宏:

#defind  LIST_HEAD_INIT(name)    { &(name), &(name) }      //仅初始化

#defind  LIST_HEAD(name)     struct list_head  name = LIST_HEAD_INIT(name)  //声明并初始化

如果要声明并初始化链表头mylist_head,则直接调用:LIST_HEAD(mylist_head),之后,

mylist_head的next、prev指针都初始化为指向自己。这样,就有了一个带头结点的空链表。

判断链表是否为空的函数:

static inline int list_empty(const struct list_head  * head) {

return head->next  ==  head;

}    //返回1表示链表为空,0表示不空

3、在链表中增加一个结点

(内核代码中,函数名前加两个下划线表示内部函数)

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.h 中增加结点的两个函数为:

(链表是循环的,可以将任何结点传递给head,调用这个内部函数以分别在链表头和尾增加结点)

static inline void list_add(struct list_head *new, struct llist_head *head)

{

__list_add(new, head, head -> next) ;

}

static inline void list_add_tail(struct list_head 8new, struct list_head *head)

{

__list_add(new, head -> prev, head) ;

}

附:给head传递第一个结点,可以用来实现一个队列,传递最后一个结点,可以实现一个栈。

static 加在函数前,表示这个函数是静态函数,其实际上是对作用域的限制,指该函数作用域仅局限

于本文件。所以说,static 具有信息隐蔽的作用。而函数前加 inline 关键字的函数,叫内联函数,表

示编译程序在调用这个函数时,立即将该函数展开。

4、 遍历链表

list.h 中定义了如下遍历链表的宏:

#define   list_for_each(pos, head)    for(pos = (head)-> next ;  pos != (head) ;  pos = pos -> next)

这种遍历仅仅是找到一个个结点的当前位置,那如何通过pos获得起始结点的地址,从而可以引用结

点的域?list.h 中定义了 list_entry 宏:

#define   list_entry( ptr, type, member )  \

( (type *) ( (char *) (ptr)  - (unsigned long) ( &( (type *)0 )  ->  member ) ) )

分析:(unsigned long) ( &( (type *)0 )  ->  member ) 把 0 地址转化为 type 结构的指针,然后获取该

结构中 member 域的指针,也就是获得了 member 在type 结构中的偏移量。其中  (char *) (ptr) 求

出的是 ptr 的绝对地址,二者相减,于是得到 type 类型结构体的起始地址,即起始结点的地址。

5、链表的应用

一个用以创建、增加、删除和遍历一个双向链表的Linux内核模块

点击(此处)折叠或打开

#include

#include

#include

#include

MODULE_LICENCE("GPL");

MODULE_AUTHOR("LUOTAIJIA");

#define N 10

struct numlist {

int num;

struct list_head list;

};

struct numlist numhead;

static int __init doublelist_init(void)

{

//初始化头结点

struct numlist * listnode; //每次申请链表结点时所用的指针

struct list_head * pos;

struct numlist * p;

int i;

printk("doublelist is starting...\n");

INIT_LIST_HEAD(&numhead.list);

/*

* static inline void INIT_LIST_HEAD(struct list_head *list)

* {

* list->next = list;

* list->prev = list;

* }

*/

//建立N个结点,依次加入到链表当中

for (i=0; i

listnode = (struct numlist *)kmalloc(sizeof(struct numlist), GFP_KERNEL);

//void *kmalloc(size_t size, int flages)

//分配内存,size 要分配内存大小,flags 内存类型

listnode->num = i+1;

list_add_tail(&listnode->list, &numhead.list);

printk("Node %d has added to the doublelist...\n", i+1);

}

//遍历链表

i = 1;

list_for_each(pos, &numhead.list) {

p = list_entry(pos, struct numlist, list);

printk("Node %d's data: %d\n", i, p->num);

i++;

}

return 0;

}

static void __exit doublelist_exit(void)

{

struct list_head *pos, *n;

struct numlist *p;

int i;

//依次删除N个结点

i = 1;

list_for_each_safe(pos, n, &numhead.list) {

//为了安全删除结点而进行的遍历

list_del(pos); //从链表中删除当前结点

p = list_entry(pos, struct numlist, llist);

//得到当前数据结点的首地址,即指针

kfree(p); //释放该数据结点所占空间

printk("Node %d has removed from the doublelist...\n", i++);

}

printk("doublelist is exiting...\n");

}

module_init(doublelist_init);

module_exit(doublelist_exit);

参考资料:Linux操作系统原理与应用(第2版)    陈莉君、康华 编著

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/550560.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux共享内存示例,linux 进程间共享内存示例

写入端:#include #include #include #include #include using namespace std;struct MappingDataType {int mappingData;};bool SetUsedPID(string mappingName){void *shm NULL;MappingDataType *shared;int shmid shmget((key_t), sizeof(MappingDataType), |IP…

Linux使用cmake编译项目,如何使用cmake在linux中构建Qt项目(How to build Qt project in linux with cmake)...

如何使用cmake在linux中构建Qt项目(How to build Qt project in linux with cmake)我使用的是ubuntu 14.04,cmake 2.8.12.2,Qt5.6.2(内置版本),GNU make 3.81用cmake PathToSource -G "Eclipse CDT4 - Unix Makefiles"运行cmake之后…

linux cmake 编译项目,使用CMake构建复杂工程

0. 什么是CMakeCMake是一个跨平台的编译、安装、测试以及打包工具;CMake不直接编译软件,而是结合原生构建系统来构建软件。CMake配置文件是CMakeList.txt文件(每个源码文件夹下都要有一个),CMake根据配置文件在生成Unix的Makefile或VS的solut…

Linux防火墙屏蔽ip6,观点|Linux 发行版们应该禁用 IPv4 映射的 IPv6 地址吗?

从各方面来看,互联网向 IPv6 的过渡是件很缓慢的事情。不过在最近几年,可能是由于 IPv4 地址资源的枯竭,IPv6 的使用处于上升态势。相应的,开发者也有兴趣确保软件能在 IPv4 和 IPv6 下工作。但是,正如近期 OpenBSD 邮…

linux db2 权限管理,DB2五种管理权限

DB2五种管理权限SYSADM, SYSCTRL SYSMAINT DBADM and LOAD前三个权限是instance-level,and can only be assigned to a group and are done so through the Database Manager Configuration file.后两个权限是database-level,are assigned to a user or group for …

boost 线程 linux,Boost Linux线程第一课

#include#includevoid ThreadFunc(){std::cout<}int main(){boost::thread thrd1(&ThreadFunc);thrd1.join();return 0;}编译指令 g test.cpp -lboost_thread注意&#xff1a;没有链接boost_thread&#xff0c;出错提示如下&#xff1a;undefined reference to boo…

linux 链接文件 通配符,linux globbing文件通配符

在linux中使用ls、cp、mv、rm等命令时可以使用文件通配符匹配操作多个文件。匹配模式*&#xff1a;匹配任意长度的任意字符?&#xff1a;匹配任意单个字符[]&#xff1a;匹配指定范围内的任意单个字符(文件通配不区分字母的大小写)[^]&#xff1a;匹配非制定范围内的任意单个字…

linux 升级centos7,Linux之从Centos 6.x 升级Centos7

1、安装升级工具依赖的软件包yum -y install openscap pcre-devel libxml2-devel libxslt-devel m2crypto python-simplejson mod_wsgi2、安装以下软件的最新版&#xff0c;可以到这里查找&#xff1a;http://dev.centos.org/centos/6/upg/x86_64/Packagesrpm -ihv http://dev.…

linux和pe修复win10启动项,pe下如何重建win10引导?pe下win10引导修复图文教程

[文章导读] 随着win10系统的流行&#xff0c;越来越多的小伙伴经常遇到win10系统引导丢失的情况&#xff0c;我们知道win10系统现在采用的是uefi引导&#xff0c;以前的一些修复工具都只能修复传统模式mbr格式下的硬引导&#xff0c;但对于uefi引导不是很清楚&#xff0c;uefi引…

linux下实现定时器,在Linux操作系统下实现定时器简介

在Linux实现一个定时器&#xff0c;不像Win32下那样直观。在Win32调用SetTimer就行了&#xff0c;在Linux下则没有相应函数可以直接调用。定时器作为一个常用的功能&#xff0c;在Linux当然也有相应实现。下面我们看看几种常用的方法。要实现定时器功能&#xff0c;最土的办法实…

c语言课程设计大作业模版,c语言课程设计报告模板下载

c语言课程设计报告模板是一款专业的设计模板&#xff0c;对于在大学有需要些设计报告的朋友&#xff0c;可以下载这款模板作为参考&#xff0c;了解设计报告的需求&#xff0c;基本上毕业的论文设计也是在这个基础上严格要求的&#xff0c;欢迎下载使用。C语言介绍C语言是一门面…

c语言error和,C语言ERROR精选.doc

C语言ERROR精选Ambiguous operators need parentheses ) ~. [1 L: f& a/ J不明确的运算需要用括号括起 # n5 J! G c( m: ! o& \( P. CAmbiguous symbol xxx - n# d??i/ t0 K8 M不明确的符号 6 r% o0 \- N! _2 UArgument list syntax error % l, j/ O9 \; x1 j1 e参数…

c语言如何把变量按位颠倒,求答案,用C语言编程,用户输入一个正整数,把他的各位数字前后颠倒,并输入点到后的结果...

满意答案q15173278975推荐于 2017.11.26采纳率&#xff1a;58% 等级&#xff1a;13已帮助&#xff1a;5665人用字符串处理很简单#include #include void main (){int n,i;char s[20];scanf("%d", &n);sprintf(s,"%d", n);printf("%d\n",s…

中南大学12月13日考c语言,中南大学2010级C语言试卷

中南大学考试试卷2010 -- 2011 学年 1 学期 时间110分钟学时学分 考试形式&#xff1a;班级 学号 姓名 总分100分,占总评成绩70 %一、选择题(每小题1.5分,共计30分)1. C语言中变量定义与使用的关系是 。A) 必须先定义&#xff0c;后使用 B)可以先使用&#xff0c;后定义 C) 可以…

c语言123报数,新人求解一道C语言题。。。麻烦了

有一百个人按编号排成一队&#xff0c;从1开始按123123报数&#xff0c;报3者退出&#xff0c;直到队尾&#xff0c;又从队尾向队首报数(1开始)&#xff0c;依旧报3的退出&#xff0c;重复执行直至队列剩2个&#xff0c;求此2人的原始编号&#xff0c;这是题目&#xff0c;下面…

素数 c语言 时间少,C语言判断素数怎么优化时间,1000000以内,不用代码,指点一下就好...

匿名用户1级2016-09-04 回答基本思想用筛法求素数的基本思想是&#xff1a;把从1开始的、某一范围内的正整数从小到大顺序排列&#xff0c; 1不是素数&#xff0c;首先把它筛掉。剩下的数中选择最小的数是素数&#xff0c;然后去掉它的倍数。依次类推&#xff0c;直到筛子为空时…

android activity动态显示不出来,uiautomatorviewer 获取不到动态页面解决办法

以前玩 PC 最近刚搞 app 测试&#xff0c;费好大劲环境装好&#xff0c;高兴的点击 uiautomatorviewer.bat 想去抓取页面元素&#xff0c;尴尬的是首页就直接报错。Error while obtaining UI hierarchy XML file: com.android.ddmlib.SyncException: Remote object doesnt exis…

谷歌tts android手机自带引擎,Android使用讯飞语记引擎实现中文TTS

1.首先去讯飞语记官网下载并安装APP&#xff1a;2.设置语音引擎&#xff1a;设置>语言和输入法>文字转语音(TTS)输出>首选引擎3.在代码中使用&#xff1a;import android.content.Context;import android.speech.tts.TextToSpeech;import android.util.Log;import jav…

android xml 画下划线,android – strings.xml:如何从标记前面的空格中删除下划线?...

我的strings.xml中有以下行&#xff1a;This is a test在我的活动xml中,我在TextView中引用了这个字符串&#xff1a;android:layout_width"wrap_content"android:layout_height"wrap_content"android:text"string/test_string" />奇怪的是,当…

android开发基本知识,Android应用开发基本知识点汇总

Activity一生命周期4种状态running/paused/stopped/killed生命周期Activity发动onCreate->onStart->onResume点Home回来主界面onPause->onStop再次回到原ActivityonRestart->onStart->onResume退出ActivityonPause->onStop->onDestroy进程优先级前台&…