4: linux 信号量在wait_event_interruptible_timeout 调用返回 -ERESTARTSYS的问题

问题概述:

在做编解码开始编码时,app通过system call 调用内核态,内核态代码如下。

rval = wait_event_interruptible_timeout(wait_queue,  condition, 5s) ;
printk( “ hello world,  rval = %d\n”, rval );

rval返回0表示时间片流完,condition还没有满足
rval返回>0 表示时间片没流完,condition满足了,rval值即为剩余的时间片值(单位ms)
但是我们在debug时候发现 rval 返回了 -512.

问题剖析

根据返回值找到了-512其实就是-ERESTARTSYS,本着有问题找百度,解决不了照google的思想,参考如下链接定位大致问题是返回 -ERESTARTSYS 是因在做system call 时候被某信号量(特指如**SIGINT,SIGQUIT,SIGTERM ** )打断了,这个时候system call 被打断,返回 -ERESTARTSYS.
而信号产生的原因诸多,不详解,我们遇到的场景是 app嵌套app执行导致中断信号产生。

系统调用 -ERESTARTSYS返回参考链接

系统调用返回 -ERESTARTSYS 问题解析1.
系统调用返回 -ERESTARTSYS 问题解析2.

问题解决方法

在app执行时候,可以将信号量给屏蔽,待执行完毕后将信号量打开。

sigset_t mask_sigset, prev;
/* 初始化信号量集 */
sigemptyset(&mask_sigset);
sigaddset(&mask_sigset, SIGINT);
sigaddset(&mask_sigset, SIGQUIT);
sigaddset(&mask_sigset, SIGTERM);
/* 给信号量绑定函数 */
signal(SIGINT, signal_handler);
signal(SIGQUIT, signal_handler);
signal(SIGTERM, signal_handler);
/* 阻塞信号量参数集mask_sigset,并将阻塞的信号量集和mask_sigset保存到信号量集prev */
sigprocmask(SIG_BLOCK, &mask_sigset, NULL);
task 1 //本任务需要block信号量下执行
/* */
sigprocmask(SIG_UNBLOCK, &mask_sigset, NULL);
task 2 //本任务不需要在block信号量下执行
信号量block和unblock参考链接

信号量block和unblock解析.

### 使用方法 `wait_event_interruptible_timeout` 函数用于等待某个条件满足或者超时,它是一个宏定义,原型如下: ```c #define wait_event_interruptible_timeout(wq, condition, timeout) ({ long __ret = timeout; if (!(condition)) __wait_event_interruptible_timeout(wq, condition, __ret); __ret; }) ``` - `wq`:作为等待队列头的等待队列,用于标识等待的队列,当条件满足或者超时后,该队列会被唤醒 [^1][^3]。 - `condition`:必须满足的条件,如果条件不满足,进程会被阻塞。只有当 `condition` 为真时,进程才会继续执行 [^2][^3]。 - `timeout`:超时时间,单位是 `jiffies`(内核定时器的节拍数)。如果在 `timeout` 时间内 `condition` 条件满足,函数会提前返回;如果超时,函数也会返回 [^1][^3][^4]。 ### 原理 一个调用 `wait_event_interruptible_timeout` 的进程,被唤醒调度执行,需要满足两个条件 [^2]: 1. `condition` 条件满足。 2. 调用 `wake_up` 唤醒。 如果仅仅是修改了 `condition`,使得 `condition` 条件为真,但由于此时调用 `wait_event_interruptible_timeout` 函数的进程不在运行队列 `runqueue` 中,因此不会被调度,这种情况还需要一个 `wake_up` 将此进程加入 `runqueue` 中。 `timeout` 和 `condition` 相比,`timeout` 有更高优先级。也就是说,如果超时时间到了,无论 `condition` 是否满足,进程都会被唤醒 [^3]。 ### 示例代码 以下是一个简单的示例,展示如何使用 `wait_event_interruptible_timeout` 函数: ```c #include <linux/module.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/wait.h> // 定义等待队列头 DECLARE_WAIT_QUEUE_HEAD(my_wait_queue); // 定义条件变量 static int my_condition = 0; static int __init my_module_init(void) { long ret; printk(KERN_INFO "Module initialized, waiting for condition...\n"); // 调用 wait_event_interruptible_timeout 函数等待条件满足或超时 ret = wait_event_interruptible_timeout(my_wait_queue, my_condition, msecs_to_jiffies(5000)); if (ret > 0) { printk(KERN_INFO "Condition satisfied after %ld jiffies.\n", ret); } else if (ret == 0) { printk(KERN_INFO "Timed out after 5 seconds.\n"); } else { printk(KERN_INFO "Interrupted by a signal.\n"); } return 0; } static void __exit my_module_exit(void) { printk(KERN_INFO "Module exited.\n"); } module_init(my_module_init); module_exit(my_module_exit); MODULE_LICENSE("GPL"); ``` 在这个示例中,模块初始化时调用 `wait_event_interruptible_timeout` 函数等待 `my_condition` 条件满足,超时时间为 5 秒。如果在 5 秒内 `my_condition` 变为真,函数会提前返回;如果超时,函数会返回 0。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值