首页 > 系统服务 > 详细

理解Linux内核之中断保存与恢复

时间:2018-02-06 13:47:07      阅读:2034      评论:0      收藏:0      [点我收藏+]

在Linux内核中(linux-4.14.12/mm/slab.c#3389), 乍一看下边的代码,貌似L3389有bug,于是我就绕偶兴趣地阅读了一下local_irq_save/local_irq_restore的源代码。

/* linux-4.14.12/mm/slab.c#3389 */

3377  static __always_inline void *
3378  slab_alloc(struct kmem_cache *cachep, gfp_t flags, unsigned long caller)
3379  {
3380    unsigned long save_flags;
3381    void *objp;
....
3389    local_irq_save(save_flags);
3390    objp = __do_cache_alloc(cachep, flags);
3391    local_irq_restore(save_flags);
....
3399    return objp;
3400  }

在L3380和L3389中, 如果local_irq_save()是一个函数,必然存在着bug, 因为需要把save_flags的变量地址传给local_irq_save()才对。

3380      unsigned long save_flags;
....
3389      local_irq_save(save_flags);

但是,local_irq_save()和local_irq_restore()不是函数,而是宏,这样就没有bug了。

1. local_irq_save()和local_irq_restore()的实现

/* linux-4.14.12/include/linux/irqflags.h#139 */

105  #ifdef CONFIG_TRACE_IRQFLAGS
...
110  #define local_irq_save(flags)                      111     do {                                            112             raw_local_irq_save(flags);              113             trace_hardirqs_off();                   114     } while (0)
115
116
117  #define local_irq_restore(flags)                   118     do {                                            119             if (raw_irqs_disabled_flags(flags)) {   120                     raw_local_irq_restore(flags);   121                     trace_hardirqs_off();           122             } else {                                123                     trace_hardirqs_on();            124                     raw_local_irq_restore(flags);   125             }                                       126     } while (0)
...
135  #else /* !CONFIG_TRACE_IRQFLAGS */
...
139  #define local_irq_save(flags)                              140     do {                                                    141             raw_local_irq_save(flags);                      142     } while (0)
143  #define local_irq_restore(flags) do { raw_local_irq_restore(flags); } while (0)
...
146  #endif /* CONFIG_TRACE_IRQFLAGS */

为简单起见,我们只关注!CONFIG_TRACE_IRQFLAGS分支就好了,

139  #define local_irq_save(flags)                              140     do {                                                    141             raw_local_irq_save(flags);                      142     } while (0)
143  #define local_irq_restore(flags) do { raw_local_irq_restore(flags); } while (0)

于是, 我们可以认为, locale_irq_save()/local_irq_restore()等同于:

#define local_irq_save(flags)    raw_local_irq_save(flags)
#define local_irq_restore(flags) raw_local_irq_restore(flags)

2. raw_local_irq_save()和raw_local_irq_restore()的实现

/* linux-4.14.12/include/linux/irqflags.h#78 */

78  #define raw_local_irq_save(flags)                   79      do {                                            80              typecheck(unsigned long, flags);        81              flags = arch_local_irq_save();          82      } while (0)
83  #define raw_local_irq_restore(flags)                84      do {                                            85              typecheck(unsigned long, flags);        86              arch_local_irq_restore(flags);          87      } while (0)

关于宏typecheck()不做解释,因为很直观,就是保证flags的类型必须是unsigned long。于是,raw_local_irq_save()和raw_local_irq_restore()等同于:

#define raw_local_irq_save(flags)       flags = arch_local_irq_save()
#define raw_local_irq_restore(flags)    arch_local_irq_restore(flags)

下面以x86为例说明arch_local_irq_save()和arch_local_irq_restore()这两个函数的实现。

3. arch_local_irq_save()和arch_local_irq_restore()这两个函数在x86上的实现

/* linux-4.14.12/arch/x86/include/asm/irqflags.h#70 */

70  static inline notrace unsigned long arch_local_save_flags(void)
71  {
72      return native_save_fl();
73  }
74
75  static inline notrace void arch_local_irq_restore(unsigned long flags)
76  {
77      native_restore_fl(flags);
78  }

显然,只需要看明白native_save_fl()和native_restore_fl()的具体实现就好了。

3.1 native_save_fl()的实现

/* linux-4.14.12/arch/x86/include/asm/irqflags.h#16 */

16  static inline unsigned long native_save_fl(void)
17  {
18      unsigned long flags;
19
20      /*
21       * "=rm" is safe here, because "pop" adjusts the stack before
22       * it evaluates its effective address -- this is part of the
23       * documented behavior of the "pop" instruction.
24       */
25      asm volatile("# __raw_save_flags\n\t"
26                   "pushf ; pop %0"
27                   : "=rm" (flags)
28                   : /* no input */
29                   : "memory");
30
31      return flags;
32  }

这是一段内嵌的汇编代码,后面写一个简单的demo再解释。

3.2 native_restore_fl()的实现

 

 

。。。未完待续。。。。

理解Linux内核之中断保存与恢复

原文:https://www.cnblogs.com/idorax/p/8421676.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!