我正在编写一个内核模块,它设置一个定时器,在一段时间后调用模块中的回调函数。 代码如下:
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
完全返回之前,是否有好方法可以保持模块加载?
答案 0 :(得分:0)
简单的解决方案可以正常工作,因为在中断上下文中调用timeout_cb()
,虽然我不确定这是常规方法。
答案 1 :(得分:0)
在module_exit
功能中,您需要停用计时器。您可以使用
timer_del_sync(&test_timer);
这将保证计时器的回调在返回时不会被执行。因此,只有两种变体是可能的:
在执行回调之前,计时器已停用。由于停用,回调执行将永远不会发生。
计时器已停用且回叫已完成。
您可以将此方法与module_put
/ try_module_get
结合使用,因此无论如何都会执行回调。