【内核机制】kref 引用计数

一、kref 简介

  kref 是一个引用计数器,它在使用时通常会嵌套在其它结构体中,用于记录所嵌套结构体的引用计数,并在计数清零时调用相应的 release 函数。简而言之,kref 的创建主要是为了跟踪复杂情况下的结构引用销毁情况。
  单从内核源码实现来说,kref 的设计是非常简单的,其目的是为了能灵活地运用在各种结构的生命周期管理中。

二、内核函数

一、操作函数
1、kref 数据结构
  可以看到,kref 的结构体中包含了一个 refcount_t 类型,也就是 atomic_t 类型的计数值。atomic_t 是原子操作,操作时有专用的 API 函数,它在一定程度上可以解决内核的并发和竞态问题,省去额外加锁去锁的过程。(include/linux/kref.h)

struct kref {
    atomic_t refcount; /* @refcount: 引用计数 */
};

2.refcount_t 数据结构

typedef struct refcount_struct {
    atomic_t refs;
} refcount_t;

3.操作函数
  kref 相关的代码实现主要在 include/linux/kref.h 中。
在这里插入图片描述

三、kref 使用

1.添加 kref 数据结构
  对于那些用在各种场合并且被随处传递的对象,你如果没有使用引用计数,那么你的代码很可能存在问题。当然,如果你想要使用引用计数,那么 kref 会是一个不错的选择。你可以使用下述的方式将 kref 添加到你的数据结构中:

struct my_data {
        struct kref kref;
        ...
};

  kref 可以出现在数据结构的任意位置。
2. kref 初始化
  在申请分配 kref 后,你必须对 kref 进行初始化:

struct my_data *data;
data = kmalloc(sizeof(*data), GFP_KERNEL);
if (!data) 
        return -ENOMEM;
kref_init(&data->kref);

  此时会将 kref 的引用计数值设置为1。
3. kref 使用规则
初始化 kref 后,你必须遵循以下规则:
a. 如果你创建了一个非临时的指针,特别是它可能会被传递给另一个线程执行,你必须在传递该指针前执行 kref_get()

kref_get(&data->kref);

如果你已经有一个指向 kref 的合法指针,也就是说引用计数值不会变成0。那么你在执行上述操作的时候可以不用加锁。
b. 当你使用完这个指针时,你必须调用kref_put()

kref_put(&data->kref, data_release);

如果这个指针是某个对象最后的引用,那么相应的 release 函数就会被调用。 如果代码不会在没有拥有合法指针的情况下去获得一个合法的指针,那么在 kref_put() 时就不需要加锁。
c. 如果代码试图在没有拥有引用计数的情况下就调用 kref_get() ,那么必须串行化 kref_get() 和 kref_put() 的执行。因为很可能在 kref_get() 执行之前或者执行过程中, kref_put() 就被调用并把整个数据结构释放掉了。

4.kref_read 读取引用计数

cnt = kref_read(&data->kref)

注意,有的内核版本中没有该函数接口,可以采用 atomic_read 去读,例如

#include <asm/atomic.h>
cnt = atomic_read(&data->kref.refcount)
  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值