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
}

一些建议供您调试此问题。

  1. 减少你的计时器计数,确保只有一个计时器时一切正常。

  2. 请附上一些紧急信息,也许我可以找到一些有用的信息来帮助您解决问题。

  3. 我不确定 "delay_us(200);" 是否会导致问题。定时器回调在软中断内容中,不能被阻塞。所以,你所使用的锁也需要检查一下是否可以屏蔽内容。

此代码可能会导致问题:

if ((!strcmp(priv->name, "timer0")) && (!timer_pending(&priv->timer0))){
            mod_timer(&priv->timer0, jiffies+SECONDS_TO_JIFFIES(5));
                return;
        }

您不能在回调中修改其他计时器。它可能会破坏计时器的 link.