嵌入式 linux中kernel代码/lib/klist.c文件分析

2024-01-05 11:58

本文主要是介绍嵌入式 linux中kernel代码/lib/klist.c文件分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

小结:

 

下面这个图应该能说明全部问题


函数列表:

 

void       klist_init

初始化klist,主要操作是挂空k->k_list,初始化k_lock锁,挂上get和put函数

 

void       klist_add_head(struct klist_node * n,   struct klist * k)

void       klist_add_tail(struct klist_node * n, struct klist * k)

初始化node链表并将其挂到klist链表的表首

 

void       klist_del(struct klist_node     * n)

从klist中删除指定的node节点,如果该节点不是klist中最后一个节点,则执行init时指定的put函数

 

void       klist_remove(struct klist_node      * n)

这个函数实际是调用了klist_del函数,只是多了一步wait_for_completion,而该信号的completion操作则是在klist_release函数中发出,klist_release的调用在klist_del中执行

 

//容器模块

void       klist_iter_init_node

void       klist_iter_init(struct klist * k,       struct klist_iter * i)

容器的初始化,具体操作是关联上klist,klist->head(node链表),将node设置为当前节点。

klist_iter_init的操作只是调用klist_iter_init_node(k, I, NULL)

 

void       klist_iter_exit(struct klist_iter      * i)

容器的当前node节点存在,则从klist中删除当前node节点(klist_del),并将当前节点挂空

从这个函数的操作,我们可以推测一下,容器实际是对klist中指定的一个节点进行操作

 

struct      klist_node      * klist_next(struct klist_iter * i)

从klist的node链表中找到下一个节点,挂到容器i->cur上,并执行之前i->cur指向的节点的klist->put函数,最后返回刚找到的下一个节点。

klist模型大概如下:

klist->node挂载着很多node链表,而每一个node链表下又挂载着很多node子链表,klist_next有一个分支操作就是当一个node链表的所有子node都找完后,就会从klist->node链表的下一个链表开始找新的node

结构体说明:

 

struct      klist {

       spinlock_t              k_lock;

       struct list_head       k_list;                   //挂载klist_node结构体

       void               (*get)(struct klist_node *);

       void               (*put)(struct klist_node *);

};

 

struct      klist_node {

       struct klist             * n_klist;

       struct list_head       n_node;

       struct kref              n_ref;                    //引用计数

       struct completion    n_removed;

};

//klist的初始化操作

void       klist_init(

       struct klist      * k,

       void (*get)(struct klist_node *),

       void (*put)(struct klist_node *))

{

       INIT_LIST_HEAD(&k->k_list);          //链表挂空

       spin_lock_init(&k->k_lock);               //自旋锁

       k->get = get;

       k->put = put;                                     //关联引用和释放计数函数

}

 

EXPORT_SYMBOL_GPL(klist_init);

//将n->node挂到k->k_list的表首

static      void       add_head(struct klist * k,      struct klist_node * n)

{

       list_add(&n->n_node,   &k->k_list);

       //__list_add(&n->n_node,    &k->k_list,    &k->k_list ->next);

}

 

//将n->node挂到k->list的表尾

static      void       add_tail(struct klist * k,        struct klist_node * n)

{

       list_add_tail(&n->n_node, &k->k_list);

}

 

//node的初始化,也就是n->node,即k->list的成员

static      void       klist_node_init(struct klist * k,     struct klist_node * n)

{

       INIT_LIST_HEAD(&n->n_node);                     //node链表挂空

       init_completion(&n->n_removed);                     //初始化等待队列

       kref_init(&n->n_ref);                                //初始化计数

       n->n_klist = k;                                                 //关联上klist,也可以理解为父设备

       if (k->get)                                                //父设备的引用加1

              k->get(n);

}


//将node链表初始化并挂到list链表的表首

void       klist_add_head(struct klist_node * n,   struct klist * k)

{

       klist_node_init(k, n);            //初始化node节点

       add_head(k, n);                    //node加入klist中

}

 

//将node链表初始化并挂到list链表的表尾

void       klist_add_tail(struct klist_node * n, struct klist * k)

{

       klist_node_init(k, n);

       add_tail(k, n);

}


//释放kref成员所在结构体在klist上的链接

static      void       klist_release(struct kref * kref)

