wait_queue如何使用

news2025/1/12 10:54:59

Linux内核的 等待队列(Wait Queue)是重要的数据结构,与进程调度机制紧密相关联,可以用来同步对系统资源的访问、异步事件通知、跨进程通信等。如下图所示,

在Linux中,等待队列以循环链表为基础结构,包括两种数据结构:

等待队列头(wait queue head)  和 等待队列元素(wait queue) ,整个等待队列由等待队列头进行管理 。使用到的数据结构如下

struct __wait_queue_head { //queue head
	spinlock_t		lock;
	struct list_head	task_list;//head
};
typedef struct __wait_queue_head wait_queue_head_t;


struct __wait_queue {//entry   队列元素
	unsigned int		flags;
	void			*private;-------------→ 关键,是task_struct 进程指针
	wait_queue_func_t  	func;-----》指向等待队列被唤醒时的回调的唤醒函数
	struct list_head	task_list;
};

 

   DECLARE_WAIT_QUEUE_HEAD(queue);
    DECLARE_WAITQUEUE(wait, current);

    for (;;) {
        add_wait_queue(&queue, &wait);
        set_current_state(TASK_INTERRUPTIBLE);
	if (condition)
	    break;
        schedule();
	remove_wait_queue(&queue, &wait);
	if (signal_pending(current))
	    return -ERESTARTSYS;
    }
    set_current_state(TASK_RUNNING);

A sleep coded in this manner is safe against missed wakeups. It is also a fair amount of error-prone boilerplate code for a very common situation. In 2.6, a set of helper functions has been added which makes this task easier. The modern equivalent of the above code would look like:


    DECLARE_WAIT_QUEUE_HEAD(queue);
    DEFINE_WAIT(wait);

    while (! condition) {
        prepare_to_wait(&queue, &wait, TASK_INTERRUPTIBLE);
	if (! condition)
	    schedule();
        finish_wait(&queue, &wait)
    }


内核mmc驱动,实际mmc host使用之前需要请求host,把当前进程设置等待host可用

/**
 *	__mmc_claim_host - exclusively claim a host
 *	@host: mmc host to claim
 *	@abort: whether or not the operation should be aborted
 *
 *	Claim a host for a set of operations.  If @abort is non null and
 *	dereference a non-zero value then this will return prematurely with
 *	that non-zero value without acquiring the lock.  Returns zero
 *	with the lock held otherwise.
 */
int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
{
	DECLARE_WAITQUEUE(wait, current);//定义等待队列元素,关联当前进程,唤醒回调函数为default_wake_function()
	unsigned long flags;
	int stop;
	bool pm = false;

	might_sleep();

	add_wait_queue(&host->wq, &wait);//将当前等待队列元素加入到等待队列host->wq中
	spin_lock_irqsave(&host->lock, flags);
	while (1) {
		set_current_state(TASK_UNINTERRUPTIBLE);// 当前进程状态设置为 TASK_UPINTERRUPTIBLE,此时仍未让出CPU
		stop = abort ? atomic_read(abort) : 0;
		if (stop || !host->claimed || host->claimer == current)// 真正让出CPU前判断等待的资源是否已经得到
			break;
		spin_unlock_irqrestore(&host->lock, flags);
		schedule();// 调用调度器,让出CPU,当前进程可进入休眠
		spin_lock_irqsave(&host->lock, flags);
	}
	set_current_state(TASK_RUNNING);
	if (!stop) {
		host->claimed = 1;
		host->claimer = current;
		host->claim_cnt += 1;
		if (host->claim_cnt == 1)
			pm = true;
	} else
		wake_up(&host->wq);// 可利用abort参数执行一次等待队列唤醒工作
	spin_unlock_irqrestore(&host->lock, flags);
	remove_wait_queue(&host->wq, &wait);/// 等待队列结束,将等待队列元素从等待队列中移除

	if (pm)
		pm_runtime_get_sync(mmc_dev(host));

	return stop;
}

 唤醒在下面的函数中

/**
 *	mmc_release_host - release a host
 *	@host: mmc host to release
 *
 *	Release a MMC host, allowing others to claim the host
 *	for their operations.
 */
