littlenewer 发表于 2015-02-05 20:13

__call_rcu如何防止多核竞争

__call_rcu只用了关中断来保护rcp,但是在SMP场景下有可能多个CPU同时把head链到rcp,而rcp又是全局变量rcu_sched_ctrlblk,这样就有可能产生冲突。系统是怎么保证不出问题的呢?

static void __call_rcu(struct rcu_head *head,
                     void (*func)(struct rcu_head *rcu),
                     struct rcu_ctrlblk *rcp)
{
        unsigned long flags;

        debug_rcu_head_queue(head);
        head->func = func;
        head->next = NULL;

        local_irq_save(flags);
        *rcp->curtail = head;
        rcp->curtail = &head->next;
        RCU_TRACE(rcp->qlen++);
        local_irq_restore(flags);
}

Tinnal 发表于 2015-02-05 23:49

回复 1# littlenewer


你看的代码是rcutiny.c吧。那个是单核的版本,多核的版本应该是rcutree.c


static void
__call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),
           struct rcu_state *rsp)
{
        unsigned long flags;
        struct rcu_data *rdp;

        head->func = func;
        head->next = NULL;

        smp_mb(); /* Ensure RCU update seen before callback registry. */

        /*
       * Opportunistically note grace-period endings and beginnings.
       * Note that we might see a beginning right after we see an
       * end, but never vice versa, since this CPU has to pass through
       * a quiescent state betweentimes.
       */
        local_irq_save(flags);
        rdp = rsp->rda;
        rcu_process_gp_end(rsp, rdp);
        check_for_new_grace_period(rsp, rdp);

        /* Add the callback to our list. */
        *rdp->nxttail = head;
        rdp->nxttail = &head->next;

        /* Start a new grace period if one not already started. */
        if (!rcu_gp_in_progress(rsp)) {
                unsigned long nestflag;
                struct rcu_node *rnp_root = rcu_get_root(rsp);

                raw_spin_lock_irqsave(&rnp_root->lock, nestflag);
                rcu_start_gp(rsp, nestflag);/* releases rnp_root->lock. */
        }

        /*
       * Force the grace period if too many callbacks or too long waiting.
       * Enforce hysteresis, and don't invoke force_quiescent_state()
       * if some other CPU has recently done so.Also, don't bother
       * invoking force_quiescent_state() if the newly enqueued callback
       * is the only one waiting for a grace period to complete.
       */
        if (unlikely(++rdp->qlen > rdp->qlen_last_fqs_check + qhimark)) {
                rdp->blimit = LONG_MAX;
                if (rsp->n_force_qs == rdp->n_force_qs_snap &&
                  *rdp->nxttail != head)
                        force_quiescent_state(rsp, 0);
                rdp->n_force_qs_snap = rsp->n_force_qs;
                rdp->qlen_last_fqs_check = rdp->qlen;
        } else if (ULONG_CMP_LT(ACCESS_ONCE(rsp->jiffies_force_qs), jiffies))
                force_quiescent_state(rsp, 1);
        local_irq_restore(flags);
}

Tinnal 发表于 2015-02-05 23:50

偶,要声明一下,我的代码是2.6.34.10的。3.x内核文件改名了,但结论不变。
页: [1]
查看完整版本: __call_rcu如何防止多核竞争