{

       //通过kref获取该成员的结构体宿主

       struct klist_node    * n = container_of(kref,       struct klist_node,   n_ref);

 

       list_del(&n->n_node);                 //将node链表从他所在的链表中断开

       complete(&n->n_removed);         //释放等待队列

       n->n_klist = NULL;                     //将node结构体的父设备挂空

}

 

//将n->n_ref计数减1,并调用klist_release函数

static      int   klist_dec_and_del(struct klist_node      * n)

{

       return     kref_put(&n->n_ref,     klist_release);

}


//从klist中删除指定的node节点,并调用初始化时指定的put函数

//如果是最后一个节点则不再调用put函数

void       klist_del(struct klist_node     * n)

{

       struct klist * k = n->n_klist;                       //获取node的父klist设备

       void (*put)(struct klist_node *) = k->put;    //获取klist的put函数

 

       spin_lock(&k->k_lock);

       if (!klist_dec_and_del(n))      put = NULL;   //从klist中删除本node节点,如果这是klist的最后一个节点,则put函数挂空

       spin_unlock(&k->k_lock);

       if (put)

              put(n);           //执行put函数,参数为已经删除的节点

}


//移除node节点

void       klist_remove(struct klist_node      * n)

{

       klist_del(n);           //这个函数的实现就在上面

       wait_for_completion(&n->n_removed);             

       //等待completion信号,该信号在klist_release函数中发出

}


//探测指定node的父设备是否指定,没指定就返回1,指定就返回0

int   klist_node_attached(struct klist_node   * n)

{

       return (n->n_klist != NULL);

}


//初始化容器

void       klist_iter_init_node(

       struct klist             * k,               //klist链表

       struct klist_iter      * i,                //容器

       struct klist_node    * n)               //node链表

{

       i->i_klist = k;

       i->i_head = &k->k_list;               //klist的node链表

       i->i_cur = n;

 

       if (n)             

              kref_get(&n->n_ref);            //node节点存在,则节点的引用计数加1

}

 

//容器的初始化,node为NULL

void       klist_iter_init(struct klist * k,       struct klist_iter * i)

{

       klist_iter_init_node(k, i, NULL);

}


//容器的退出

void       klist_iter_exit(struct klist_iter      * i)

{

       //容器的当前node节点存在,则从klist中删除当前node节点,并将当前节点挂空

       if (i->i_cur) {

              klist_del(i->i_cur);

              i->i_cur = NULL;

       }

}


//根据成员返回klist_node宿主

static      struct klist_node    * to_klist_node(struct list_head * n)

{

       return     container_of(n,      struct klist_node,   n_node);

}


struct      klist_node      * klist_next(struct klist_iter * i)

{

       struct list_head      * next;

       struct klist_node    * lnode = i->i_cur;        //当前操作的节点

       struct klist_node    * knode = NULL;

       void (*put)(struct klist_node *) = i->i_klist->put;       //父klist链表中的put函数

 

       spin_lock(&i->i_klist->k_lock);

 

       //当前操作节点存在

       if (lnode) {

              next = lnode->n_node.next;                 //获取当前节点的下一个节点

              if (!klist_dec_and_del(lnode))              //删除当前节点

                     put = NULL;

       }

       //当前操作节点不存在,下一个接是klist->node链表的下一个node链表

       else

              next = i->i_head->next;

 

       //下一个节点不是klist->node的链表头

       if (next != i->i_head) {

              knode = to_klist_node(next);               //取出节点

              kref_get(&knode->n_ref);                   //引用计数

       }

 

       i->i_cur = knode;                                      //容器的当前节点修改为找到的下一个节点

       spin_unlock(&i->i_klist->k_lock);

 

       if (put && lnode)

              put(lnode);                                        //执行之前节点的put函数

 

       //返回找到的下一个节点

       return     knode;

}

这篇关于嵌入式 linux中kernel代码/lib/klist.c文件分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/572789

相关文章

linux-基础知识3

打包和压缩 zip 安装zip软件包 yum -y install zip unzip 压缩打包命令: zip -q -r -d -u 压缩包文件名 目录和文件名列表 -q:不显示命令执行过程-r:递归处理,打包各级子目录和文件-u:把文件增加/替换到压缩包中-d:从压缩包中删除指定的文件 解压:unzip 压缩包名 打包文件 把压缩包从服务器下载到本地 把压缩包上传到服务器(zip

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能