void mmc_release_host(struct mmc_host *host)
{
	unsigned long flags;

	WARN_ON(!host->claimed);

	spin_lock_irqsave(&host->lock, flags);
	if (--host->claim_cnt) {
		/* Release for nested claim */
		spin_unlock_irqrestore(&host->lock, flags);
	} else {
		host->claimed = 0;//=0代表没有进程请求host,等待进程可以使用host
		host->claimer = NULL;
		spin_unlock_irqrestore(&host->lock, flags);
		wake_up(&host->wq);// 唤醒等待队列host->wq上的所有进程
		pm_runtime_mark_last_busy(mmc_dev(host));
		pm_runtime_put_autosuspend(mmc_dev(host));
	}
}

一般配套使用 ,使用前申请,使用后释放

void mmc_rescan(struct work_struct *work)
{
	struct mmc_host *host =
		container_of(work, struct mmc_host, detect.work);
	
     .....

	if (!(host->caps & MMC_CAP_NONREMOVABLE) && host->ops->get_cd &&
			host->ops->get_cd(host) == 0) {
		mmc_claim_host(host);---------申请
		mmc_power_off(host);
		mmc_release_host(host);----释放
		goto out;
	}

	mmc_claim_host(host);-----申请
	for (i = 0; i < ARRAY_SIZE(freqs); i++) {
		if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) {
			extend_wakelock = true;
			break;
		}
		if (freqs[i] <= host->f_min)
			break;
	}
	mmc_release_host(host);-----释放

 out:
	if (extend_wakelock)
		wake_lock_timeout(&mmc_delayed_work_wake_lock, HZ / 2);
	else
		wake_unlock(&mmc_delayed_work_wake_lock);
	if (host->caps & MMC_CAP_NEEDS_POLL)
		mmc_schedule_delayed_work(&host->detect, HZ);
}


实际例子

include<linux/module.h>
#include<linux/sched.h>
#include<linux/list.h>
#include<linux/kthread.h>
#include<linux/wait.h>
#include<linux/types.h>
#include<linux/sched/signal.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>

MODULE_LICENSE("GPL");


int condition =0 ;
DECLARE_WAIT_QUEUE_HEAD(queue);

int  test_wait(void * argc)
{
    //DECLARE_WAIT_QUEUE_HEAD(queue);
    DECLARE_WAITQUEUE(wait, current);
    
    printk("in thread \n");
    //add_wait_queue(&queue, &wait);
    for (;;) {
        add_wait_queue(&queue, &wait);
        set_current_state(TASK_INTERRUPTIBLE);
	printk("in thead,condition is %d\n",condition);
	//if (condition)	    break;
        schedule();
	printk("has wakeup ,so continue \n");
	remove_wait_queue(&queue, &wait);
	if (signal_pending(current))
	    return -ERESTARTSYS;
    }
    set_current_state(TASK_RUNNING);

    return  0;
}

static int mytest_proc_show(struct seq_file *seq, void *v) 
{
   seq_puts(seq, condition ? "true\n" : "false\n");
  
   return 0;
}

static int mytest_proc_open(struct inode *inode, struct file *file)
{
 return single_open(file, mytest_proc_show, inode->i_private);
}

static ssize_t mytest_proc_write(struct file *file, const char __user *buffer,
        size_t count, loff_t *pos)
{
 char mode;
 
 printk("proc write\n");
 
 if (count > 0) {
  if (get_user(mode, buffer))
     return -EFAULT;
   printk("mode is %c \n",mode);
   
   condition = (mode != '0');
   printk("end write,condition is %d \n",condition);

   //if(condition)
	   wake_up_interruptible(&queue);
 }

 return count;
}
static const struct file_operations mytest_proc_fops = {
 .open  = mytest_proc_open,
 .read  = seq_read,
 .write  = mytest_proc_write,
 .llseek  = seq_lseek,
 .release = single_release,
};

struct proc_dir_entry *mytest_file;
struct task_struct *thread1;
static int __init prepare_to_wait_init(void)
{
    //struct task_struct *thread1;
printk("module init begin \n");

thread1 = kthread_run(test_wait, NULL, "wait and  wakeup test");

if(thread1)
	printk("creat thread1 \n"); 
 
 mytest_file = proc_create("mytest", 0x0666, NULL, &mytest_proc_fops);
 
 return 0;
}
static void __exit prepare_to_wait_exit(void)
{
    printk("\n rmmod ,Goodbye prepare_to_wait\n");

    if(mytest_file)
	proc_remove(mytest_file);
}

