加入收藏 | 设为首页 | 会员中心 | 我要投稿 淮北站长网 (https://www.0561zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 运营中心 > 交互 > 正文

深入理解RCU实现

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

    仅当系统检测到一个grace period的所有CPU都经历了进程切换后,才会给系统一个信息要求启动新batch,在此期间的所有写者请求,都暂存在本地CPU的nxtlist链表里。

进程切换

在每一次进程切换的时候,都会调用rcu_qsctr_inc().如下代码片段如示: 
asmlinkage void __sched schedule(void) 

//......

rcu_qsctr_inc(cpu); 
//...... 

rcu_qsctr_inc()代码如下: 
static inline void rcu_qsctr_inc(int cpu) 

    struct rcu_data *rdp = &per_cpu(rcu_data, cpu); 
    rdp->passed_quiesc = 1; 

    该函数将对应CPU上的rcu_data的passed_quiesc成员设为了1。或许你已经发现了,这个过程就标识该CPU经过了一次quiescent state,和之前在软中断的初始化为0相呼应。 

几种RCU情况分析 

1. 如果CPU 1上有进程调用rcu_read_lock进入临界区,之后退出来,发生了进程切换,新进程又通过rcu_read_lock进入临界区.由于RCU软中断中只判断一次上下文切换,因此,在调用回调函数的时候,仍然有进程处于RCU的读临界区,这样会不会有问题呢? 
    这样是不会有问题的.还是上面的例子: 
    spin_lock(&foo_mutex); 
    old_fp = gbl_foo; 
    *new_fp = *old_fp; 
    new_fp->a = new_a; 
    rcu_assign_pointer(gbl_foo, new_fp); 
    spin_unlock(&foo_mutex); 
    synchronize_rcu(); 
    kfree(old_fp); 
    使用synchronize_rcu ()只是为了等待持有old_fd(也就是调用rcu_assign_pointer ()更新之前的gbl_foo)的进程退出.而不需要等待所有的读者全部退出.这是因为,在rcu_assign_pointer ()之后的读取取得的保护指针,已经是更新好的新值了. 

2. 如果一个CPU连续调用synchronize_rcu()或者call_rcu()它们会有什么影响呢? 
    如果当前有请求在等待,就会新请提交的回调函数挂到taillist上,一直到前一个等待完成,再将taillist的数据移到curlist,并开启一个新的等待,因此,也就是说,在前一个等待期间提交的请求,都会放到一起处理.也就是说,他们会共同等待所有CPU切换完成. 
举例说明如下: 

带bh的RCU API 

在上面的代码分析的时候,经常看到带有bh的RCU代码.现在来看一下这些带bh的RCU是什么样的。
#define rcu_read_lock_bh() __rcu_read_lock_bh() 
#define rcu_read_unlock_bh() __rcu_read_unlock_bh() 

#define __rcu_read_lock_bh() 
do { 
    local_bh_disable(); 
    __acquire(RCU_BH); 
    rcu_read_acquire(); 
}while (0) 

#define __rcu_read_unlock_bh() 
do { 
    rcu_read_release(); 
    __release(RCU_BH); 
    local_bh_enable(); 
} while (0) 
    根据上面的分析:bh RCU跟普通的RCU相比不同的是,普通RCU是禁止内核抢占,而bh RCU是禁止下半部. 
    其实,带bh的RCU一般在软中断使用,不过计算quiescent state并不是发生一次上下文切换。而是发生一次softirq.我们在后面的分析中可得到印证. 

call_rcu_bh() 

void call_rcu_bh(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) 

    unsigned long flags; 
    struct rcu_data *rdp; 

    head->func = func; 
    head->next = NULL; 
    local_irq_save(flags); 
    rdp = &__get_cpu_var(rcu_bh_data); 
    *rdp->nxttail = head; 
    rdp->nxttail = &head->next; 

    if (unlikely(++rdp->qlen > qhimark)) { 
        rdp->blimit = INT_MAX; 
        force_quiescent_state(rdp, &rcu_bh_ctrlblk); 
    } 

    local_irq_restore(flags); 

    它跟call_rcu()不相同的是,rcu是取per_cpu变量rcu__data和全局变量rcu_ctrlblk.而bh RCU是取rcu_bh_data,rcu_bh_ctrlblk.他们的类型都是一样的,这样做只是为了区分BH和普通RCU的等待. 

对于rcu_bh_qsctr_inc 
static inline void rcu_bh_qsctr_inc(int cpu) 

    struct rcu_data *rdp = &per_cpu(rcu_bh_data, cpu); 
    rdp->passed_quiesc = 1; 

    它跟rcu_qsctr_inc()机同,也是更改对应成员. 所不同的是,调用rcu_bh_qsctr_inc()的地方发生了变化. 
asmlinkage void __do_softirq(void) 

    //......
    do { 
        if (pending & 1) { 
            h->action(h); 
            rcu_bh_qsctr_inc(cpu); 
        } 
        h++; 
        pending >>= 1; 
     } while (pending); 
    //...... 

     也就是说,在发生软中断的时候,才会认为是经过了一次quiescent state.

(编辑:淮北站长网)

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

热点阅读