进程挂起wait_event_interruptible

Linux内核wait_event_interruptible/ wait_event_interruptible实现简介 阅读详情

在进程执行过程中,有时候需要等待某个条件满足而进行进程阻塞。
常用的一种方法就是让调用者进程暂时挂起,直到目标进程返回结果后,再唤醒等待的进程。

wait_event_interruptible()定义如下:
#define wait_event_interruptible(wq, condition) \
({ \
    int _ret = 0; \
    if(!condition) \
        _wait_event_interruptible(wq, condition, _ret); \
    _ret;
})

也就是说,如果condition满足的话就直接返回0;否则,调用 _wait_event_interruptible进入可中断的挂起状态。

#define _wait_event_interruptible(wq, condition, ret) \
do{ \
    DEFINE_WAIT(_wait) \
        \
    for(;;){ \
        prepare_to_wait(&wq, &_wait, TASK_INTERRUPTIBLE); \
        if(condition) \
            break; \
        if(!signal_pending(current)){ \
            schedule(); \
            continue; \
        } \
        ret = -ERESTARTSYS; \
        break; \
    } \
    finish_wait(&wq, &_wait); \ 
}while(0)

1. prepare_to_wait()只是进行一些链表操作,以确保自己在等待队列中,不会漏掉事件;
2. 进程睡眠的位置为schedule()函数;
3. 进程在确定本身在队列后,再次检查条件,如果不检查,可能条件已经满足,直接去睡眠,可能就再也不会被唤醒;
4. 如果条件不满足就调用schedule()去睡眠,进程的状态在prepare_to_wait()里设置为TASK_INTERRUPTIBLE,所以后续调度的时候就看不到此进程,因为无法参与调度,此时称为休眠
5. 当条件满足后,会存在其他部分(其他进程、内核等)来唤醒等待队列上的进程,具体是唤醒等待队列上的所有进程还是只唤醒第一个,完全取决于唤醒者,
6. 一次唤醒所有进程并不一定是合理的,在多个进程是等待互斥资源的时候,所有等待队列中的进程可以分为互斥、非互斥进程
7. 互斥进程:等待的资源是互斥访问的;互斥进程由内核有选择的唤醒,等待队列项的flag字段为1;非互斥进程:等待的资源是可多进程同时访问的。非互斥进程在事件发生时,总是被内核唤醒,等待队列元素的flag字段为0。
8. 唤醒者通常调用__wake_up_common(),这样,依次取下等待队列中的__wait_queue_t结构, 调用该睡眠进程设置的func函数,即这里的autoremove_wake_function(), 将该进程的状态重新设置为RUNNING。
注意,此时该睡眠进程并不会立刻执行,只有等到下次调度的时候,该进程才有机会运行,即醒来了。醒来是从schedule()回来,继续运行__wait_event()

总结一下, 睡眠是自己设置好进程状态(TASK_UNINTERRUPTIBLE,等等),加入等待队列, 并调用schedule()去睡眠。 睡眠是自己的动作。唤醒是别人发现条件满足,调用__wake_up_common(),将睡眠进程从等待队列取下, 调用该睡眠进程设置的唤醒func,重新设置该睡眠进程为RUNNING。 从而可以在下次调度时运行。 唤醒是别人的动作。

代码由condition控制的for()循环中,所以当由shedule()返回时(当然是被wake_up之后,通过其他进程的schedule()而再次调度本进程),如果condition不满足,本进程将自动再次被设置为TASK_INTERRUPTIBLE状态,接下来执行schedule()的结果是再次被从runqueue队列中删除。这时候就需要再次通过wake_up重新添加到runqueue队列中。

如此反复,直到condition为真的时候被wake_up. 成功地唤醒一个被wait_event_interruptible()的进程,需要满足:
1) 调用wake_up()。
2)condition为真

特别注意:
如果要被wait_event_interruptible的当前进程有nonblocked pending signals, 那么会直接返回-ERESTARTSYS,当前进程不会被wait_event_interruptible 和从runqueue队列中删除。

宏定义_wait_event_interruptible里有个for死循环,跳出循环的条件是condition已经满足要求。首先将自己设置为TASK_INTERRUPTIBLE,也就是可中断挂起状态,然后进行schedule调度。可想而知,因为已经不是处于可运行状态,所以将不再分配到CPU时间,直到有调用wakeup将其唤醒。醒来后还是得先检查condition是否已经满足,否则将再次处于可中断挂起状态。

仔细分析wait_event_interruptible(),其逻辑实现为:
1、函数首先将进程的状态设置为TASK_INTERRUPTIBLE,然后调用schedule();
2、系统调度函数schedule()会将处于TASK_INTERRUPTIBLE状态的进程从队列runqueue中删除;
3、删除后,此进程将不再参与调度,除非通过其他函数(wake_up())将这个进程重新放入runqueue队列中。

