【内核】等待队列

一、概述

linux驱动中,进程上下文阻塞一般就是用等待队列来实现,将进程停止在此处并睡眠下,直到条件满足时,才可通过此处,继续运行。
在睡眠等待期间,wake up时,唤起来检查条件,条件满足解除阻塞,不满足继续睡下去。

二、函数接口

wait_queue_head_t my_queue;
init_waitqueue_head(&my_queue) //初始化等待队列
DECLARE_WAIT_QUEUE_HEAD(name); //直接定义

wait_event(queue, condition); 
wait_event_interruptible(queue, condition);  //进入TASK_INTERRUPTIBLE进程的阻塞状态
wait_event_timeout(queue, condition, timeout); 
wait_event_interruptible_timeout(queue, condition, timeout);
wait_event_lock_irq(wq, condition, lock)
wait_event_interruptible_lock_irq(wq, condition, lock, cmd)
wait_event_interruptible_lock_irq_timeout(wq, condition, lock,  timeout)
wait_event_interruptible_exclusive  添加此进程是互斥独占进程

void wake_up(wait_queue_head_t * queue);  唤醒等待队列所有进程,所以唤醒进程需要进行条件判断,不满足时继续睡眠。
void wake_up_interruptible(wait_queue_head_t * queue);   //唤醒TASK_INTERRUPTIBLE进程
void sleep_on(wait_queue_head_t *q);

wait_event <==>  等效以下
init_waitqueue_entry
add_wait_queue 
set_current_state(TASK_INTERRUPTIBLE)
schedule();
schedule_timeout(HZ*10);
remove_wait_queue
finish_wait

//手动休眠方式
//初始化等待队列entry, 与线程绑定
void init_waitqueue_entry(struct wait_queue_entry *wq_entry, struct task_struct *p)
DECLARE_WAITQUEUE(name, tsk) //静态定义
//将entry添加到等待队列中
void add_wait_queue(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry)
void add_wait_queue_exclusive(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry)
//设置flag WQ_FLAG_EXCLUSIVE表明此进程是互斥独占进程。
//等待队列的flag为EXCLUSIVE,设置这个就是表示一次只会有一个非独占进程被唤醒,且是先进先唤醒(若先进进程条件未满足继续等待,则后进的进程会一直得不到唤醒)
//当然非独占进程同样会被全部唤醒。
void remove_wait_queue(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry)
void finish_wait(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry);

三、代码示例

#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/wait.h>
#include <linux/kthread.h>

MODULE_AUTHOR("hpz");
MODULE_LICENSE("Dual BSD/GPL");

#define hp_prt(fmt, arg...)  printk("[%s,%d] "fmt, __FUNCTION__, __LINE__, ##arg);

struct wait_queue_head hp_queue;
struct wait_queue_entry queue_entry1, queue_entry2;
struct task_struct *ptask2;
struct task_struct *ptask1;

static int gcondition;

void timer_func(struct timer_list * timelist);
DEFINE_TIMER(hp_timer,timer_func);
void timer_func(struct timer_list * timelist)
{
    hp_prt("enter\n");
    gcondition = 1;
    wake_up(&hp_queue); //唤醒等待队列的所有进程

    hp_timer.expires = jiffies + 10*HZ;
    add_timer(&hp_timer);
}

int phtread_fun_1(void *data)
{
    hp_prt("[%s,%d] enter!\n",__FUNCTION__,__LINE__);

    while(1){
        hp_prt("phtread_fun_1 pid=%d is alive!\n", current->pid);
        wait_event(hp_queue, gcondition);

        // 手动休眠等待方式
        // set_current_state(TASK_INTERRUPTIBLE);
        // schedule();
        // hp_prt("remove_wait_queue\n");
        // set_current_state(TASK_RUNNING); 
        // remove_wait_queue(&hp_queue,  &queue_entry1);
        break;
    }
    hp_prt("out!\n");
    ptask1 = NULL;
    return 0;
}

int phtread_fun_2(void *data)
{
    hp_prt("[%s,%d] enter!\n",__FUNCTION__,__LINE__);

    while(1){
        hp_prt("phtread_fun_2 pid=%d is alive!\n", current->pid);
        wait_event(hp_queue, gcondition);
        break;
    }
    hp_prt("out!\n");
    ptask2 = NULL;
    return 0;
}

static int code_case_waitqueue_init(void)
{
    hp_prt("enter!\n");
    init_waitqueue_head(&hp_queue); 
    hp_timer.expires = jiffies + 2*HZ;  // 2s 后 进入时钟软中断
    add_timer(&hp_timer);  

    ptask1 = kthread_create(phtread_fun_1, NULL, "task1");
    ptask2 = kthread_create(phtread_fun_2, NULL, "task2");
    if(IS_ERR(ptask1) || IS_ERR(ptask2)){
        hp_prt("create kthread error!\n");
        return 0;
    }

    // 手动休眠等待方式
    // init_waitqueue_entry(&queue_entry2, ptask2);
    // init_waitqueue_entry(&queue_entry1, ptask1); 
    // add_wait_queue_exclusive(&hp_queue, &queue_entry1);
    // add_wait_queue_exclusive(&hp_queue, &queue_entry2); 

    wake_up_process(ptask1);
    wake_up_process(ptask2);
    hp_prt("out!\n");
    return 0;
}
static void code_case_waitqueue_exit(void)
{
     hp_prt("enter!\n"); 
     gcondition = 1;
     wake_up(&hp_queue); 
     hp_prt("enter 02\n");    
     del_timer(&hp_timer);
}

module_init(code_case_waitqueue_init);
module_exit(code_case_waitqueue_exit);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值