- 论坛徽章:
- 0
|
Linux2.6 RCU情景分析 (四核)
初始态
static struct rcu_ctrlblk rcu_ctrlblk = {
.cur = -300,
.completed = -300,
.lock = __SPIN_LOCK_UNLOCKED(&rcu_ctrlblk.lock),
.cpumask = CPU_MASK_NONE,
};
static void rcu_init_percpu_data(int cpu, struct rcu_ctrlblk *rcp,
struct rcu_data *rdp)
{
memset(rdp, 0, sizeof(*rdp));
rdp->curtail = &rdp->curlist;
rdp->nxttail = &rdp->nxtlist;
rdp->donetail = &rdp->donelist;
rdp->quiescbatch = rcp->completed;
rdp->qs_pending = 0;
rdp->cpu = cpu;
rdp->blimit = blimit;
}
情景1:系统没有RCU保护资源,也就是处于初态
时钟中断和idle中,此时rcu_pending返回0,也没有rcu entry所以不做任何事
情景2:0号cpu调用了call_rcu,也就是往nxlist加入了一个rcu entry。
下面两列并发执行
Cpu0:在时钟中断和idle中,此时rcu_pending返回1于是rcu_qsctr_inc被调用将passed_quiesc设为1 Other cpus:在时钟中断和idle中,此时rcu_pending返回0,无rcu相关的操作
| cpu0:处理rcu的软中断中__rcu_process_callbacks被调用将nxlist移到curlist,本cpu batch号设为cur+1,即-299。next_pending为0,将next_pending设为1,调用rcu_start_batch开始一个新的batch,rcu_start_batch中测试条件为真,于是nextpending←0
cur←cur+1,即-299
signaled←0,可用cpu 在cpumask中全部置位。接着__rcu_process_callbacks调用rcu_check_quiescent_state,这个函数中rdp->quiescbatch !=rcp->cur这个条件满足,所以qs_pending←1
passed_quiesc←0
quiescbatch←cur 这次软中断结束。 Other cpus:处理rcu的软中断中调用rcu_check_quiescent_state,这个函数中rdp->quiescbatch !=rcp->cur这个条件满足,所以qs_pending←1
passed_quiesc←0
quiescbatch←cur 这次软中断结束。 | 如果下次RCU软中断执行时,passed_quiesc还未被设为1,也就是自上次rcu软中断之后没有发生上下文切换,__rcu_process_callbacks什么都不做。
Cpu0:如果下次RCU软中断执行时,passed_quiesc为1,也就是自上次rcu软中断之后至少发生一次上下文切换,rcu_check_quiescent_state中qs_pending←0 此时quiescbatch与cur相等,于是cpu_quiet被调用,cpu_quiet中将本cpu从cpumask清除,其他cpu也已被清除,调用rcu_start_batch开始一个新batch,completed←cur。调用rcu_do_batch处理batch。
Other cpus:调用cpu_quiet将本cpu从cpumask清除,如果cpu全部被清除,调用rcu_start_batch开始一个新batch,completed←cur。
情景3:除cpu0以外其他cpu调用了call_rcu,也就是往nxlist加入了一个rcu entry。
Other cpus:在时钟中断和idle中,此时rcu_pending返回1于是rcu_qsctr_inc被调用将passed_quiesc设为1 Cpu0:在时钟中断和idle中,此时rcu_pending返回0,无rcu相关的操作 | Other cpus:处理rcu的软中断中__rcu_process_callbacks被调用将nxlist移到curlist,本cpu batch号设为cur+1,即-299。next_pending为0,将next_pending设为1,调用rcu_start_batch开始一个新的batch,rcu_start_batch中测试条件为真,于是nextpending←0
cur←cur+1,即-299
signaled←0,可用cpu 在cpumask中全部置位。接着__rcu_process_callbacks调用rcu_check_quiescent_state,这个函数中rdp->quiescbatch !=rcp->cur这个条件满足,所以qs_pending←1
passed_quiesc←0
quiescbatch←cur 这次软中断结束。 cpu0:处理rcu的软中断中调用rcu_check_quiescent_state,这个函数中rdp->quiescbatch !=rcp->cur这个条件满足,所以qs_pending←1
passed_quiesc←0
quiescbatch←cur 这次软中断结束。 |
如果下次RCU软中断执行时,passed_quiesc还未被设为1,也就是自上次rcu软中断之后没有发生上下文切换,__rcu_process_callbacks什么都不做。
Other cpu:如果下次RCU软中断执行时,passed_quiesc为1,也就是自上次rcu软中断之后至少发生一次上下文切换,rcu_check_quiescent_state中qs_pending←0 此时quiescbatch与cur相等,于是cpu_quiet被调用,cpu_quiet中将本cpu从cpumask清除,其他cpu也已被清除,调用rcu_start_batch开始一个新batch,completed←cur。调用rcu_do_batch处理batch。
Other cpus:调用cpu_quiet将本cpu从cpumask清除,如果cpu全部被清除,调用rcu_start_batch开始一个新batch,completed←cur。
情景分析总结
由以上分析可知,rcu的处理是由cur驱动的,进一步是由nxtlist,再进一步是由call_rcu驱动的,即nxlist不空时,cur会加1,如果上次batch处理完,就会开始新的batch |
|