内核模块计时器杀死系统

时间:2014-06-05 14:22:48

标签: c timer linux-kernel

我想用计时器多次调用一个函数。 为了实现这一点,我使用了this示例。默认情况下它没有任何错误。

当我将此代码段集成到源代码中时,会导致内核崩溃(?)。有一个很长的错误,虚拟机停止工作 。

控制台上印有错误:

[ 1130.520474]  [<c12bf6ae>] ? no_context+0x14b/0x155       
[ 1130.520474]  [<c12bf7ca>] ? bad_area_nosemaphore+0xa/0xc                     
[ 1130.520474]  [<c12c7370>] ? do_page_fault+0x1bf/0x35e
[ 1130.520474]  [<c100d6bf>] ? show_trace_log_lvl+0x37/0x3d                     
[ 1130.520474]  [<c12c71b1>] ? vmalloc_fault+0x87/0x87                     
[ 1130.520474]  [<c12c5377>] ? error_code+0x67/0x6c                             
[ 1130.520474]  [<c12c306e>] ? __schedule+0x31/0x5a4                            
[ 1130.520474]  [<c100fa07>] ? sched_clock+0x9/0xd      
[ 1130.520474]  [<c1051896>] ? sched_clock_local+0x10/0x14b
[ 1130.520474]  [<c102abe2>] ? test_tsk_need_resched+0xa/0x13
[ 1130.520474]  [<c102abe2>] ? test_tsk_need_resched+0xa/0x13              
[ 1130.520474]  [<c102e59c>] ? check_preempt_curr+0x48/0x58                     
[ 1130.520474]  [<c121f462>] ? __napi_complete+0x1b/0x22                        
[ 1130.520474]  [<c12213f0>] ? napi_complete+0x25/0x31
[ 1130.520474]  [<f825d2d6>] ? e1000_clean+0x33e/0x35c [e1000]
[ 1130.520474]  [<c105daf5>] ? arch_local_irq_save+0xf/0x14
[ 1130.520474]  [<c12c45a2>] ? _raw_spin_lock_irq+0x9/0x12                 
[ 1130.520474]  [<c1042307>] ? run_timer_softirq+0x1eb/0x1f3                   
[ 1130.520474]  [<c107b86c>] ? __rcu_process_callbacks+0x5f/0x252              
[ 1130.520474]  [<c103cfdb>] ? local_bh_enable+0x2/0x2               
[ 1130.520474]  [<c103d0dc>] ? __do_softirq+0x101/0x12f
[ 1130.520474]  [<c103c6e8>] ? __local_bh_enable+0x37/0x67                      
[ 1130.520474]  <IRQ>  [<c10cd712>] ? sys_write+0x58/0x61                       
[ 1130.520474]  [<c12c8e5f>] ? sysenter_do_call+0x12/0x28  

我想我的问题是在返回上一个之前触发了一个新的调用。

为了测试这个,我修改了上面引用的计时器玩具示例:

int i;

void timer1_routine(unsigned long data)
{
    int no;
    no=i;
    i++;
    printk(KERN_INFO "process %d starts",no);

    msleep(5000);

    printk(KERN_INFO "process %d ends",no);

    mod_timer(&timer1, jiffies + HZ); /* restarting timer */
}

这会导致同样的错误,所以我认为我的猜测是对的:调用之间存在冲突。我的问题是,如果我不知道函数的执行需要多长时间,我该如何避免这个问题?

1 个答案:

答案 0 :(得分:3)

linux内核有两种主要的上下文类型:进程上下文和原子上下文。您已经习惯了在流程上下文中运行的事物。原子上下文主要用于中断,包括硬件和软件。内核定时器从软件中断(原子上下文)运行。在原子上下文中运行的代码有许多限制,包括禁止睡眠。这解释了崩溃。

你几乎肯定想要一个workqueue而不是一个计时器。 Workqueue函数在进程上下文中执行,因此您可以进入休眠状态。如果您要在内核的这个级别工作,那么您真的需要阅读LDD3的这一章:http://lwn.net/images/pdf/LDD3/ch07.pdf