• linux 使用spinlock的配对关系问题


    大家使用spinlock的时候,一般是这么配对:

    spin_lock---------------------spin_unlock------------------最轻
    spin_lock_bh----------------spin_unlock_bh-----------------较轻
    spin_lock_irq----------------spin_unlock_irq---------------较重 
    spin_lock_irqsave---------spin_lock_irqrestore--------------最重

    那么,假设我使用 spin_lock_irqsave 来关中断和关抢占,并保存之前的中断状态,那么,我能不能使用spin_unlock来解锁呢?

    static inline int
    __mod_timer(struct timer_list *timer, unsigned long expires,
                            bool pending_only, int pinned)
    {
        struct tvec_base *base, *new_base;
        unsigned long flags;
        int ret = 0 , cpu;
    
        timer_stats_timer_set_start_info(timer);
        BUG_ON(!timer->function);
    
        base = lock_timer_base(timer, &flags);
    
        ret = detach_if_pending(timer, base, false);
        if (!ret && pending_only)
            goto out_unlock;
    
        debug_activate(timer, expires);
    
        cpu = smp_processor_id();
    
    #if defined(CONFIG_NO_HZ_COMMON) && defined(CONFIG_SMP)
        if (!pinned && get_sysctl_timer_migration())
            cpu = get_nohz_timer_target();
    #endif
        new_base = per_cpu(tvec_bases, cpu);
    
        if (base != new_base) {
            /*
             * We are trying to schedule the timer on the local CPU.
             * However we can't change timer's base while it is running,
             * otherwise del_timer_sync() can't detect that the timer's
             * handler yet has not finished. This also guarantees that
             * the timer is serialized wrt itself.
             */
            if (likely(base->running_timer != timer)) {
                /* See the comment in lock_timer_base() */
                timer_set_base(timer, NULL);
                spin_unlock(&base->lock);
                base = new_base;
                spin_lock(&base->lock);
                timer_set_base(timer, base);
            }
        }
    
        timer->expires = expires;
        internal_add_timer(base, timer);
    
    out_unlock:
        spin_unlock_irqrestore(&base->lock, flags);-----------收尾很重要
    
        return ret;
    }

    答案就在这个函数中,看完这个函数,你就不会这么浅显地理解配对了,可能会更深地去理解spinlock的使用。

    其实spinlock这种忙等的方式,使用场景一般要求,临界区不能太大,且多路径访问的概率不那么高。这里的多路径,就是指进程上下文和中断上下文,其中中断上下文又分为硬中断和软中断。

    进程上下文包括:用户进程,内核线程,从调度角度来说,都归属进程上下文,可以睡眠。

    中断上下文包括:HW interrupt context(中断handler)、软中断上下文(soft irq,当然由于各种原因,该softirq被推迟到softirqd的内核线程中执行的时候就不属于这个场景了,属于进程上下文那个分类了)、timer的callback函数(本质上也是softirq)、tasklet(本质上也是softirq)。

    不同的控制路径,使用不同的spinlock,比如只有进程上下文访问临界区,则使用spin_lock就够了,如果有软中断和进程上下文访问临界区,则需要用spin_lock_bh,如果有硬中断访问和进程上下文访问,则用spin_lock_irq。

    假设只有软中断访问临界区,则只要关软中断就行,甚至都不需要spin-lock,

    假设只有硬中断访问临界区,则只要关硬中断就行,也不需要spin-lock

     如果有兴趣完全弄懂,可以参考 蜗窝科技  http://www.wowotech.net/kernel_synchronization/spinlock.html

    水平有限,如果有错误,请帮忙提醒我。如果您觉得本文对您有帮助,可以点击下面的 推荐 支持一下我。版权所有,需要转发请带上本文源地址,博客一直在更新,欢迎 关注 。
  • 相关阅读:
    学习jQuery必须知道的几种常用方法
    Jquery技巧总结
    代码测试
    NOIP2003 神经网络
    NOIP2003 传染病控制
    NOIP2003 加分二叉树
    NOIP2004 虫食算
    NOIP2004 合唱队列
    NOIP2004 合并石子
    NOIP2004 津津的储蓄计划
  • 原文地址:https://www.cnblogs.com/10087622blog/p/9560979.html
Copyright © 2020-2023  润新知