第一章 概述
1.1Linux操作系统概述
操作系统:
1 对整个计算机系统的软硬件资源进行管理
2为用户提供服务
对应的,
操作系统设计目标:
1 提高资源利用率
2 方便用户使用
Linux系统整体结构
LINUX设计理念
机制与策略分离
机制-提供什么样功能
策略-如何使用这些功能
隔离变化-系统调用机制
系统调用机制在应用程序和操作系统内核之间起到接口的作用。
操作系统内核做大量繁杂事情,应用程序开发时候只需要调用系统调用的接口。
1.2 Linux内核结构以及内核模块的编程
单内核与微内核
单内核:操作系统各个子系统(如文件系统、内存管理、进程管理、网络系统、进程通信),他们之间可以互相直接调用。
特点:由于各个子系统之间可以直接调用,所以性能比较高,可维护性比较差
微内核:只有核心的进程间通信中断以及调用程序放在微内核,其他的如文件系统以服务器形式放在外面。
特点: 因为与服务器之间是一种通信的关系,比如说当要发出一个请求的时候,文件系统可能要与微内核进行通信,通信是有代价的,所以微内核效率比较低。但是因为这种架构,各个服务器之间相对独立,可维护性比较好。
Linux是单内核
可加载的Linux内核模块
用的时候加载,不用的时候卸载。
printk函数
入口和出口函数
module_init 用来调用初始化函数
__init告诉编译程序,当这个模块执行完后把内存空间回收
Makefile文件:
下图为ubantu系统下的Makefile,包括模块当前路径、linux内核源代码的当前版本、linux内核源代码的绝对路径
模块插入命令和删除命令:
linux内核模块和C的对比
1.3 内核源码中的双链表结构
对于双链表:减少一个指针域→退化为单链表
只对链表的首尾进行插入或者删除操作→队列结构
只对链表的头进行插入或删除操作→栈结构
如果前驱和后继表示左右孩子→二叉树结构
链表的声明和初始化
链表的插入
static加在函数前表示这个函数是静态函数
静态函数:对函数作用域的一种限制,函数作用域仅限于本文件。
static具有信息隐藏的作用。
inline关键字加在函数前说明这个函数对编译程序可见,编译程序在调用这个函数的时候立即展开这个函数。
如何遍历一个双链表:
1 linux内核开了一个宏,让指针不断往下走,当头尾相遇,遍历结束。
这种方法只找到一个节点在链表中的偏移位置
如何通过这个偏移获得节点的起始位置,从而引用节点中的各个域?
linux定义了list_entry宏,ptr指针代表成员member所在的位置,type代表结构体类型,member是结构体的一个成员。
通过这个宏可以获得节点的起始地址
宏的外边是几个强制类型转换,宏的里面是一个减法操作,绝对值减去偏移量得到节点的起始地址。
绝对值:将ptr强制转换成一个char类型,实际上就是指针的绝对位置。
member的偏移量:member前面强制转换成0,从0开始求位置。
二者相减得到节点的起始地址。
1.4 内核中哈希表源码分析
哈希表
哈希函数:将关键字和其存储位置之间建立起映射关系
通过哈希函数可以实现在时间复杂度O(1)下查找数据
哈希冲突:两个相同关键字经过哈希函数的运算后具有同样的哈希地址,如果不做特别处理,两个不同的关键字将会被存储在同一个位置上
如何解决哈希表的冲突?
开放寻址法、再散列法、链地址法
链地址法
基本思想:将具有相同哈希地址的记录链成一个链表,用一个数组将M个链表的头结点存储起来,形成一个动态的结构
hlist:一种链表结构,专门用于实现哈希表中的链地址法
有一个指向第一个链表体结构的first指针
包含一个指向后继节点的next指针,特别的是还包含一个二级指针pprv
哈希表中删除一个节点
补充:二级指针
一级指针:指向的是某个变量,一级指针存储的是某个变量的地址。
二级指针:指向指针的指针,二级指针中存储的是某个一级指针的地址。
下图中A是二级指针,B是一级指针,C是一个变量