linux 可睡眠RCU

可睡眠 RCU( Sleepable RCU, SRCU)允许在读端临界区里面睡眠。

在读端临界区里面睡眠,可能导致宽限期很长。为了避免影响整个系统,使用 SRCU的子系统需要定义一个 SRCU 域,每个 SRCU 域有自己的读端临界区和宽限期。

目前内核有 3 种可睡眠 RCU。

(1)经典 SRCU:传统的 SRCU,配置宏是 CONFIG_CLASSIC_SRCU。

(2)微型 SRCU:为单处理器系统设计,配置宏是 CONFIG_TINY_SRCU。

(3)树型 SRCU:为拥有几百个或几千个处理器的大型系统设计,配置宏是 CONFIG_TREE_SRCU。

内核 4.12 版本引入微型 SRCU 和树型 SRCU,保留经典 SRCU,作为微型 SRCU 和树型 SRCU 出现问题时的备选项。由于微型 SRCU 和树型 SRCU 在测试中表现非常好,所以内核 4.13 版本废除了经典 SRCU。

使用方法

首先需要定义一个 SRCU 域:
struct srcu_struct ss;
然后初始化 SRCU 域:
int init_srcu_struct(struct srcu_struct *sp);
成功则返回 0,分配内存失败则返回“ -ENOMEM”。

读者访问临界区的方法如下:
idx = srcu_read_lock(&ss);
/* 读端临界区 */
srcu_read_unlock(&ss, idx);
函数 srcu_read_lock()返回一个索引,需要把这个索引传给函数 srcu_read_unlock()。
在读端临界区里面应该使用宏 srcu_dereference(p, sp)访问指针, 这个宏封装了数据依赖屏障,即只有阿尔法处理器需要的读内存屏障。

写者可以使用下面 4 个函数。
(1)使用函数 synchronize_srcu()等待宽限期结束,即所有读者退出读端临界区,然后写者执行下一步操作。这个函数可能睡眠。
void synchronize_srcu(struct srcu_struct *sp);
(2)使用函数 synchronize_srcu_expedited()等待宽限期结束,强制宽限期快速结束。
void synchronize_srcu_expedited(struct srcu_struct *sp);
(3)使用函数 call_srcu()注册延后执行的回调函数,把回调函数添加到 srcu_struct 结构体的回调函数链表中,立即返回,不会睡眠。
void call_srcu(struct srcu_struct *sp, struct rcu_head *head, rcu_callback_t func);
(4)使用函数 srcu_barrier()等待所有回调函数执行完。这个函数可能睡眠。
void srcu_barrier(struct srcu_struct *sp);


用完以后,需要使用函数 cleanup_srcu_struct()销毁结构体。
void cleanup_srcu_struct(struct srcu_struct *sp);
可以使用下面的宏定义并且初始化数据类型为 srcu_struct 的变量。
(1) DEFINE_SRCU(name):定义外部全局变量。
(2) DEFINE_STATIC_SRCU(name):定义静态全局变量或静态局部变量。
使用这两个宏定义的变量,不需要使用函数 init_srcu_struct()初始化,也不需要使用函数 cleanup_srcu_struct()销毁。


​​​​​​​

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Linux内核中的RCU(Read-Copy-Update)机制是一种用于实现高效并发访问共享数据的技术。在RCU机制中,读操作不会被阻塞,而写操作则通过延迟更新来避免对读操作的影响。然而,当某些情况下读操作被长时间阻塞时,就会发生RCU stall。下面是Linux内核中RCU stall的机制的详细介绍: 1. RCU的快速路径:在正常情况下,RCU的快速路径允许读操作不受写操作的影响,从而实现高效并发访问。当一个线程进行读操作时,它会在读取共享数据之前增加一个引用计数,并在读操作完成后减少引用计数。这样,即使有其他线程正在进行写操作,读操作仍然可以顺利进行。 2. 写操作的延迟更新:当一个线程进行写操作时,它会创建一个新的数据版本,并将更新后的数据写入新版本中。然后,它将原来的数据版本标记为废弃,并等待所有正在进行读操作的线程完成后才会释放废弃版本的内存资源。这种延迟更新的方式可以避免对读操作的影响。 3. RCU stall的触发:RCU stall通常在以下情况下触发: - 长时间的写操作:当一个写操作需要很长时间才能完成时,所有正在进行读操作的线程需要等待写操作完成才能继续进行读操作,这可能导致RCU stall的发生。 - 频繁的写操作:如果写操作频繁地竞争同一资源,如数据结构或共享变量,读操作的等待时间会增加,可能导致RCU stall。 - 更新操作的阻塞:当一个更新操作阻塞了RCU的快速路径,使得其他读操作无法顺利进行时,也会引发RCU stall。 4. RCU stall的处理:当RCU stall发生时,内核会通过一些机制来尝试解决或减轻RCU stall的影响,包括: - RCU回调函数处理机制:当RCU stall发生时,内核会通过回调函数处理机制来延迟执行一些需要被延迟的任务,如内存回收等,以减轻RCU stall的影响。 - RCU GP(Grace Period)的处理:GP是一个时间间隔,在这个时间间隔内,所有已经开始进行读操作的线程都可以继续执行,而不会被阻塞。内核会通过GP来确保读操作的一致性,并在GP结束后释放废弃版本的内存资源。 - RCU stall检测机制:内核会定期检测是否发生了长时间的阻塞,如果检测到长时间的阻塞,会尝试唤醒被阻塞的CPU,以解决RCU stall的问题。 通过以上机制,Linux内核的RCU机制可以在大多数情况下实现高效并发访问共享数据。然而,在某些特殊情况下,如长时间的写操作或频繁的写操作竞争,可能会引发RCU stall。内核通过回调函数处理、GP处理和RCU stall检测等机制来处理和减轻RCU stall的影响,以保证系统的性能和响应时间。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一叶知秋yyds

分享是一种美德,感谢金主打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值