wait_event_interruptible()和 wake_up的等效代码 

wait_event_interruptible(wq, condition) /*等效没有考虑返回值*/ 
{ 
     if (!(condition)) 
     { 
         wait_queue_t _ _wait; 
         init_waitqueue_entry(&_ _wait, current); 
         add_wait_queue(&wq, &_ _wait); 
         for (;;) 
         { 
            set_current_state(TASK_INTERRUPTIBLE); 
            if (condition) 
            break; 
            schedule();  /* implicit call: del_from_runqueue(current)*/ 
         } 
         current->state = TASK_RUNNING; 
         remove_wait_queue(&wq, &_ _wait); 
    } 
} 

void wake_up(wait_queue_head_t *q) 
{ 
      struct list_head *tmp; 
      wait_queue_t *curr; 
      list_for_each(tmp, &q->task_list) 
      { 
        curr = list_entry(tmp, wait_queue_t, task_list); 
        wake_up_process(curr->task); 
        /* implicit call: add_to_runqueue(curr->task);*/ 
        if (curr->flags) 
          break; 
      } 
}
BOOST源码笔记(2) - boost::thread之内部干将interrupt_wait     BOOST的Thread库博大精深,有很多的多线程概念在里面,今天就对其中很多call都用到的interrupt_wait的实现进行解释。首先,在BOOST文档中,有1个不得不看的概念,如下:Predefined Interruption Points The following functions are interruption points, which will throw 阅读详情

相关推荐

linux设备驱动中阻塞与非阻塞I/O

阻塞与非阻塞I/O     阻塞操作是指在执行设备操作时,若不能获得资源,则挂起进程直到满足可操作的条件后再进行操作。     被挂起的进程进入休眠状态,被移出调度器的运行队列,直到等待的条件被满足。     非阻塞操作的进程在不能进行设备操作时,并不挂起,它或者放弃,或者不停地查询,直到可用进行     操作为止。     驱动程序通常需要提供这样的能力,支持阻塞和非阻塞的进行re

thinker 826

内核驱动程序——中断处理

内容注册中断处理程序编写中断处理程序中断上下文等待队列 注册中断处理程序 驱动程序可以通过下面的函数注册并激活一个中断处理程序: 函数原型: int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char * name, void * dev); irq:表示要申请的中断号(中断线); handler:指向处理这个中断的实际中断处理程序; flags:中断标志(设置触发方式); name:是与

嵌入式Linux充电站 1211

分组背包问题(MCKP)三大算法对比:贪心、Dyer-Zemel和动态规划谁更强?

本文深入对比了分组背包问题(MCKP)的三大主流算法:贪心算法、Dyer-Zemel算法和动态规划。通过分析各自的原理、实现及性能表现,揭示了贪心算法速度快但非最优,动态规划精确但受限于规模,而Dyer-Zemel算法则在效率与最优性间取得了最佳平衡,是解决中等至大规模MCKP问题的首选方案。

vscode6remote的博客 226

wait_event_interruptible 使用方法

1. 关于 wait_event_interruptible() 和 wake_up()的使用    读一下wait_event_interruptible()的源码,不难发现这个函数先将 当前进程的状态设置成TASK_INTERRUPTIBLE,然后调用schedule(), 而schedule()会将位于TASK_INTERRUPTIBLE状态的当前进程从runqueue

allen6268198的专栏 5万+

使用 NTLite 来定制专属的官方 windows 镜像

移除掉不想要的一些自带的应用,比如 Xbox,office 啥的,这个就根据自己的实际需求来选择,备注基本都是有解释这个应用的作用。win 11 的右键展示不喜欢,更喜欢 win10 的,但是需要修改注册表,这里直接把下面的命令写到后期任务里面。NTLite 的自动保存会话功能会保留操作过的配置,是一个 xml 文件,可以在下次升级镜像版本的时候,导入配置。关闭 windows defender,不关会有这个提示,点是,就会跳到对应的界面。勾选创建 iso,配置 iso 镜像的名字,然后点开始。

以梦为马|越骑越傻 3334

ECU诊断功能测试:从理论到实践

ECU诊断功能是指通过特定的诊断协议与ECU进行通信,以获取ECU的状态信息、故障码、数据流等,并执行特定的诊断操作。诊断功能的主要目的是帮助开发人员和维修人员快速定位和解决ECU中的问题,确保车辆的安全性和可靠性。UDS协议是ISO 14229标准的一部分,定义了一系列的诊断服务,如读取故障码、清除故障码、读取数据流等。UDS协议基于CAN(Controller Area Network)总线,具有较高的灵活性和扩展性。读取故障码是诊断功能中最基本的操作之一。通过读取故障码,可以快速定位ECU中的问题。

闲人编程的博客 1807

wait_event_interruptible()

