四季帆 2021-12-03 17:51
浏览 29
已结题

Linux wait_event_timeout()提前超时唤醒

问题遇到的现象和发生背景

在使用wait_event_timeout接口时,我传的参数是定时20毫秒,但是偶尔会出现14毫秒就超时唤醒的情况。

问题相关代码,请勿粘贴截图
wait_event_timeout(tmp_que, flag == 1, msecs_to_jiffies(20));
我的解答思路和尝试过的方法
  1. 第一种可能:因为kernel刚启动时是使用基于tick的低精度定时器,当系统中有合适的高频率clock source注册以后,kernel会切换至高精度定时器,所以我猜测是不是高低精度定时器之间的切换导致了这种情况的偶发,目前从代码层面还没有直接的证据证明,只能是猜测;
  2. 第二种可能:因为该情况是在反复上下电的情况下才偶尔出现,我猜测是硬件clock source偶尔的不稳定导致的,当然仅仅只是猜测。
我想要达到的结果

我个人更倾向于第二种可能,算是一种自我安慰吧,欢迎各位Code people来交流讨论!

附录
#define wait_event_timeout(wq, condition, timeout)            \
({                                    \
    long __ret = timeout;                        \
    if (!(condition))                         \
        __wait_event_timeout(wq, condition, __ret);        \
    __ret;                                \
})

#define __wait_event_timeout(wq, condition, ret)            \
do {                                    \
    DEFINE_WAIT(__wait);                        \
                                    \
    for (;;) {                            \
        prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE);    \
        if (condition)                        \
            break;                        \
        ret = schedule_timeout(ret);                \
        if (!ret)                        \
            break;                        \
    }                                \
    if (!ret && (condition))                    \
        ret = 1;                        \
  //设置当前线程为运行态,并从给定的等待队列中删除等待描述符
    finish_wait(&wq, &__wait);                    \
} while (0)

signed long __sched schedule_timeout(signed long timeout)
{
    struct timer_list timer;
    unsigned long expire;

    switch (timeout)
    {
    case MAX_SCHEDULE_TIMEOUT:
        schedule();
        goto out;
    default:
        if (timeout < 0) {
            printk(KERN_ERR "schedule_timeout: wrong timeout value %lx\n", timeout);
            dump_stack();
            current->state = TASK_RUNNING;
            goto out;
        }
    }

    expire = timeout + jiffies;

    setup_timer_on_stack(&timer, process_timeout, (unsigned long)current);
    __mod_timer(&timer, expire, false, TIMER_NOT_PINNED);   //设置定时时间
    schedule();     //让出CPU进入休眠,timer的callback(即process_timeout)会唤醒当前进程
    del_singleshot_timer_sync(&timer);

    /* Remove the timer from the object tracker */
    destroy_timer_on_stack(&timer);

    timeout = expire - jiffies;

 out:
    return timeout < 0 ? 0 : timeout;
}

static inline int __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only, int pinned)
{
    struct tvec_base *base, *new_base;
    unsigned long flags;
    int ret = 0 , cpu;

    timer_stats_timer_set_start_info(timer);
    BUG_ON(!timer->function);
    base = lock_timer_base(timer, &flags);
    cpu = smp_processor_id();
   ······
    timer->expires = expires;
 //将当前这个timer挂接到合适的链表上,继续跟踪代码会发现,内核根据距离超时的时间长短设置了4个链表(tv1-tv4)
    internal_add_timer(base, timer);  

out_unlock:
    spin_unlock_irqrestore(&base->lock, flags);

    return ret;
}

  • 写回答

0条回答 默认 最新

    报告相同问题?

    问题事件

    • 系统已结题 12月11日
    • 创建了问题 12月3日

    悬赏问题

    • ¥15 爬取网页内容并保存需要完整的python代码
    • ¥30 NIRfast软件使用指导
    • ¥20 matlab仿真问题,求功率谱密度
    • ¥15 求micropython modbus-RTU 从机的代码或库?
    • ¥15 铜与钢双金属板叠加在一起每种材料300mm长,18mm宽,4mm厚一端固定并加热至80℃,当加热端温度保持不变时另一端的稳态温度。ansys
    • ¥15 django5安装失败
    • ¥15 Java与Hbase相关问题
    • ¥15 后缀 crn 游戏文件提取资源
    • ¥15 ANSYS分析简单钎焊问题
    • ¥20 bash代码推送不上去 git fetch origin master #失败了