中断中不能睡眠的原因
为什么interrupt context中不能调用导致睡眠的kernel API呢?如果驱动这么做会导致什么样的后果呢?
本文的实验在X86 64bit + 标准4.4内核上完成。
看下一个中断:
#define DRIVER_DESC "context schedule test driver" static struct timer_list cst_timer; static void cst_timer_handler (unsigned long data) { struct task_struct *p = current; pr_info("=====in timer handler=====\n"); pr_info("cst shoot %16s [%x] task:\n", p->comm, preempt_count()); mod_timer(&cst_timer, jiffies + HZ); schedule(); } static int __init cst_init(void) { init_timer(&cst_timer); cst_timer.function = cst_timer_handler; cst_timer.expires = jiffies + HZ; add_timer(&cst_timer); pr_info(DRIVER_DESC " : init on cpu:%d\n", smp_processor_id()); return 0; } module_init(cst_init); static void __exit cst_exit(void) { del_timer_sync(&cst_timer); pr_info(DRIVER_DESC " : exit\n"); } module_exit(cst_exit); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR("sylas "); MODULE_LICENSE("GPL");
另外,再构造一个被中断的受害者:
int main(int argc, char **argv) { int i = 0; while (1) { sqrt (rand ()); if ((i % 0xffffff) == 0) printf ("=\n"); if ((i % 0xfffffff) == 0) printf ("haha......still alive\n"); i++; } return 0; }
测试时先把受害者跑起来,注意,必须把核都占满。然后插入内核模块。
后面就可以看Log了。
sudo tail –f /var/log/messages
结果分析:
系统并没有挂掉,而是每隔一秒打一次call trace。
当然,这里的测试看起来一切OK,但这并不是说可以自由的在中断上下文中调用导致睡眠的内核API,因为我这里给出了一个简单的例子,实际上也有可能导致系统死锁。例如在内核态持有锁的时候被中断,然后发生调度。有兴趣的同学可以自己修改上面的代码实验这种情况。