有没有好的方法来保持内核模块加载,直到相关的计时器回调返回

时间:2017-03-09 00:45:25

标签: c timer linux-kernel linux-device-driver kernel-module

我正在编写一个内核模块,它设置一个定时器,在一段时间后调用模块中的回调函数。 代码如下:

static struct timer_list test_timer;
static void timeout_cb(unsigned long data)
{
    printk("cb called\n");
}    
static int __init timer_module_init( void )
{
    init_timer(&test_timer);
    test_timer.expires = jiffies + HZ*5;
    test_timer.data = 0;
    test_timer.function = timeout_cb;
    add_timer(&test_timer);
    return 0;
}

我认为如果在调用回调函数之前卸载模块,系统将挂起。而且,这实际上发生了。

# insmod timer_test.ko && lsmod | grep timer_test && rmmod timer_test.ko
timer_test              1034  0 ### No ref count to the module
### After some seconds, the system hung up 

我认为这个问题的一个简单解决方案是在add_timer()之前递增模块的引用计数,并在timeout_cb()结束时递减它,这会使模块加载到{{1}结束。

timeout_cb()

这似乎工作正常,但严格来说,如果在static void timeout_cb(unsigned long data) { printk("cb called\n"); module_put(THIS_MODULE); // decrementing ref count } static int __init timer_module_init( void ) { ... try_module_get(THIS_MODULE); // incrementing ref count add_timer(&test_timer); return 0; } 返回后但在module_put()返回之前卸载模块,系统将挂断。

timeout_cb()

//objdump static void timeout_cb(unsigned long data) { 0: 55 push %rbp 1: 48 89 e5 mov %rsp,%rbp 4: e8 00 00 00 00 callq 9 <timeout_cb+0x9> 9: 48 c7 c7 00 00 00 00 mov $0x0,%rdi 10: 31 c0 xor %eax,%eax 12: e8 00 00 00 00 callq 17 <timeout_cb+0x17> printk("cb called\n"); module_put(THIS_MODULE); 17: 48 c7 c7 00 00 00 00 mov $0x0,%rdi 1e: e8 00 00 00 00 callq 23 <timeout_cb+0x23> } // I think the system would hang up if the module is unloaded here. 23: c9 leaveq 24: c3 retq 25: 90 nop 完全返回之前,是否有好方法可以保持模块加载?

2 个答案:

答案 0 :(得分:0)

简单的解决方案可以正常工作,因为在中断上下文中调用timeout_cb(),虽然我不确定这是常规方法。

参考:http://www.makelinux.net/ldd3/chp-7-sect-4

答案 1 :(得分:0)

module_exit功能中,您需要停用计时器。您可以使用

以同步方式执行此操作
timer_del_sync(&test_timer);

这将保证计时器的回调在返回时不会被执行。因此,只有两种变体是可能的:

  1. 在执行回调之前,计时器已停用。由于停用,回调执行将永远不会发生。

  2. 计时器已停用且回叫已完成。

  3. 您可以将此方法与module_put / try_module_get结合使用,因此无论如何都会执行回调。