1.前言

本文主要介绍Linux内核实现的基本数据类型,包括链表,内核对象,内核对象引用计数,内核对象集合,

2.链表

1. 链表的基本结构

内核链表可以将任何类型的数据结构连接起来,链表结构如下:

 struct list_head {
struct list_head *next, *prev;
};

图 标准双链表

典型的循环双向链表如上图所示。

2. 链表相关API

LIST_HEAD(list_name) 定义一个list_head结构体,next和pre成员均初始化为当前新创建的list_head

list_add(new,head) 用于head元素之后紧接着插入new元素

list_add_tail(new,head) 在head元素前面插入new元素,由于是循环链表,实际是将new元素插入到末尾

list_del(entry) 从链表中删除一项 

list_empty(head) 检查链表是否为空

list_splice(list, head) 合并两个链表,把list插入到另一个链表head的后面

list_entry(ptr, tpe, member) ptr是某数据结构中指向list_head成员的指针,type是该数据结构的类型,member是该数据结构中list_head成员变量名

list_for_each(pos, head) 用于遍历链表的所有元素。pos表示链表的当前位置,head指定了表头

3. 内核对象

3.1 kobject

1. kobject的基本结构

 struct kobject {
const char *name; /*kobject的名字*/
struct list_head entry;/*用于将kobject放置到一个链表中*/
struct kobject *parent;/*指向当前kobject的父对象,用于建立层次结构*/
struct kset *kset; /*用于将对象与其他对象放到一个集合中*/
struct kobj_type *ktype; /*提供了kobject的更多属性,最重要的是释放该数据结构资源的析构器函数*/
struct kernfs_node *sd; /* sysfs directory entry */
struct kref kref; /*用于简化引用计数*/
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
struct delayed_work release;
#endif
unsigned int state_initialized:;
unsigned int state_in_sysfs:;
unsigned int state_add_uevent_sent:;
unsigned int state_remove_uevent_sent:;
unsigned int uevent_suppress:;
};

注:kobject不是通过指针与其他数据结构连接,而必须直接嵌入到其他数据结构中,这样通过管理kobject达到了包含kobject对象的管理。由于kobject会嵌入到许多数据结构中,因此要保持kobject结构较小。

2. kobject的API

struct kobject *kobject_get(struct kobject *kobj) 增加kobject的引用计数

void kobject_put(struct kobject *kobj) 减少kobject的引用计数

void kobject_init(struct kobject *kobj, struct kobj_type *ktype) 初始化kobject结构体,即将引用计数设为0,并初始化kobject的链表成员

int kobject_add(struct kobject *kobj, struct kobject *parent, 将kobject加入sysfs中显示
const char *fmt, ...) int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype, struct kobject *parent, const char *fmt, ...) kobject_init和kobject_add的合并操作 struct kobject *kobject_create(void) 为一个kobject分配空间,并调用kobject_init初始化 struct kobject *kobject_create_and_add(const char *name, struct kobject *parent) kobject_create和kobject_add的合并操作 static void kobject_cleanup(struct kobject *kobj) 在不需要kobject(以及包含kobject的对象)时释放kobject占用的资源

3.2 kref

1.kref结构体

引用计数用来检测内核中有多少地方使用了某个对象,当内核一个部分包含某个对象的信息时,需要将该对象对应kobject的kref加1,不需要时则减1,如果减为0则释放该对象

 struct kref {
atomic_t refcount; /*原子计数,给出内核中当期使用某个对象的计数,在计数为0时,kobject就可以从内存中删除了*/
};

2.kref的API

static inline void kref_init(struct kref *kref) 初始化kref,即将refcount初始化为1

static inline void kref_get(struct kref *kref)  要使用某个对象必须将对应的kobject的引用计数加1

static inline int kref_sub(struct kref *kref, unsigned int count,
void (*release)(struct kref *kref)) 对象不在使用则将对应的kref减1,如果引用计数为0则调用release释放kobject

3.3 kset

kset是kobject应用的第一个例子,因此它是用kobject 进行管理的,它与kset中包含的各个kobject无关,此处的kobject只是纯粹为了管理kset之需

 struct kset {
struct list_head list; /*用于链接当前kset中所有的kobject的链表*/
spinlock_t list_lock;
struct kobject kobj;
const struct kset_uevent_ops *uevent_ops; /*提供了若干函数指针,用于将kset的相关信息透给应用层*/
};

3.4 ktype

 struct kobj_type {
void (*release)(struct kobject *kobj);
const struct sysfs_ops *sysfs_ops;
struct attribute **default_attrs;
const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
const void *(*namespace)(struct kobject *kobj);
};

注:ktype与kset没有关系,kset已经提供了集合功能,ktype提供了与sysfs文件系统相关的接口。如果多个kobject导出类似的信息,则可以共享一个ktype提供所需要的方法

4.  数据类型

  • 数据类型定义

typedef  为避免依赖体系结构的相关特性,如sector_t, pid_t等

  • 字节序