原文地址:wait_event_interruptible()作者:joee33  wait_event_interruptible()。该函数修改task的状态为TASK_INTERRUPTIBLE,意味着改进程将不会继续运行直到被唤醒,然后被添加到等待队列wq中。     在wait_event_interruptible()中首先判断condition是不是已经满足,如果是则直接返回0,否

shangyaowei的专栏 732

倍福EL6002做RS232通信获取称重数据..

本文介绍EL6002模块通过RS232自由口通信协议获取从站数据。具体数据对照说明手册即可。

weixin_41883890的博客 1012

Linux kernel 中使用 wait_event_interruptible(wq, condition) 使进程睡眠

wait_event_interruptible(wq, condition)  修改当前进程为TASK_INTERRUPTIBLE状态,并把进程添加到等待队列wq中, 意味着该进程要等到被唤醒时才能继续运行,或者被信号中断;如果没有被唤醒或者中断,它会一直等下去。 wait_event_interruptible(wq, condition)  就是用来等待condition为真, condi

moonlighting的专栏 1987

知识图谱实战应用8-从文本关系抽取到知识图谱关系构建流程贯通

大家好,我是微学AI,今天给大家介绍一下知识图谱实战应用8-从文本关系抽取到知识图谱关系构建流程贯通。我们从文本数据中采集到关键信息,并抽取出其中的关系信息,然后在存入图数据库中,整个过程实现自动化,我这里将举一个文本例子进行抽取。 对于知识图谱的构建是将实体、概念和它们之间的关系都以图表形式呈现出来的一种数据结构。要构建一个知识图谱,需要从不同的数据源中采集到相关信息,并将这些信息整合在一起,最终形成一个全面而且精确的知识图谱。

微学AI的博客 2545

软硬件融合加速技术系列文章

目录 文章目录目录计算机组成原理Linux 操作系统原理处理器进程管理内存管理I/O 系统文件系统网络协议栈资源管理设备管理GPUFPGASmartNIC/DPU 计算机组成原理 《计算机组成原理 — 冯诺依曼体系结构》 《计算机组成原理 — 基本硬件设备》 《计算机组成原理 — CPU 中央处理器》 《计算机组成原理 — 指令系统》 《计算机组成原理 — 总线系统》 《计算机组成原理 — 存储系统》 《计算机组成原理 — 输入输出系统 — 存储控制器接口类型》 《计算机组成原理 — 服务器》 《计算机组成

烟云的计算 6806

wait_event()和wait_event_interruptible()的介绍

我们先写下该函数的含义:先判断一下condition条件,如果条件不成立,则将当前进程挂在等待队列中,如果条件成立,则唤醒等待队列. 在kernel-4.14/include/linux/wait.h中,有着大量的wait_event类的API函数, wait_event(wq_head, condition) wait_event_timeout(wq_head, condition, timeout) wait_event_interruptible(wq_head, condition) wait_

baron-周贺贺-代码改变世界ctw 1701

基于MATLAB的奇异谱分析(SSA)算法详解

本文详细介绍了基于MATLAB的奇异谱分析(SSA)算法。文章首先阐述了SSA的基本概念、历史发展及其与传统信号分析方法的对比优势,指出SSA作为一种非参数、非线性时间序列分析方法,特别适合处理非平稳信号。随后详细解析了SSA算法的核心原理与数学模型,包括轨迹矩阵构建、奇异值分解、分组与重构四个关键步骤。文章还提供了完整的MATLAB实现框架和代码解析,涵盖参数检查、轨迹矩阵构建、SVD分解、分组策略和重构过程。最后,通过信号分解、去噪和预测三个应用案例展示了SSA的实际效果。

qq_42212808的博客 168

linux wait_event_interruptible()

wait_event_interruptible(wq, condition),该函数修改task的状态为TASK_INTERRUPTIBLE,意味着该进程将不会继续运行直到被唤醒,然后被添加到等待队列wq中。 在wait_event_interruptible()中首先判断condition是不是已经满足,如果条件满足则直接返回0,否则调用__wait_event_interruptibl

goushuiku的博客 1583

把 SAP GUI 做成可维护的应用:Module Pool 基础与 Table Control 深入实战

SAP Module Pool 与 Table Control 开发要点 摘要:Module Pool 作为 SAP GUI 交互的核心技术,由程序、屏幕(Dynpro)和流逻辑(Flow Logic)组成,通过 PBO/PAI 事件驱动数据流。Table Control 是其中处理多行数据的核心控件,其开发关键在于: 正确理解 PBO/PAI 数据流机制 掌握 CXTAB_CONTROL 结构的关键属性(LINES、TOP_LINE 等) 合理设置列控制属性(CXTAB_COLUMN) 采用 LOOP W

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 242

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

wait_event_interruptible 使用方法