module_init(prepare_to_wait_init);
module_exit(prepare_to_wait_exit);

参考:

Linux 阻塞与唤醒实现原理 - zbs666 - 博客园

Linux等待队列(Wait Queue) - huey_x - 博客园

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/76193.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于web的实验教学管理系统java ssm教学视频平台源码和论文

研究背景 近几年来&#xff0c;随着地方高等院校办学规模的不断扩大&#xff0c;为了适用社会发展需要&#xff0c;地方高校将应用 型人才培养作为学校的人才培养目标。为了适应学校应用型人才培养目标&#xff0c;各专业尤其是理工科专 业人才培养方案中加强了实践教学环节&a…

1559_AURIX_TC275_RCU系统中的Boot支持、Pad配置以及NMI trap处理

全部学习汇总&#xff1a; GreyZhang/g_TC275: happy hacking for TC275! (github.com) 这一次看的10页文档虽然文字内容不多&#xff0c;但是涉及到的面还是很多的。而且&#xff0c;看完之后的确是有一种答疑解惑的畅快感。 1. ESRx作为GPIO用的时候&#xff0c;也拥有GPIO设…

高等数学(第七版)同济大学 习题11-1 个人解答

高等数学&#xff08;第七版&#xff09;同济大学 习题11-1 函数作图软件&#xff1a;Mathematica 1.设在xOy面内有一分布着质量的曲线弧L&#xff0c;在点(x,y)处它的线密度为μ(x,y)&#xff0c;用对弧长的曲线积分分别表达&#xff1a;\begin{aligned}&1. \ 设在xOy面内…

蓝桥杯嵌入式MCP4017

文章目录前言一、查看MCP4017芯片手册二、MCP4017在开发板上的电路图三、工程配置四、MCP4017读写函数编写总结前言 MCP4017是一个可编程电阻&#xff0c;通过写入数值可以调节电阻值的大小。 一、查看MCP4017芯片手册 在这里我们只需要关注MCP4017即可。下面的几个重要点我…

广播、组播 socket编程

目录 1、单播 / 广播 / 组播 的概念 (1) 单播 (2) 广播 (3) 多播&#xff08;组播&#xff09; 2、广播 socket编程&#xff08;只能是UDP通信&#xff09; 3、多播 socket编程&#xff08;只能是UDP通信&#xff09; 1、单播 / 广播 / 组播 的概念 (1) 单播 之前在进行…

m基于FPGA的MSK调制解调系统verilog开发,并带FPGA误码检测模块和matlab仿真程序

目录 1.算法描述 2.仿真效果预览 3.Verilog核心程序 4.完整FPGA 1.算法描述 整个模型的基本框图为 软件无线电是现代通信技术的重要研究领域和发展方向,目前发展迅速.快速发展的软件无线电技术与落后的硬件计算资源之间的矛盾越来越突出.为了缓解这个矛盾,一方面可以加快集…

职场日常:一文剖析性能测试流程,时间为啥那么长?

如果你做过性能测试&#xff0c;你就会知道&#xff0c;性能测试的时间要比功能测试时间长很多&#xff0c;但是&#xff0c;你没有做过&#xff0c;你可能就会问了&#xff0c;为什么性能测试时间要长那么多呢&#xff1f;今天就用一文&#xff0c;带大家了解性能测试工作流程…

自学python?一般人我还是劝你算了吧

前言 本人纯屌丝一枚&#xff0c;在学python之前对电脑的认知也就只限于上个网&#xff0c;玩个办公软件。这里不能跑题&#xff0c;我为啥说自学python&#xff0c;一般人我还是劝你算了吧。因为我就是那个一般人。 基础真的很简单&#xff0c;是个人稍微认点真都能懂&#…

Python一学就会系列:01 开发环境搭建 及 hello world

文章目录前言一、python是什么&#xff1f;官网简介二、开发环境安装1.下载2.安装3. 验证是否安装成功编写一个python新建一个后缀名为py的文件运行python文件总结前言 一、python是什么&#xff1f; 官网 https://www.python.org/ 简介 官网介绍&#xff1a; Python是一种编…

