Linux 内核完成接口
发布日期:2021-06-30 18:45:57
浏览次数:3
分类:技术文章
本文共 3935 字,大约阅读时间需要 13 分钟。
Linux 内核里面有一个函数wait_for_completion,这是一个内核同步机制的函数,同步机制如果是早期的读者应该看过我发的文章,如果没有看过的可以看看Linux 专辑文章里面找找。
既然是同步机制,主要的工作就是调用了这个函数,程序就会等另外的事件完成之后再继续下面的工作。
wait_for_completion 结构体
/* * struct completion - structure used to maintain state for a "completion" * * This is the opaque structure used to maintain the state for a "completion". * Completions currently use a FIFO to queue threads that have to wait for * the "completion" event. * * See also: complete(), wait_for_completion() (and friends _timeout, * _interruptible, _interruptible_timeout, and _killable), init_completion(), * reinit_completion(), and macros DECLARE_COMPLETION(), * DECLARE_COMPLETION_ONSTACK(). */struct completion { unsigned int done; wait_queue_head_t wait;};
结构体里面就两个东西,一个是 done,一个是队列wait。
还有他相关的函数
complete()wait_for_completion() init_completion()reinit_completion()DECLARE_COMPLETION()DECLARE_COMPLETION_ONSTACK().
如何使用?
先声明
struct completion bl_ready;init_completion(&ts->bl_ready);
需要等待退出的线程
static irqreturn_t cyttsp_irq(int irq, void *handle){ struct cyttsp *ts = handle; int error; /*退出的时候会设置为CY_BL_STATE*/ /*在这里做判断*/ if (unlikely(ts->state == CY_BL_STATE)) { complete(&ts->bl_ready); goto out; }}
退出时候调用
static int cyttsp_soft_reset(struct cyttsp *ts){ unsigned long timeout; int retval; /* wait for interrupt to set ready completion */ reinit_completion(&ts->bl_ready); /*退出的时候会设置为 CY_BL_STATE*/ ts->state = CY_BL_STATE; enable_irq(ts->irq); retval = ttsp_send_command(ts, CY_SOFT_RESET_MODE); if (retval) goto out; timeout = wait_for_completion_timeout(&ts->bl_ready, msecs_to_jiffies(CY_DELAY_DFLT * CY_DELAY_MAX)); retval = timeout ? 0 : -EIO;out: ts->state = CY_IDLE_STATE; disable_irq(ts->irq); return retval;}
里面的实现细节
三个函数的流程
init_completion 初始化
我们看init 初始化的代码
static inline void init_completion(struct completion *x){ x->done = 0; init_waitqueue_head(&x->wait);}static inline void reinit_completion(struct completion *x){ x->done = 0;}
初始化的时候,把done这个变量设置为 0 。
wait_for_completion_timeout 的调用流程
static inline long __scheddo_wait_for_common(struct completion *x, long (*action)(long), long timeout, int state){ /*如果done是0就跑到if里面去,也就说明我们等的事件还没完成*/ if (!x->done) { DECLARE_WAITQUEUE(wait, current); __add_wait_queue_tail_exclusive(&x->wait, &wait); do { if (signal_pending_state(state, current)) { timeout = -ERESTARTSYS; break; } __set_current_state(state); spin_unlock_irq(&x->wait.lock); timeout = action(timeout);/*休眠timeout时间等待*/ spin_lock_irq(&x->wait.lock); } while (!x->done && timeout);/*如果事件完成了就提出*/ __remove_wait_queue(&x->wait, &wait); if (!x->done) return timeout; } x->done--; return timeout ?: 1;}
内核里面有非常多这样的小代码,我觉得看这样的代码非常有意思,你需要不断的去揣摩它,品味它。
这段代码的主要工作就是在超时时间内判断done的值已经大于0,然后退出,退出的时候把done 减去1。
总结
文章里面的实例是从一个touch驱动里面提取出来的,它的目的是为了reset触摸屏的时候,确保中断线程已经完全退出了,在中断线程里面有操作touch I2C的操作,如果reset的时候,线程还没有跑完,驱动就会可能收到I2C报错的异常。
error = request_threaded_irq(ts->irq, NULL, cyttsp_irq, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, pdata->name, ts);
内核完成补丁
这份补丁是用来修复do_wait_for_common 这个函数的,看注释的作用就是用一行代码代替了几行代码。内核专家做了修正,贴出来方便大家加深理解。
Change do_wait_for_common() to use signal_pending_state() instead ofopen coding.Signed-off-by: Oleg Nesterov--- 26-rc2/kernel/sched.c~1_SPS_WAIT_FOR 2008-07-22 18:36:58.000000000 +0400+++ 26-rc2/kernel/sched.c 2008-07-24 19:54:12.000000000 +0400@@ -4735,10 +4735,7 @@ do_wait_for_common(struct completion *x,wait.flags |= WQ_FLAG_EXCLUSIVE;__add_wait_queue_tail(&x->wait, &wait);do {- if ((state == TASK_INTERRUPTIBLE &&- signal_pending(current)) ||- (state == TASK_KILLABLE &&- fatal_signal_pending(current))) {+ if (signal_pending_state(state, current)) {timeout = -ERESTARTSYS;break;}--To unsubscribe from this list: send the line "unsubscribe linux-kernel" inthe body of a message to majordomo@xxxxxxxxxxxxxxxMore majordomo info at http://vger.kernel.org/majordomo-info.htmlPlease read the FAQ at http://www.tux.org/lkml/
推荐阅读:
嵌入式Linux
微信扫描二维码,关注我的公众号
转载地址:https://linus.blog.csdn.net/article/details/107171447 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
做的很好,不错不错
[***.243.131.199]2024年04月05日 22时17分24秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
PyPy
2019-04-30
打印CSDN文章
2019-04-30
MATLAB与CUDA
2019-04-30
Linux png转jpg (convert命令)
2019-04-30
NAS (Network Attached Storage 网络附属存储)
2019-04-30
Ubuntu更新后终端中字体的颜色全是白色
2019-04-30
Ninja
2019-04-30
lmdb数据库的读取与转换(一) —— 基本操作
2019-04-30
opencv相关操作(cv2) (python)
2019-04-30
lmdb数据库的读取与转换(二) —— 数据集操作
2019-04-30
Lua语言
2019-04-30
Python __doc__获得模块的文档字符串内容
2019-04-30
Python sys.path和模块搜索路径
2019-04-30
github.io网页无法打开(连接不是私密连接)
2019-04-30
git submodule
2019-04-30
linux中source、sh、bash、./有什么区别
2019-04-30
vscode git
2019-04-30
基于MATLAB的二进制数字调制与解调信号的仿真——2FSK
2019-04-30
基于MATLAB的二进制数字调制与解调信号的仿真——2PSK
2019-04-30