rcu_read_lock() / rcu_read_unlock():用于进入和离开RCU读取段,保证了在这两个函数调用内的读取不会看到中间状态的数据。 synchronize_rcu():等待一个RCU宽限期的结束,确保之前的所有RCU读者都已经完成。 call_rcu():将一个回调函数传递给RCU,该函数会在RCU宽限期之后被调用,用于释放老的数据结构。 kfree_...
并继续为每个暂停当前 RCU 任务宽限期的任务输出 sched_show_task()。 解释RCU’s CPU Stall-Detector“Splats” 对于RCU 的非 RCU 任务风格,当一个 CPU 检测到某个其他 CPU 正在停止时,它将打印类似于以下内容的消息: INFO:rcu_scheddetected stalls on CPUs/tasks: 2-...: (3 GPs behind) idle=06c/0...
为了解决这个问题,Linux提供了rcu_assign_pointer/rcu_dereference宏来确保执行顺序,Linux内核也基于rcu_assign_pointer/rcu_dereference宏进行了更高层的封装,比如list,hlist,因此,在内核中有三种被RCU保护的场景:1)指针;2)list链表;3)hlist哈希链表。 针对这三种场景,Publish-Subscribe接口如下表: 2.2.2Wait For Pre...
组织成层级树状struct rcu_node*level[RCU_NUM_LVLS+1];//指向每层的首个rcu_node节点,数组加1是为了消除编译告警struct rcu_data __percpu*rda;//指向每个CPU的rcu_data实例call_rcu_func_t call;//指向特定RCU类型的call_rcu函数:call_rcu_sched, call_rcu_bh等int ncpus;// 处理器数量unsigned long ...
在Linux内核中,RCU最常见的用途是替换读写锁。在20世纪90年代初期,Paul在实现通用RCU之前,实现了一种轻量级的读写锁。后来,为这个轻量级读写锁原型所设想的每个用途,最终都使用RCU来实现了。
void __sched some_function(args, ...) { ... schedule(); ... } 1.2 schedule函数 schedule就是主调度器的函数, 在内核中的许多地方, 如果要将CPU分配给与当前活动进程不同的另一个进程, 都会直接调用主调度器函数schedule. 该函数完成如下工作 确定当前就绪队列, 并在保存一个指向当前(仍然)活动进程的t...
//指向每个CPU的rcu_data实例call_rcu_func_tcall;//指向特定RCU类型的call_rcu函数:call_rcu_sched, call_rcu_bh等intncpus;// 处理器数量unsignedlonggpnum;//当前宽限期编号,gpnum > completed,表明正处在宽限期内unsignedlongcompleted;//上一个结束的宽限期编号,如果与gpnum相等,表明RCU空闲......
(1)等待RCU reader离开临界区(这是大家都熟悉的功能) (2)等待NMI的handler调用完成 (3)等待所有的interrupt handler调用完成 (4)其他 因此,该函数用途太多,最终被两个函数代替:synchronize_rcu和synchronize_sched。其中synchronize_rcu用于RCU的同步。而synchronize_sched负责其他方面的功能(本质是等待系统中所有CPU退出...
大家想必觉得内存屏障能够达到赋值顺序执行,但是相对来说内存屏障这操作是比较麻烦的事(原文用的是notoriously这个词,众所周知地、恶名昭彰地,声名狼藉地;看来作者对内存屏障是相当不感冒啊)。因此,我们压缩一下,提供一个发布语义的原生接口,rcu_assign_ pointer() 。变成下面这种形式: ...
RCU有几个关键的数据结构:struct rcu_state,struct rcu_node,struct rcu_data; 图来了: struct rcu_state:用于描述RCU的全局状态,它负责组织树状层级结构,系统中支持不同类型的RCU状态:rcu_sched_state, rcu_bh_state,rcu_preempt_state; struct rcu_node:Tree RCU中的组织节点; ...