加入收藏 | 设为首页 | 会员中心 | 我要投稿 PHP编程网 - 黄冈站长网 (http://www.0713zz.com/)- 数据应用、建站、人体识别、智能机器人、语音技术!
当前位置: 首页 > 运营中心 > 交互 > 正文

深入理解RCU实现

发布时间:2016-10-29 16:06:37 所属栏目:交互 来源:站长网
导读:副标题#e# 深入理解RCU实现 ——基于 内核2.6.21 RCU实现(lvyilong316) RCU(Read-Copy Update),顾名思义就是读-拷贝修改,它是基于其原理命名的。对于被RCU保护的共享数据结构, 读者不需要获得任何锁就可以访问它,但写者在访问它时首先拷贝一个副本,然

    下面我们介绍剩下的三组指针,但首先注意这三组链表上的元素都是struct rcu_head 类型。这三个链表的作用还要结合整个RCU写者从阻塞到唤醒的过程来看。

rcu写者的整体流程,假设系统中出现rcu写者阻塞,那么流程如下:

(1) 调用synchronize_rcu,将代表写者的rcu_head添加到CPU[n]每cpu变量rcu_data的nxtlist,这个链表代表有需要提交给rcu处理的回调(但还没有提交);

(2) CPU[n]每次时钟中断时检测自己的nxtlist是否为null,若不为空,因此则唤醒rcu软中断;

(3) RCU的软中断处理函数rcu_process_callbacks会挨个检查本CPU的三个链表。

下面分析RCU的核心处理函数,也就是软中断处理函数rcu_process_callbacks。

RCU软中断

在“RCU API实现分析”一节我们知道调用synchronize_rcu,将代表写者的rcu_head添加到了CPU[n]每cpu变量rcu_data的nxtlist。

而另一方面,在每次时钟中断中,都会调用update_process_times函数。

update_process_times 

void update_process_times(int user_tick) 

    //......
    if (rcu_pending(cpu)) 
        rcu_check_callbacks(cpu, user_tick); 

//......

    在每一次时钟中断,都会检查rcu_pending(cpu)是否为真,如果是,就会为其调用rcu_check_callbacks()。

rcu_pending

rcu_pending()的代码如下: 
int rcu_pending(int cpu) 

    return __rcu_pending(&rcu_ctrlblk, &per_cpu(rcu_data, cpu)) || 
    __rcu_pending(&rcu_bh_ctrlblk, &per_cpu(rcu_bh_data, cpu)); 

    同上面一样,忽略bh的部份,我们看 __rcu_pending。

 __rcu_pending

static int __rcu_pending(struct rcu_ctrlblk *rcp, struct rcu_data *rdp) 

    /* This cpu has pending rcu entries and the grace period 
     * for them has completed. 
     */ 
    if (rdp->curlist && !rcu_batch_before(rcp->completed, rdp->batch)) 
        return 1; 

    /* This cpu has no pending entries, but there are new entries */ 
    if (!rdp->curlist && rdp->nxtlist) 
        return 1; 

    /* This cpu has finished callbacks to invoke */ 
    if (rdp->donelist) 
        return 1; 

    /* The rcu core waits for a quiescent state from the cpu */ 
    if (rdp->quiescbatch != rcp->cur || rdp->qs_pending) 
        return 1; 

    /* nothing to do */ 
    return 0; 

    可以上面有四种情况会返回1,分别对应: 

A. 该CPU上有等待处理的回调函数,且已经经过了一个batch(grace period).rdp->datch表示rdp在等待的batch序号;

B. 上一个等待已经处理完了,又有了新注册的回调函数;

C. 等待已经完成,但尚末调用该次等待的回调函数;

D. 在等待quiescent state. 

如果rcu_pending返回1,就会进入到rcu_check_callbacks(),rcu_check_callbacks()中主要工作就是调用raise_softirq(RCU_SOFTIRQ),触发RCU软中断。而RCU软中断的处理函数为rcu_process_callbacks,其中分别针对每cpu变量rcu_bh_data和rcu_data调用__rcu_process_callbacks。我们主要分析针对rcu_data的调用。

__rcu_process_callbacks

1) 先看nxtlist里有没有待处理的回调(rcu_head),如果有的话,说明有写者待处理,那么还要分两种情况:

1.1)如果系统是第一次出现写者阻塞,也即之前的写者都已经处理完毕,那么此时curlist链表一定为空(curlist专门存放已被rcu检测到的写者请求),于是就把nxtlist里的所有成员都移动到curlist指向,并把当前CPU需要等待的grace period id:rdp->batch设置为当前系统处理的grace period的下一个grace周期,即rcp->cur+ 1。由于这算是一个新的grace period,即start_rcu_batch,所以还接着需要增加系统的grace period计数,即rcp->cur++,同时,将全局的cpusmask设置为全f,代表新的grace period开始,需要检测所有的cpu是否都经过了一次进程切换。代码如下:

void __rcu_process_callbacks(struct rcu_ctrlblk *rcp,  

                    struct rcu_data *rdp)  

{  

    if (rdp->nxtlist && !rdp->curlist) {  

        move_local_cpu_nxtlist_to_curlist();  

  

        rdp->batch = rcp->cur + 1;  

  

        if (!rcp->next_pending) {  

            rcp->next_pending = 1;  

            rcp->cur++;  

            cpus_andnot(rcp->cpumask, cpu_online_map, nohz_cpu_mask);  

        }  

    }  

}  

接着跳转至1.2。

 

(编辑:PHP编程网 - 黄冈站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

推荐文章
    热点阅读