-
2021-05-10 20:22:34
我正在处理i2c-omap驱动程序的一个奇怪问题。我不确定问题是否在其他时间发生,但是当我尝试关闭系统时发生了大约5%的问题。 在系统关机期间,我通过I2C写入PMIC中的某些寄存器。在i2c-omap.c中,我可以看到调用线程正在等待wait_for_completion_timeout,超时值设置为1秒。我可以看到称为“完整”的IRQ(我在完成后添加了printk)。但是,在“完成”被调用之后,wait_for_completion_timeout没有返回。相反,它在返回之前最多需要5分钟。 wait_for_completion_timeout的返回值为正数,表示没有超时。整个I2C交易成功了。Linux内核的wait_for_completion_timeout未完全唤醒
与此同时,我可以看到来自其他驱动程序的printk消息。串口控制台仍然可以工作。它在Android上,如果我使用“top”,我可以看到system_server占用了大约95%的CPU。 kill system_server可以立即返回wait_for_completion_timeout。
所以我的问题是用户空间应用程序(system_server)可以做什么来使内核“wait_for_completion_timeout”不被唤醒?
谢谢!
2012-11-21
Jun Li
+0
你能粘贴相关的代码吗? –
+0
事情是我不知道什么是“有关”。代码调用wait_for_completion并且大部分时间完成。这很少发生。 :( –
更多相关内容 -
Linux内核API wait_for_completion_timeout
2021-09-02 15:48:48wait_for_completion_timeout函数功能描述:此函数用于阻塞当前进程,等待其他进程的执行结束,被等待进程保存在输入参数的wait字段所代表的等待队列中。有两种情况可以结束此种等待:第一,当等待队列中的进程被...概述
wait_for_completion_timeout函数功能描述:此函数用于阻塞当前进程,等待其他进程的执行结束,被等待进程保存在输入参数的wait字段所代表的等待队列中。有两种情况可以结束此种等待:第一,当等待队列中的进程被函数complete( )或函数complete_all( )唤醒,等待结束,阻塞进程将继续执行;第二,当等待的时钟节拍超时时,被阻塞的进程会继续执行。
此函数将当前进程设置为不可中断的等待状态,所以即使通过Ctrl+C组合键也不能强制结束等待;此函数设置的等待时间是函数的第二个参数所代表的系统时钟节拍数,这个时间是可以更改的。
文章目录
- 1 wait_for_completion_timeout文件包含
- 2 wait_for_completion_timeout函数定义
- 3 wait_for_completion_timeout实例解析
wait_for_completion_timeout文件包含
#include <linux/completion.h>
C
wait_for_completion_timeout函数定义
在内核源码中的位置:linux-3.19.3/kernel/sched/completion.c
函数定义格式:
unsigned long __sched wait_for_completion_timeout(struct completion*x, unsigned long timeout)
wait_for_completion_timeout输入参数说明
此函数的第一个输入参数是struct completion结构体类型的指针,包含一个等待队列信息及等待队列的状态信息,等待队列的状态代表此等待队列是否被唤醒过,其定义及详细解释参考函数complete( )分析文档的输入参数说明部分。
此函数的第二个输入参数是unsigned long型的变量,代表等待的时钟节拍数,当等待的时钟节拍数超过此值时,被阻塞的进程将继续执行。
wait_for_completion_timeout返回参数说明
此函数的返回结果是unsigned long型的变量,代表剩余的系统时钟节拍数,即传入的第二个参数所代表的时钟节拍数与等待进程结束消耗的时钟节拍之差。如果等待是正常结束,则返回值的范围在0到函数的第二个输入参数值之间。
wait_for_completion_timeout实例解析
编写测试文件:wait_for_completion_timeout.c
头文件引用及全局变量定义:
/*头文件引用*/ #include <linux/module.h> #include <linux/sched.h> #include <linux/pid.h> #include <linux/wait.h> #include <linux/completion.h> #include <linux/kthread.h> MODULE_LICENSE("GPL"); /*全局变量定义*/ static struct completion comple; //用于保存completion的状态 static struct task_struct * old_thread; //保存初始化进程信息
子进程处理函数定义:
int my_function(void * argc) { wait_queue_head_t head; wait_queue_t data; printk("in the kernel thread function! \n"); init_waitqueue_head(&head); //初始化等待队列头元素 init_waitqueue_entry(&data, current); //用当前进程初始化等待队列元素 add_wait_queue(&head, &data); //将当前进程插入到等待队列中 schedule_timeout_uninterruptible(10); //将等待队列置于不可中断的等待状态 printk("the current pid is:%d\n", current->pid); //显示当前进程的PID值 printk("the state of the real_parent is :%ld\n", old_thread->state); //显示父进程的状态 //complete(&comple); //调用函数唤醒进程,并更改done字段的值 printk("out the kernel thread function\n"); return 0; }
模块加载函数定义:
static int __init wait_for_completion_timeout_init(void) { struct task_struct * result; long leavetime; wait_queue_t data; printk("into wait_for_completion_timeout_init.\n"); old_thread = current; result=kthread_create_on_node(my_function, NULL, -1, "wait_for_completion_timeout"); // 创建新进程 wake_up_process(result); init_completion(&comple); //初始化completion变量 init_waitqueue_entry(&data, result); //用新进程初始化等待队列元素 __add_wait_queue_tail(&(comple.wait), &data); //将新进程加入等待队列的尾部 leavetime=wait_for_completion_timeout(&comple,100); //阻塞进程,等待新进程的结束 /*显示函数wait_for_completion_timeout( )的返回结果*/ printk("the result of the wait_for_completion_timeout is:%ld\n", leavetime); /*显示函数kernel_thread( )函数的返回结果*/ printk("the pid of new thread is :%d\n", result->pid); printk("the current pid is:%d\n", current->pid); //显示当前进程的PID值 printk("out wait_for_completion_timeout_init.\n"); return 0; }
模块退出函数定义:
static void __exit wait_for_completion_timeout_exit(void) { printk("Goodbye wait_for_completion_timeout\n"); }
模块加载、退出函数调用:
module_init(wait_for_completion_timeout_init); module_exit(wait_for_completion_timeout_exit);
实例运行结果及分析:
首先编译模块,执行命令insmod wait_for_completion_timeout.ko插入内核模块,此时终端会出现短暂的停顿,因为进程阻塞所至,当终端恢复命令行模式时,输入命令dmesg -c会出现如图
A
所示的结果。去掉子进程处理函数中对语句“complete(&comple); ”的注释,保存文件,重新编译、加载模块,此时不会出现终端短暂的停顿的现象,输入命令dmesg -c,会出现如图
B
所示的结果。结果分析:
从图
A
和图B
可以看出在子进程执行时父进程的状态值都是2,即父进程处于不可中断的等待状态,并且子进程都在父进程之前执行完毕,父进程会等待子进程的执行完毕。图
A
中显示函数wait_for_completion_timeout( )的返回结果是0,可以推测此等待是正常结束的,实际情况是因等待超时而程序正常运行结束的。图
B
中显示函数wait_for_completion_timeout( )的返回结果是90,可以推测等待是正常结束的,实际情况是通过调用函数complete( )唤醒等待队列中的进程,使等待提前结束,返回结果90是等待剩余的时钟节拍数,所消耗的时钟节拍数是10。说明
对于子进程处理函数中调用函数schedule_timeout_uninterruptible( )使子进程进入短暂的睡眠,是为了保证父进程中的函数wait_for_completion( )能够在子进程中显示父进程状态之前被执行,从而能看到函数wait_for_completion( )对当前进程的作用。进程状态说明:
对于进程能够处于的状态,在函数__wake_up( )的进程状态说明部分有详细的说明。
-
wait_for_completion_timeout 超时返回0 的问题
2016-06-16 19:13:37"kernel/sched/core.c" ...3420 * wait_for_completion_timeout: - waits for completion of a task (w/timeout) 3421 * @x: holds the state of this particular completion 3422 * @timeout: t"kernel/sched/core.c"
3419 /**
3420 * wait_for_completion_timeout: - waits for completion of a task (w/timeout)
3421 * @x: holds the state of this particular completion
3422 * @timeout: timeout value in jiffies
3423 *
3424 * This waits for either a completion of a specific task to be signaled or for a
3425 * specified timeout to expire. The timeout is in jiffies. It is not
3426 * interruptible.
3427 *
3428 * The return value is 0 if timed out, and positive (at least 1, or number of
3429 * jiffies left till timeout) if completed.
3430 */
3431 unsigned long __sched
3432 wait_for_completion_timeout(struct completion *x, unsigned long timeout)
3433 {
3434 return wait_for_common(x, timeout, TASK_UNINTERRUPTIBLE);
3435 }
3436 EXPORT_SYMBOL(wait_for_completion_timeout);
3437
返回0 就是超时,我试试把time out 设置大一些看看是否会好点。
-
Linux下wait_for_completion引起的开机定屏
2020-07-12 17:34:58} static long __sched wait_for_common(struct completion *x, long timeout, int state) { return __wait_for_common(x, schedule_timeout, timeout, state); } static inline long __sched __wait_for_common...新的项目,编译代码,烧写到主板后,主板能起来,但就是进入不了主界面(通过vysor同屏查看)。这是比较少见的,怀疑是编译代码时哪里弄错了,但再三检查也没发现问题,将固件烧写到其他项目的主板上能正常起来,那就不是代码的问题了。
先看内核log,init进程一直在启动camera服务,但到了600s都没启动成功。
查看死掉的进程
root@G480:/home/w# adb shell ps -AT|grep -e "D" -e "Z" -e "R" USER PID TID PPID VSZ RSS WCHAN ADDR S CMD root 69 69 2 0 0 mbox_send_thread 0 D mbox-send-threa root 72 72 2 0 0 monitor_irqs_change 0 D irqs_change root 232 232 2 0 0 0 0 R sugov:0 root 419 689 1 2424672 8708 poll_schedule_timeout 0 S SkDestroyListen root 420 4678 1 5456024 177276 futex_wait_queue_me 0 S HeapTaskDaemon root 420 4679 1 5456024 177276 futex_wait_queue_me 0 S ReferenceQueueD root 420 4680 1 5456024 177276 futex_wait_queue_me 0 S FinalizerDaemon root 421 1451 1 1768180 161488 futex_wait_queue_me 0 S HeapTaskDaemon root 421 1452 1 1768180 161488 futex_wait_queue_me 0 S ReferenceQueueD root 421 1453 1 1768180 161488 futex_wait_queue_me 0 S FinalizerDaemon cameraserver 427 427 1 71428 18752 sprd_i2c_handle_msg 0 D android.hardwar
刚好有个camerasever用户处在D状态,sprd_i2c_handle_msg应该是正在执行的函数。一下子明白了,i2c卡死导致无法进入系统(之前有遇到类似的case)。查看摄像头代码默认使用了i2c0和i2c1,我们的主板i2c1还接了其他外设,也就可能是设备没上电导致i2c信号被拉低,导致系统初始化话摄像头的时候,引起系统卡死。修改代码,屏蔽i2c1后,系统能进入主界面了。调过qcom,mtk的主板,都没有遇到类似的情况,只有展讯平台才遇到过,遇到过几次了,于是提个cq问下展讯。他们回复是符合协议的,非平台特有。直觉告诉我那里不对,如果是i2c设备共性,那所有的平台都有类似的情况,但调的其他平台就没有遇到,难道是运气好。
找代码看下
i2c-sprd.c « busses « i2c « drivers - kernel/git/torvalds/linux.git - Linux kernel source tree
看下sprd_i2c_handle_msg(ps -AT有看到该函数),看到wait_for_completion函数没
static int sprd_i2c_handle_msg(struct i2c_adapter *i2c_adap, struct i2c_msg *msg, bool is_last_msg) { struct sprd_i2c *i2c_dev = i2c_adap->algo_data; i2c_dev->msg = msg; i2c_dev->buf = msg->buf; i2c_dev->count = msg->len; reinit_completion(&i2c_dev->complete); sprd_i2c_reset_fifo(i2c_dev); sprd_i2c_set_devaddr(i2c_dev, msg); sprd_i2c_set_count(i2c_dev, msg->len); if (msg->flags & I2C_M_RD) { sprd_i2c_opt_mode(i2c_dev, 1); sprd_i2c_send_stop(i2c_dev, 1); } else { sprd_i2c_opt_mode(i2c_dev, 0); sprd_i2c_send_stop(i2c_dev, !!is_last_msg); } /* * We should enable rx fifo full interrupt to get data when receiving * full data. */ if (msg->flags & I2C_M_RD) sprd_i2c_set_fifo_full_int(i2c_dev, 1); else sprd_i2c_data_transfer(i2c_dev); sprd_i2c_opt_start(i2c_dev); wait_for_completion(&i2c_dev->complete); return i2c_dev->err; }
那什么时候发complete信号呢
static irqreturn_t sprd_i2c_isr_thread(int irq, void *dev_id) { .... complete(&i2c_dev->complete); ... }
也就是i2c控制器中断来了,就发中complete信号,如果中断信号不过来,那sprd_i2c_handle_msg就一直卡住。
看下wait_for_completion函数实现,也就是没有信号过来,一直schedule(主动让出cpu),直到信号过来。
#define MAX_SCHEDULE_TIMEOUT LONG_MAX void __sched wait_for_completion(struct completion *x) { wait_for_common(x, MAX_SCHEDULE_TIMEOUT, TASK_UNINTERRUPTIBLE); } static long __sched wait_for_common(struct completion *x, long timeout, int state) { return __wait_for_common(x, schedule_timeout, timeout, state); } static inline long __sched __wait_for_common(struct completion *x, long (*action)(long), long timeout, int state) { timeout = do_wait_for_common(x, action, timeout, state); } static inline long __sched do_wait_for_common(struct completion *x, long (*action)(long), long timeout, int state) { 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); 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; } signed long __sched schedule_timeout(signed long timeout) { switch (timeout) { case MAX_SCHEDULE_TIMEOUT: /* * These two special cases are useful to be comfortable * in the caller. Nothing more. We could take * MAX_SCHEDULE_TIMEOUT from one of the negative value * but I' d like to return a valid offset (>=0) to allow * the caller to do everything it want with the retval. */ schedule(); goto out; } out: return timeout < 0 ? 0 : timeout; }
再看下mtk或qcom的驱动
i2c-mt65xx.c « busses « i2c « drivers - kernel/git/torvalds/linux.git - Linux kernel source tree
i2c-qcom-geni.c « busses « i2c « drivers - kernel/git/torvalds/linux.git - Linux kernel source tree
使用的是wait_for_completion_timeout函数,如
static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,u32 m_param) { unsigned long time_left; time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT); if (!time_left) geni_i2c_abort_xfer(gi2c); return gi2c->err; }
即使没有信号过来,i2c也不会卡住。
当然,这个bug已提给他们,后续版本会加入超时机制。
-
Linux下wait_for_completion函数分析
2020-09-19 11:53:10wait_for_completion_timeout(&tx_done_complete,msecs_to_jiffies(100)); complete(&tx_done_complete); 分析围绕这三个函数进行 init_completion struct completion { unsigned int done; wait_... -
linux kernel中的wait_for_completion和complete总结
2020-12-23 19:23:48文章目录结构体init_completioncompletewait_for_completion 结构体 struct completion { unsigned int done; wait_queue_head_t wait; }; #define UINT_MAX (~0U) init_completion #define init_completion(x) ... -
进程调度 – Linux内核API wait_for_completion
2021-05-12 08:55:34wait_for_completion函数功能描述:此函数用于阻塞当前进程,等待其他进程的执行结束,被等待进程保存在输入参数的wait字段所代表的等待队列中,只有当等待队列中的进程被函数complete( )或complete_all( )唤醒之后... -
wait_for_completion_timeout 的返回值
2011-08-13 12:40:14引用一段话: 来自:http://blog.csdn.net/fudan_abc/article/details/1822034 我们需要知道的是怎么去判断等待的结果,也就是wait_for_completion_timeout的返回值代表什么意思?一般来说,一个函数返回 -
进程调度API之wait_for_completion_x
2017-12-18 08:30:39wait_for_completion_x 是一系列函数用于等待完成量释放task,这里以常见的wait_for_completion为例 void __sched wait_for_... wait_for_common(x, MAX_SCHEDULE_TIMEOUT, TASK_UNINTERRUPTIBLE); } 继续调用wa -
Linux 内核Complete和wait_for_completion
2014-11-11 14:45:181. Linux中很多同步机制,completion是 -
linux 同步机制之complete wait_for_completion
2014-01-06 10:18:45在Linux内核中,completion是一种简单的同步机制,标志"things may proceed"。 要使用completion,必须在文件中包含,同时创建一个类型为struct completion的变量。 [cpp] view plaincopy 这个... -
对wait_timeout引发的问题的分析及解决办法
2020-03-21 13:59:52美好的清晨遇到一到莫名的错误。 MySQL连接错误,具体报错信息如下: The last packet sent successfully to the server ... is longer than the server configured value of 'wait_timeout'. You should consider e... -
completion
2014-01-20 21:03:59struct completion { unsigned int done; wait_queue_head_t wait;//等待队列头 }; 2 初始化 2.1 动态 static inline void init_completion(struct completion *x) { x->done = 0; init_waitqueue_head(&x->wai -
内核完成变量completion的原理
2020-08-07 23:59:11一结构体变量定义: 25 struct completion { 26 unsigned int done; //决定进程是否睡眠等待 ...91 extern void wait_for_completion(struct completion *); 92 extern void wait_for_completion_... -
wait_event与wait_event_interruptible的区别
2020-04-02 10:32:21wait_event与wait_event_interruptible有什么区别? 最近在项目,被报了一个log,然后就思考到了这个问题: wait_event_interruptible将当前进程的状态设置成TASK_INTERRUPTIBLE。 wait_event将当前进程的状态设置... -
linux kernel 同步机制 -- completion完成量
2020-08-05 20:59:39线程间的 同步大多使用completion信号量,而互斥资源的保护大多使用自旋锁和互斥锁。. 该篇文章主要讲解的是completion完成量。也算是信号量中的一种。 completion信号量是一个轻量级的机制,它允许一个线程告诉另一... -
31 completion完成量,wait_queue_head_t等待队列和epoll
2017-06-13 10:50:19完成量, 功能与信号量差不多, 最大不同可以唤醒多个休眠的进程或线程#include <linux/completion.h> struct completion { unsigned int done; //done表示资源,上锁时done--. 当done为0时再上锁则会... wait_queue_ -
linux一些机制的总结
2012-06-15 21:48:381. Work 将任务添加到系统的工作队列中 Struct work_struct cd_wq; INIT_WORK(&cd_wq,work_func);...实际上工作队列就是一个进程,添加到工作队列中就是调度的时候运行 ...#define DELAY_TIME 1 -
提交并发请求时使用FUNCTION FND_CONCURRENT.WAIT_FOR_REQUEST等待子并发程序完成
2016-07-22 10:04:38在提交并发请求的时候,有些情况需要调用其他的并发程序去处理相应的事务,此时父并发请求进入等待状态,当子程序完成之后接着去处理其他的业务,为了实现这种情况需要使用到FUNCTION FND_CONCURRENT.WAIT_FOR_... -
【内核同步机制】深入理解Linux内核 -- completion机制
2020-12-17 22:32:29completion 机制 在linux内核中,引入锁机制主要是解决资源并发与竞争问题; 主要常用锁机制:信号量,自旋锁,互斥锁; 该篇文章主要讲解的是completion信号量。... struct swait_queue_head wait; } -
等待队列&&完成量completion
2019-03-13 11:09:302. 完成量completion 1. 等待队列 等待队列(wait queue)用于使进程等待某一特定事件发生,而无须频繁轮询。进程在等待期间睡眠,在事件发生时内核自动唤醒。 1、数据结构: 每个等待队列都有一个队列头 //... -
【Linux设备驱动程序(第三版)】----延迟:超时(wait_event_interruptible_timeout)
2011-07-08 13:50:58【Linux设备驱动程序(第三版)】----延迟:超时(wait_event_interruptible_timeout)jit.c#include #include #include #include #include #include #include -
linux模块编程(三)——线程的约会completion
2011-09-30 15:18:51它相当于wait_for_completion_timeout调用中的timeout值为0。 completion_done检查是否有线程阻塞在completion上。但这个API并不准确,它只是检查completion.done是否为0,为0则认为有线程阻塞。这个API并不会... -
Linux设备驱动程序 之 完成量
2021-05-15 18:47:15内核提供了完成量(completion)来完成上述需求;完成量是一个轻量级的机制,它允许一个线程告诉另一个线程某个工作已经完成;为了使用完成量,代码需要包含;可以利用下面的宏静态的创建和初始化完成量;1 #de... -
记一次Linux主机内存脏数据引发的NameNode故障,主机提示echo 0 > /proc/sys/kernel/hung_task_timeout...
2020-10-18 20:31:58记一次Linux主机内存脏数据引发的NameNode故障,主机提示echo 0 > /proc/sys/kernel/hung_task_timeout_secs。内存脏数据是什么,如何调优。