在atomic context环境中不能调用msleep等函数,atomic context基本就是中断或者被spin_lock/spin_unlock等包起来的部分,我们先看看msleep 为啥在atomic context中使用
void msleep(unsigned int msecs)
{
unsigned long timeout = msecs_to_jiffies(msecs) + 1;
while (timeout)
timeout = schedule_timeout_uninterruptible(timeout);
}
原来是调用schedule_timeout_uninterruptible
signed long __sched schedule_timeout_uninterruptible(signed long timeout)
{
__set_current_state(TASK_UNINTERRUPTIBLE);
return schedule_timeout(timeout);
}
在schedule_timeout_uninterruptible->__schedule->schedule_debug 最终会出现 BUG: scheduling while atomic经典bug 这样经典的bug
但是如果真的要在atomic context delay该怎么办呢?答案是可以调用mdelay函数
#ifndef mdelay
#define mdelay(n) (\
(__builtin_constant_p(n) && (n)<=MAX_UDELAY_MS) ? udelay((n)*1000) : \
({unsigned long __ms=(n); while (__ms--) udelay(1000);}))
这里都是调用udelay
#define udelay(n) \
({ \
if (__builtin_constant_p(n)) { \
if ((n) / 20000 >= 1) \
__bad_udelay(); \
else \
__const_udelay((n) * 0x10c7ul); \
} else { \
__udelay(n); \
} \
})
加入走else的case
void __udelay(unsigned long usecs)
{
__const_udelay(usecs * 0x10C7UL); /* 2**32 / 1000000 (rounded up) */
}
可见最终也是调用__const_udelay
static inline void cpu_relax(void)
{
asm volatile("yield" ::: "memory");
}
void __delay(unsigned long cycles)
{
cycles_t start = get_cycles();
while ((get_cycles() - start) < cycles)
cpu_relax();
}
EXPORT_SYMBOL(__delay);
inline void __const_udelay(unsigned long xloops)
{
unsigned long loops;
loops = xloops * loops_per_jiffy * HZ;
__delay(loops >> 32);
}
原来最终是调用cpu_relax 啊,所以说mdelay可以用在atomic context环境中