cpu_to_le64 将64位数据类型转换为小端序格式

le64_to_cpu 将64位小端序格式转换为64位cpu端格式

  • per-cpu变量

可有效避免多处理器并发访问同个变量引发的并发问题

DEFINE_PER_CPU(name, type) name是变量名, type是数据类型

get_cpu(name, cpu) 获取当前cpu上创建的变量实例

smp_processor_id() 返回当前 cpu 的id

  • 访问用户空间

__user 使用此标记来标识指向用户空间的指针

5. 参考文档

[1] 深入Linux内核架构(PLKA)

Linux内核基础设施的更多相关文章

  1. Linux内核的总结认识

    转载博文: http://www.linuxdiyf.com/linux/11234.html 1.内核是怎样实现其管理的职能? 以前在学校时一直不能理解内核是怎么做管理?比如内核如何知道在什么时候对 ...

  2. KSM剖析——Linux 内核中的内存去耦合

    简介: 作为一个系统管理程序(hypervisor),Linux® 有几个创新,2.6.32 内核中一个有趣的变化是 KSM(Kernel Samepage Merging)  允许这个系统管理程序通 ...

  3. 现在的 Linux 内核和 Linux 2.6 的内核有多大区别?

    作者:larmbr宇链接:https://www.zhihu.com/question/35484429/answer/62964898来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转 ...

  4. 2019-2020-9 20199317 《Linux内核原理与分析》第九周作业

    第8章  进程的切换和系统的一般执行过程 1  进程调度的时机 1.1  硬终端与软中断 进程调度的时机都与中断相关,中断有很多种,都是程序执行过程中的强制性转移,转移到操作系统内核相应的处理程序.中 ...

  5. Linux内核调试的方式以及工具集锦【转】

    转自:https://blog.csdn.net/gatieme/article/details/68948080 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原 ...

  6. Linux内核调试的方式以及工具集锦

    原文:https://blog.csdn.net/gatieme/article/details/68948080 CSDN GitHubLinux内核调试的方式以及工具集锦 LDD-LinuxDev ...

  7. 探索Linux内核:Kconfig / kbuild的秘密

    探索Linux内核:Kconfig / kbuild的秘密 文章目录 探索Linux内核:Kconfig / kbuild的秘密 深入了解Linux配置/构建系统的工作原理 Kconfig kbuil ...

  8. Linux内核学习之工作队列

    Author       : Toney Email         : vip_13031075266@163.com Date          : 2020.12.02 Copyright : ...

  9. Linux 内核概述 - Linux Kernel

    Linux 内核学习笔记整理. Unix unix 已有40历史,但计算机科学家仍认为其是现存操作系统中最大和最优秀的系统,它已成为一种传奇的存在,历经时间的考验却依然声名不坠. 1973 年,在用 ...

随机推荐

  1. BZOJ 4032: [HEOI2015]最短不公共子串

    4032: [HEOI2015]最短不公共子串 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 446  Solved: 224[Submit][Sta ...

  2. codeforces 793B - Igor and his way to work(dfs、bfs)

    题目链接:http://codeforces.com/problemset/problem/793/B 题目大意:告诉你起点和终点,要求你在只能转弯两次的情况下能不能到达终点.能就输出“YES”,不能 ...

  3. Android DownloadManager 的使用

    分类: android 技巧2013-05-28 10:32 3278人阅读 评论(1) 收藏 举报   目录(?)[+]   从Android 2.3(API level 9)开始Android用系 ...

  4. HDU 3081 Marriage Match II (二分图,并查集)

    HDU 3081 Marriage Match II (二分图,并查集) Description Presumably, you all have known the question of stab ...

  5. HDU 5608 - function

    HDU 5608 - function 套路题 图片来自: https://blog.csdn.net/V5ZSQ/article/details/52116285 杜教筛思想,根号递归下去. 先搞出 ...

  6. A1019. General Palindromic Number

    A number that will be the same when it is written forwards or backwards is known as a Palindromic Nu ...

  7. Activiti 用户任务并行动态多实例(多用户执行流程)

    在很多情况下,我们需要多用户共同执行余下流程,比如开会流程: 领导发起开会,选择开会人员(多个) 每个开会人员接收到通知后需要签到(一名用户签到不会影响到另一位用户的签到) 签到完成后则流程结束 如果 ...

  8. 20190417 Spring Security

    参考资料 Spring-Security的4.2.12版本官方文档 Spring Security简介

  9. mysql 8.0.12 创建新的数据库、用户并授权

    Mysql安装成功后,默认的root用户密码为空,你可以使用以下命令来创建root用户的密码: [root@host]# mysqladmin -u root password "new_p ...

  10. JavaSE学习总结(二)——Java语言基础

    一.Java程序预览 Java的语法与C非常类似,这里先使用几个非常简单的程序以点带面来区分C语Java的区分再细讲每个知识点.该文仅针对有编程基础的朋友参考. 1.1.Hello World 创建j ...