1、什么是引用计数器
如果我们写了一个字符驱动,当硬件设备插上时,系统会生成一个设备节点。用户在应用空间操作这个设备节点就可以操作设备。如果此时将硬件断开,驱动是不是就要立刻释放呢?如果立刻释放,应用程序是不是就崩溃了呢。所以要等应用程序关闭,再去释放驱动。
在Linux系统中是通过引用计数来实现的。比如用kref这个变量记录某个驱动或者某块内存的引用计数。初始值为1,每引用一次+1,每取消一次-1,当计数值为0的时候,自动调用自定义的释放函数释放驱动或者内存。
2、相关结构体和api介绍
2.1 struct kref
2.2 kref_init
初始化kref的值为1
2.3 kref_get
计数值加1
2.4 kref_put
kref的计数值减1,当减到0时,会调用release函数执行释放的操作
3、kref实验
#include<linux/module.h>
#include<linux/init.h>
#include<linux/kernel.h>
#include<linux/kobject.h>
#include<linux/slab.h>
struct kobject *my_kobject01;
struct kobject *my_kobject02;
struct kobject *my_kobject03;
struct kobj_type mytype;
static int my_kobject_init(void)
{
int ret;
my_kobject01 = kobject_create_and_add("my_kobject01",NULL); // /sys/my_kobject01
printk("my_kobject01 kref = %d\n",my_kobject01->kref.refcount.refs.counter);
my_kobject02 = kobject_create_and_add("my_kobject02",my_kobject01); // /sys/my_kobject01/my_kobject02
printk("my_kobject01 kref = %d\n",my_kobject01->kref.refcount.refs.counter);
printk("my_kobject02 kref = %d\n",my_kobject02->kref.refcount.refs.counter);
my_kobject03 = kzalloc(sizeof(struct kobject),GFP_KERNEL);
ret = kobject_init_and_add(my_kobject03,&mytype,NULL,"%s","my_kobject03");
printk("my_kobject03 kref = %d\n",my_kobject03->kref.refcount.refs.counter);
return 0;
}
static void my_kobject_exit(void)
{
printk("my_kobject01 kref = %d\n",my_kobject01->kref.refcount.refs.counter);
printk("my_kobject02 kref = %d\n",my_kobject02->kref.refcount.refs.counter);
printk("my_kobject03 kref = %d\n",my_kobject03->kref.refcount.refs.counter);
kobject_put(my_kobject01);
printk("my_kobject01 kref = %d\n",my_kobject01->kref.refcount.refs.counter);
printk("my_kobject02 kref = %d\n",my_kobject02->kref.refcount.refs.counter);
printk("my_kobject03 kref = %d\n",my_kobject03->kref.refcount.refs.counter);
kobject_put(my_kobject02);
printk("my_kobject01 kref = %d\n",my_kobject01->kref.refcount.refs.counter);
printk("my_kobject02 kref = %d\n",my_kobject02->kref.refcount.refs.counter);
printk("my_kobject03 kref = %d\n",my_kobject03->kref.refcount.refs.counter);
kobject_put(my_kobject03);
printk("my_kobject01 kref = %d\n",my_kobject01->kref.refcount.refs.counter);
printk("my_kobject02 kref = %d\n",my_kobject02->kref.refcount.refs.counter);
printk("my_kobject03 kref = %d\n",my_kobject03->kref.refcount.refs.counter);
}
module_init(my_kobject_init);
module_exit(my_kobject_exit);
MODULE_LICENSE("GPL");
obj-m += kref.o
KDIR := /home/johan/share/rk3588/linux_sdk/kernel
PWD ?= $(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules
clean:
rm -f *.ko *.o *mod* *.mod.c modules* Module*