美团面试官总结的“Spring boot面试文档”,全是大厂高频面试题,太全了!

前言 Spring boot不单单在BAT这些一线大厂使用率极其的高&#xff0c;在中小企业中使用率也是非常高的&#xff0c;企业的需求增大&#xff0c;当然对待面试者的要求也会随之提高&#xff0c;竞争也会随之增大。 相信现在的你之所以可以看到我的这篇文章&#xff0c;那肯定是…

[附源码]计算机毕业设计的高校课程知识库Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Python数据分析项目案例

第一部分&#xff1a;数据类型处理 数据加载 字段含义&#xff1a; user_id:用户IDorder_dt:购买日期order_product:购买产品的数量order_amount:购买金额观察数据 查看数据的数据类型数据中是否存储在缺失值将order_dt转换成时间类型查看数据的统计描述在源数据中添加一列表示…

图像风格迁移基础入门及实践案例总结

目录 &#xff11;图像的不同风格 &#xff12;何为图像风格迁移 &#xff12;.&#xff11;基础概念及方法 &#xff12;.&#xff12;示例 &#xff13;图像风格迁移的典型研究成果 &#xff13;.1deep-photo-styletransfer &#xff13;.2CycleGAN &#xff13;.3U-…

【问题记录】Mac M1 Docker配置redis一主二从三哨兵(烧饼好吃)

文章目录Docker配置 redis一主二从三哨兵文件目录redis compose 文件在 redis 文件路径下执行 docker composesentinel 文件结构sentinel compose 配置文件sentinel config 配置文件切换到 sentinel执行 compose测试及问题记录解决方案Docker配置 redis 一主二从三哨兵 文件目…

8家最大的WooCommerce在线商店

想象一下&#xff0c;世界上三分之一的电子商务网站都由单一技术提供支持&#xff0c;而且令人惊讶的是它是免费的。我说的是最大的电子商务解决方案提供商之一&#xff0c;WooCommerce。在这里&#xff0c;我们列出了8 家最大的WooCommerce在线商店&#xff0c;以激发您建立自…

基于jsp+mysql+ssm供应链管理信息系统-计算机毕业设计

项目介绍 本文以销售供应链管理系统的开发为背景&#xff0c;对企业销售管理系统的分析&#xff0c;设计&#xff0c;开发和实施过程进行了详细的描述。本系统基于ssm框架访问作为后台数据库管理连接&#xff0c;通过jdbc与数据库建立连接&#xff0c;以jsp为前端开发工具提供…

数据库之MHA高可用集群部署及故障切换

目录 1 MHA概念 1.1 MHA 的组成 1.2 MHA 的特点 2 搭建MySQLMHA 2.2 修改三台MySQL服务器的主配置文件/etc/my.cnf&#xff0c;并创建命令软链接 2.3 配置MySQL一主两从 2.4 安装 MHA 软件 2.5 在所有服务器上配置无密码认证 2.6 在 manager 节点上配置 MHA 2.7 第一次配…

分类评价指标

不均衡数据 很多时候&#xff0c;不同类别的分类代价并不相等&#xff0c;这就是非均衡分类问题。如果在两个类别中&#xff0c;一个类别的出现次数比另一个多很多&#xff0c;那么错误类型将发挥重要作用。例如。我们一共有100个病人&#xff0c;其中99人是健康的&#xff08…

『.Net』在C#/.Net中将Json压缩成一行的几种方式

&#x1f4e3;读完这篇文章里你能收获到 在.Net Core中使用多种方式将Json压缩成一行主要介绍两种实现方案&#xff0c;Newtonsoft.Json和内置的System.Text.Json 文章目录一、Newtonsoft.Json二、System.Text.Json一、Newtonsoft.Json 将 Formatting 参数设为 Formatting.No…

世界杯杂谈之有趣的数据纪录

目录 &#xff08;一&#xff09;前言 &#xff08;二&#xff09;正文 1. 关于出场 &#xff08;1&#xff09;出场次数 &#xff08;2&#xff09;出场时间最长球员 &#xff08;3&#xff09;连续出场决赛场次最多 &#xff08;4&#xff09;世界杯出场时间最短的人 …