critical section 中断唤醒系统流程(10)

电脑杂谈  发布时间:2018-02-14 08:19:48  来源:网络整理

{

struct gpio_button_data *bdata = dev_id;

mod_delayed_work(system_wq,

&bdata->work,

msecs_to_jiffies(bdata->software_debounce));

return IRQ_HANDLED;

}

当按键按下,中断handler gpio_keys_gpio_isr执行,设定delayed work的定时器,等到定时器计时结束执行gpio_keys_gpio_work_func(),在gpio_keys_gpio_work_func()上报键值。你有考虑过一个问题吗?加入系统已经睡眠,此时第一次按下按键,有可能出现gpio_keys_gpio_work_func()函数没有执行,系统又继续睡眠,在第二次按键的时候执行第一次按键应该调用的gpio_keys_gpio_work_func()的情况吗?其实是有可能出现。只要bdata->software_debounce大于一定的时间就有可能出现。如果这个时间巧合,还有可能出现有时候正确上报,有时候没有上报。其实原因就是,内核的suspend只保证了IRQ handler的执行完成,并没有保证工作队列的执行完毕。

这里说的问题是work_queue没有机会调度,系统就休眠了。如果使用的不是delayed work,就是普通的work,只是在work中使用类似msleep的操作,系统是否也会继续睡眠呢?修改代码如下:

static void gpio_keys_gpio_work_func(struct work_struct *work)

{

struct gpio_button_data *bdata =

container_of(work, struct gpio_button_data, work.work);

msleep(1000);

gpio_keys_gpio_report_event(bdata);

}

static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id)

{

struct gpio_button_data *bdata = dev_id;

schedule_work(&bdata->work);

return IRQ_HANDLED;

}

这里的gpio_keys_gpio_work_func()中添加一句msleep(1000)会怎么样呢?由于此时使用的不是delayed work,因此一般不会出现没有调度work就睡眠的情况,与上面的情况还是有点区别的。但是这里其实也是有可能睡眠的,一旦msleep(1000)语句执行完毕,系统满足sleep条件,此时系统还是有可能睡眠导致后面的操作没有执行。critical section在下次唤醒系统的时候才可能执行。所以这种情况下也是危险的。

结论就是:内核的suspend只保证了IRQ handler(hardirq handler or threaded handler)的执行完成,并没有保证工作队列的执行完毕。因此我们使用工作队列的话,必须要考虑这种情况的发生,并解决。

2.9. 如何解决工作队列睡眠问题?

系统suspend的过程中,主要是通过pm_wakeup_pending()判断suspend时候需要abort。如果你对我说的这一块不清楚,可以看看wowo其他几篇关于电源管理的文章。pm_wakeup_pending()主要是判断combined_event_count变量在suspend的过程中是否改变,如果改变suspend就应该abort。既然知道了原理,那么就好办了。在中断handler开始处增加combined_event_count计数,在处理完成工作队列的事情减小combined_event_count计数即可。当然是不用你自己写代码,系统提供了接口函数pm_stay_awake()和pm_relax()。2.8节修改后的代码如下:


本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-77055-10.html

相关阅读
    发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

    热点图片
    拼命载入中...