读一下wait_event_interruptible()的源码,不难发现这个函数先将  当前进程的状态设置成TASK_INTERRUPTIBLE,然后调用schedule(),  而schedule()会将位于TASK_INTERRUPTIBLE状态的当前进程从runqueue  队列中删除。从runqueue队列中删除的结果是,当前这个进程将不再参  与调度,除非通过其他函数将

xiaopohaibebo的专栏 723

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

wait_queue_t,wait_queue_head_t的认识

wait_queue_head_t属于设备,设备可以维护几个wait_queue_head_t以等待不同类型的事件,wait_queue_t跟进程相关,wait_event把wait_queue_t的进程加入到设备的wait_queue_head_t,中来等待事件的发生,事件发生后wake_up_interruptible会唤醒设备中wait_queue_head——t中的所有wait_queue

lin111000713的专栏 958

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

kernel的sleep机制

一 。因为我是在写driver的时候,学会的这个问题,就以driver的代码来理解吧。 while (dev->rp == dev->wp) { /* nothing to read */ up(&dev->sem); /* release the lock */ if (filp->f_flags...

weixin_33877092的博客 326

阻塞 IO

进程的状态 在操作系统中,进程至少要有三种基本状态:运行状态,就绪状态和等待状态。 1)就绪——执行:对就绪状态的进程,当进程调度程序按一种选定的策略从中选中一个就绪进程,为之分配了处理机后,该进程便由就绪状态变为执行状态; 2)执行——等待:正在执行的进程因发生某等待事件而无法执行,则进程由执行状态变为等待状态,如进程提出输入/输出请求而变成等待外部设备传输信息的状态,进程申请资源(主存空间或外部设备)得不到满足时变成等待资源状态,进程运行中出现了故障(程序出错或主存储器读写错等)变成等待干预状态等等;

qq_29890089的博客 1180

linux的驱动常用函数,Linux 驱动的 杂乱函数记录

1.DECLARE_WAIT_QUEUE_HEAD/* 定义并初始化一个等待队列头 */1.static DECLARE_WAIT_QUEUE_HEAD(waiter);static int i2c_flag ; //定义一个全局唤醒变量2.wait_event_interruptible(waiter, i2c_flag != 0); //唤醒变量 != 0,则执行这句之后代码在特殊的地方唤醒等...

weixin_31460419的博客 182

wait _event_interruptible()函数分析

wait_event_interruptible()函数分析 (2011-11-03 11:32:51) 转载▼ 标签: 杂谈 分类:linuxkernel Linux-2.6提供如下关于等待队列的操作: (1) 定义"等待队列头", wa...

weixin_33836874的博客 259

Linux 阻塞性驱动程序设计

一 。阻塞性驱动程序设计   1. 阻塞的必要性   2. 内核等待队列     1、定义等待队列wait_queue_head_tmy_queue     2、初始化等待队列init_waitqueue_head(&my_queue     3、定义+初始化等待队列DECLARE_WAIT_QUEUE_HEAD(my_queue)     4、进入等待队列,睡眠     ...

weixin_33705053的博客 80

如何唤醒 wait_event_interruptible()

线程1通过系统调用进入内核,后调用wake_up_interruptible等待唤醒事件,当事件不满足条件时,线程1进入休眠状态。中断或其他线程任务事件满足条件时,调用wait_event_interruptible,唤醒等待在wait_queue_head上的线程1。如果两个线程调用wait_event_interruptible(test,condition)阻塞休眠,一个中断调用wake_up_interruptible(test)但是并没有设置condition为1,会怎么样?

星空语_的博客 490

竞态编程相关接口

Name wait_event_interruptible_timeout — sleep until a condition gets true or a timeout elapses Synopsis wait_event_interruptible_timeout (wq,condition,timeout); Arguments wq the waitqu

ych_ding的专栏 549

linux内核wait_event_interruptible和wake_up_interruptible的使用,实现内核两个进程间的交互

内核中使用wait_event_interruptible和wake_up_interruptible接口函数,来实现内核两个进程之间的交互。 代码实现: /* 声明一个工作队列入等待*/ static DECLARE_WAIT_QUEUE_HEAD(my_wq); static volatile int wq_condition = 0; void thread1() { for(;;){ /*进入休眠等待*/ wait_event_interrupti

zgp2917的专栏 1004

Linux驱动中的wait_event_interruptible()与wake_up_interruptible()

【版权申明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) Linux驱动中的wait_event_interruptible()与wake_up_interruptible() DECLARE_WAIT_QUEUE_HEAD(wq)   生成一个等待队列头wait_queue_head_t,名字为wq. wait_event_interruptible(wq, condition):...

手中沙的博客 2940
上一篇: 可变参数实现原理
下一篇: C++封装成托管模式供C#调用过程
yanlinembed
博客等级 码龄12年 42粉丝 32原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值