Linuxs是单内核
宏内核:把所有东西都集成到内核里,优点:高效 缺点:稳定性差
微内核:内核中只有基本的调度,内存管理等,其他的都是作为用户态守护进程进行运行,模块化程度高,优点:超级稳定 可以kill掉驱动进程 缺点:效率低,进程间同喜消耗资源
Linux是单内核结构:吸收了微内核的优点可以进行模块化设计,支持动态加载内核模块,同时吸收了宏内核的优点把关键模块集中在内核中比较高效
Linux内核编程例子
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
static int __init lkp_init(void);
static int __exit lkp_exit(void);
static int __init lkp_init(void)
{
printk("<1>Hello ,Word!\n");
return 0;
}
static int __exit lkp_exit(void)
{
printk("<2>Hello,Word exit\n");
}
module_init(lkp_init);
module_exit(lkp_exit);
首先是这个init与exit前面不是一个下划线,而是两个下划线。
而且要注意print后跟的是k,不可以习惯性的打成f了。
Makefile编写
obj-m += test.o
CURRENT_PATH:=$(shell pwd)
LINUX_KERNEL:=$(shell uname -r)
LINUX_KERNEL_PATH := /usr/src/kernels/$(LINUX_KERNEL)
all:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
clean:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean
这里共有四处是要特别注意的,比较容易犯错的地方。而且如果没有注意到的同学往往自己检查起来也很难查到出错的原因。
首先,obj与-m中间没有空格。
其次,右上角的框框里是你的模块程序的名字后加.o。比如我这里模块程序的名字叫test.c,于是我这里是test.o
接下来,两个make的前面是一个TAB键,绝对不可以使用其他比如空格之类的来在形式上进行替代。
最后,$符号前面与M=之间没有空格,必须紧密相连。
双链表是Linux中的基础数据结构,但是是做了一个list_head的结构体嵌入在各个数据结构中,一开始初始化时next,prev都是指向自己
可以使用list_empty来判断链表是非为空 true为空 false为有内容
链表头部插入形成一个栈,尾部插入形成一个队列,static有信息隐藏的作用,只能在本文件中使用
先看&((type *)0)->member:
把“0”强制转化为指针类型,则该指针一定指向“0”(数据段基址)。因为指针是“type *”型的,所以可取到以“0”为基地址的一个type型变量member域的地址。那么这个地址也就等于member域到结构体基地址的偏移字节数。简单说就是从地址0形成一个type型的结构体指针,找到对应member的地址就是偏移量再来看 ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))):
(char *)(ptr)使得指针的加减操作步长为一字节,(unsigned long)(&((type *)0)->member)等于ptr指向的member到该member所在结构体基地址的偏移字节数。二者一减便得出该结构体的地址。转换为 (type *)型的指针,大功告成。简单说结构体都是放在栈中ptr要比entry的地址大,往上增长
hlist是linux内核中关键的数据结构
时间复杂度O(1)下查到数据
解决哈希冲突的三种方法: 开放寻址法 再散列法 链地址法