我是linux内核的新手。我的问题是关于task_struct
. 我知道每个task_struct
都通过指向父进程的指针来引用其父进程task_struct
。
查看task_struct
定义中的 sched.h 后,我注意到以下内容:
struct task_struct __rcu *real_parent; /* real parent process */
我发现它引用了compiler.h。我猜“__rcu”代表“读取副本更新”
有人可以澄清语法吗?
我是linux内核的新手。我的问题是关于task_struct
. 我知道每个task_struct
都通过指向父进程的指针来引用其父进程task_struct
。
查看task_struct
定义中的 sched.h 后,我注意到以下内容:
struct task_struct __rcu *real_parent; /* real parent process */
我发现它引用了compiler.h。我猜“__rcu”代表“读取副本更新”
有人可以澄清语法吗?
Read-copy-update是一种算法,它允许对数据结构的读取器进行并发访问,而无需锁定结构。可以在这里阅读。
如果内核是使用CONFIG_SPARSE_RCU_POINTER
config 选项构建的,__rcu
则定义include/linux/compiler.h
为
# define __rcu __attribute__((noderef, address_space(4)))
这是稀疏代码分析工具的注释,可以警告程序员可能忽略的某些事情。这与 RCU 的关系在以下内容中进行了解释Documentation/RCU/checklist.txt
:
__rcu 稀疏检查:使用 __rcu 标记指向受 RCU 保护的数据结构的指针,如果您在没有 rcu_dereference() 变体之一的服务的情况下访问该指针,sparse 会警告您。
rcu_dereference()
返回一个可以被代码安全取消引用的指针,并记录程序员使用 RCU 机制保护指针的意图,使 Sparse 等工具能够检查编程错误和遗漏。
RCU 代表“读取、复制、更新”。它是一种允许多个读者访问数据的算法,这些数据可以由作者同时更新甚至删除。
在 RCU 下,写入者仍然必须确保相互排斥,但读取者不会获得锁。必须注意以不违反读取完整性的方式更新共享数据结构。如果必须删除或删除某些内容,则可以与读取器并行完成该项目与数据结构的取消链接,但实际删除内存必须等到最后一个读取器完成。
不是让读者获得锁,而是通过其他方式推断读者的下落。线程可以通过加入“读取端临界区”来宣布它们浏览数据结构的意图,这不是真正的锁,而是一种全局阶段。
例如,假设某些线程在阶段 0 进入 RCU 读取端临界区。更新程序执行了删除操作并希望释放一块内存。它必须简单地等待系统中的所有线程腾出阶段 0。同时,其他读者已经在查看数据结构,但是当他们向 RCU 声明他们的意图时,他们通过输入 RCU 读取端关键来完成阶段 1 下的部分。只有阶段 0 的线程可能仍然拥有指向已删除对象的指针,因此当最后一个线程离开阶段 0 时,可以安全地删除该对象。阶段 1 中新到达的线程看不到对象,因为对象已经从数据结构中删除,所以他们没有办法找到它。
RCU 利用了我们不需要“拥有”的锁定对象的想法,以便了解诸如“没有线程可以再访问该对象”之类的信息。