内核中有许多地方调用类似BUG()的语句,它非常像一个内核运行时的断言,意味着本来不该执行到BUG()这条语句,一旦执行即抛出Oops。 BUG()的定义为:
#define BUG() do { \
printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
panic("BUG!"); \
} while (0)
#endif
其中的panic()定义在kernel/panic.c中,会导致内核崩溃,并打印Oops。比如arch/arm/kernel/dma.c中的enable_dma()函数:
void enable_dma (unsigned int chan)
{
dma_t *dma = dma_channel(chan);
if (!dma->lock)
goto free_dma;
if (dma->active == 0) {
dma->active = 1;
dma->d_ops->enable(chan, dma);
}
return;
free_dma:
printk(KERN_ERR "dma%d: trying to enable free DMA\n", chan);
BUG();
}
上述代码的含义是,如果在dma->lock不成立的情况下,驱动直接调用了enable_dma(),实际上意味着内核的一个bug。
BUG()还有一个变体叫BUG_ON(),它的内部会引用BUG(),形式为
#define BUG_ON(condition) \
do { \
if (unlikely(condition)) BUG(); \
} while(0)
对于BUG_ON()而言,只有当括号内的条件成立的时候,才抛出Oops。比如drivers/char/random.c中的类似代码:
static void push_to_pool(struct work_struct *work)
{
struct entropy_store *r = container_of(work, struct entropy_store
push_work);
BUG_ON(!r);
_xfer_secondary_pool(r, random_read_wakeup_bits/8);
trace_push_to_pool(r->name, r->entropy_count >> ENTROPY_SHIFT);
r->pull->entropy_count >> ENTROPY_SHIFT);
}
除了BUG_ON()外,内核有个稍微弱一些WARN_ON(),在括号中的条件成立的时候,内核会抛出栈回溯,但是不会panic(),这通常用于内核抛出一个警告,暗示某种不太合理的事情发生了。
如在kernel/locking/mutexdebug.c中的debug_mutex_unlock()函数发现mutex_unlock()的调用者和mutex_lock()的调用者不是同 一个线程的时候或者mutex的owner为空的时候,会抛出警告信息。
void debug_mutex_unlock(struct mutex *lock)
{
if (likely(debug_locks)) {
DEBUG_LOCKS_WARN_ON(lock->magic != lock);
if (!lock->owner)
DEBUG_LOCKS_WARN_ON(!lock->owner);
else
DEBUG_LOCKS_WARN_ON(lock->owner != current);
DEBUG_LOCKS_WARN_ON(!lock->wait_list.prev && !lock->wait_li
mutex_clear_owner(lock);
}
}
小技巧:
WARN_ON()可以作为一个调试技巧。比如,我们进到内核某个函数后,不知道这个函数是怎么一级一级被调用进来的,那可以在该函数中加入一个WARN_ON(1)。
|