mod_timer() 内的内核恐慌
Kernel panic inside mod_timer()
我正在编写一个使用多个计时器的程序。每 5 秒,他们将使用一个相同的网络链接与用户空间通信。
更具体地说,每 5 秒每个计时器都会调用一次 func()
,func()
将执行锁定、发送内容、解锁,以及:
delay_us(200);
if(!timer_pending(&timer1)){
mod_timer(&timer1, jiffies+RTL_SECONDS_TO_JIFFIES(5));
}
奇怪的是在极少数情况下,系统会在mod_timer()
里面崩溃,我拆机发现在tne zero,v0,0xc
处崩溃
一段代码(MIPS指令)如下:
/*
* This is a common optimization triggered by the
* networking code - if the timer is re-modified
* to be the same thing then just return:
*/
if (timer_pending(timer) && timer->expires == expires)
800216bc: 8e020000 lw v0,0(s0)
800216c0: 50400005 beqzl v0,800216d8 <mod_timer+0x98>
800216c4: 8e020010 lw v0,16(s0)
800216c8: 8e020008 lw v0,8(s0)
800216cc: 10510042 beq v0,s1,800217d8 <mod_timer+0x198>
800216d0: 24130001 li s3,1
800216d4: 8e020010 lw v0,16(s0)
800216d8: 2c420001 sltiu v0,v0,1
800216dc: 00020336 tne zero,v0,0xc
我调试起来很痛苦。我怀疑计时器竞赛,但从技术上讲,如果是这样,崩溃不应该在 mod_timer()
内,对吗?看起来很可能会发生某种比赛,但这超出了我的知识范围。感谢任何调试建议。
编辑:我只是在下面添加了一些重要的转储消息:
Call Trace:
[<800243a4>] mod_timer+0x9c/0x1b8
[<8002399c>] call_timer_fn+0x20/0x88
[<80023bd0>] run_timer_softirq+0x1cc/0x244
[<8001de80>] __do_softirq+0x118/0x218
[<8001e05c>] do_softirq+0x58/0x78
[<8001e0e0>] irq_exit+0x64/0x80
[<8000044c>] ret_from_irq+0x0/0x4
[<800036cc>] __copy_user_common+0x44/0x2b8
[<8006701c>] file_read_actor+0x9c/0x114
[<8006a47c>] generic_file_aio_read+0x4f4/0x7f4
[<80092f00>] do_sync_read+0x90/0xd4
[<80093fc8>] vfs_read+0xb0/0x158
[<80094170>] SyS_read+0x60/0x9c
[<800017b0>] stack_done+0x20/0x40
Code: 24130001 8e020010 2c420001 <00020336> 02002021 0c008f12 27a50010 8e030000 10600015
编辑:回调函数如下:
void send_info(unsigned long task_priv)
{
unsigned long flags;
struct target_priv *priv = (struct target_priv *)task_priv;
SMP_LOCK(flags);
construct_netlink_send(priv);
SMP_UNLOCK(flags);
delay_us(200);
if ((!strcmp(priv->name, "timer0")) && (!timer_pending(&priv->timer0))){
mod_timer(&priv->timer0, jiffies+SECONDS_TO_JIFFIES(5));
return;
}
...//do same for the rest 9 timers
}
一些建议供您调试此问题。
减少你的计时器计数,确保只有一个计时器时一切正常。
请附上一些紧急信息,也许我可以找到一些有用的信息来帮助您解决问题。
我不确定 "delay_us(200);" 是否会导致问题。定时器回调在软中断内容中,不能被阻塞。所以,你所使用的锁也需要检查一下是否可以屏蔽内容。
此代码可能会导致问题:
if ((!strcmp(priv->name, "timer0")) && (!timer_pending(&priv->timer0))){
mod_timer(&priv->timer0, jiffies+SECONDS_TO_JIFFIES(5));
return;
}
您不能在回调中修改其他计时器。它可能会破坏计时器的 link.
我正在编写一个使用多个计时器的程序。每 5 秒,他们将使用一个相同的网络链接与用户空间通信。
更具体地说,每 5 秒每个计时器都会调用一次 func()
,func()
将执行锁定、发送内容、解锁,以及:
delay_us(200);
if(!timer_pending(&timer1)){
mod_timer(&timer1, jiffies+RTL_SECONDS_TO_JIFFIES(5));
}
奇怪的是在极少数情况下,系统会在mod_timer()
里面崩溃,我拆机发现在tne zero,v0,0xc
一段代码(MIPS指令)如下:
/*
* This is a common optimization triggered by the
* networking code - if the timer is re-modified
* to be the same thing then just return:
*/
if (timer_pending(timer) && timer->expires == expires)
800216bc: 8e020000 lw v0,0(s0)
800216c0: 50400005 beqzl v0,800216d8 <mod_timer+0x98>
800216c4: 8e020010 lw v0,16(s0)
800216c8: 8e020008 lw v0,8(s0)
800216cc: 10510042 beq v0,s1,800217d8 <mod_timer+0x198>
800216d0: 24130001 li s3,1
800216d4: 8e020010 lw v0,16(s0)
800216d8: 2c420001 sltiu v0,v0,1
800216dc: 00020336 tne zero,v0,0xc
我调试起来很痛苦。我怀疑计时器竞赛,但从技术上讲,如果是这样,崩溃不应该在 mod_timer()
内,对吗?看起来很可能会发生某种比赛,但这超出了我的知识范围。感谢任何调试建议。
编辑:我只是在下面添加了一些重要的转储消息:
Call Trace:
[<800243a4>] mod_timer+0x9c/0x1b8
[<8002399c>] call_timer_fn+0x20/0x88
[<80023bd0>] run_timer_softirq+0x1cc/0x244
[<8001de80>] __do_softirq+0x118/0x218
[<8001e05c>] do_softirq+0x58/0x78
[<8001e0e0>] irq_exit+0x64/0x80
[<8000044c>] ret_from_irq+0x0/0x4
[<800036cc>] __copy_user_common+0x44/0x2b8
[<8006701c>] file_read_actor+0x9c/0x114
[<8006a47c>] generic_file_aio_read+0x4f4/0x7f4
[<80092f00>] do_sync_read+0x90/0xd4
[<80093fc8>] vfs_read+0xb0/0x158
[<80094170>] SyS_read+0x60/0x9c
[<800017b0>] stack_done+0x20/0x40
Code: 24130001 8e020010 2c420001 <00020336> 02002021 0c008f12 27a50010 8e030000 10600015
编辑:回调函数如下:
void send_info(unsigned long task_priv)
{
unsigned long flags;
struct target_priv *priv = (struct target_priv *)task_priv;
SMP_LOCK(flags);
construct_netlink_send(priv);
SMP_UNLOCK(flags);
delay_us(200);
if ((!strcmp(priv->name, "timer0")) && (!timer_pending(&priv->timer0))){
mod_timer(&priv->timer0, jiffies+SECONDS_TO_JIFFIES(5));
return;
}
...//do same for the rest 9 timers
}
一些建议供您调试此问题。
减少你的计时器计数,确保只有一个计时器时一切正常。
请附上一些紧急信息,也许我可以找到一些有用的信息来帮助您解决问题。
我不确定 "delay_us(200);" 是否会导致问题。定时器回调在软中断内容中,不能被阻塞。所以,你所使用的锁也需要检查一下是否可以屏蔽内容。
此代码可能会导致问题:
if ((!strcmp(priv->name, "timer0")) && (!timer_pending(&priv->timer0))){
mod_timer(&priv->timer0, jiffies+SECONDS_TO_JIFFIES(5));
return;
}
您不能在回调中修改其他计时器。它可能会破坏计时器的 link.