简单休眠之等待队列

1. 简单休眠

让进程以一种安全的方式进入休眠,必须牢记两条规则:

第一条:永远不能在原子上下文中进入休眠。即是说,我们的进程不能在拥有自旋锁、顺序锁、读写锁时休眠。如果我们已经禁止了中断,也不能休眠。但是,在拥有信号量时休眠是合法的。

第二条:当休眠进程被唤醒时,必须检查以确保我们等待的条件真正为真。

2. 等待队列

Linux中,一个等待队列可以实现简单休眠。一个等待队列由一个等待队列头来管理,一个wait_queue_head_t类型的结构,定义在<litlux/wait.h>

一个等待队列头需要定义和初始化后才能使用:

DECLARE_WAIT_QUEUE_HEAD (name)

或者动态地,如下:

wait_queue_head_t my_queue;

init_waitqueue_head(&my_queue);

3. 休眠API

当一个进程休眠,它这样做以期望某些条件在以后会成真。wait event的形式如下:

wait_event(queue, condition)

wait_event_interruptible(queue, condition)

wait_event_timeout(queue, condition, timeout)

wait_event_interruptible_timeout(queue, condition, timeout)

在所有上面的形式中,queue是要用的等待队列头。注意它是通过值传递的。Condition,是任意的布尔表达式,上面的宏在休眠前后都要求对该表达式求值;在条件为真之前,进程保持睡眠。注意条件可能被任意次地求值,因此它不应当有任何边界效应。

如果你使用wait_event你的进程被置为不可中断地睡眠,它常常不是你所要的首选。最好的选择是wait_event_interruptible,它可能被信号中断,非零值表示休眠被某个信号中断。而你的驱动可能需要返回-ERESTARTSYS。后面的版本((wait_event_timeoutwait_event_interruptible_timeout)只会等待限定的时间;当给定的时间到期后,这两个宏都会返回0值。

4. 唤醒API  

void wake_up (wait_queue_head_t *queue);

void wake_up_interruptible(wait_queue_head_t *queue)

wake_up唤醒所有的在给定队列上等待的进程。另一个的形式(wake_up_iterruptible)只会唤醒那些执行可中断休眠的进程。实际上,惯例是:如果你在使用wait_event,就使用wake_up来唤醒;如果你在使用wait_event_interruptible,就是有wake up_interruptible来唤醒。

5. 示例

 typedef struct {
    uint32_t len;
    spinlock_t lock;
    struct list_head list;
    wait_queue_head_t wait;
} bio_queue_t;

typedef struct {
    void * bio;
    struct list_head list;
} bio_t;

bio_queue_t my_queue;


bio_t * get_bio(void)
{
    struct list_head *pos = NULL;
    unsigned long flag = 0;

    for(;;)
    {
        spin_lock_irqsave(&my_queue.lock, flag);
        if(!list_empty(&my_queue.list))
        {
            pos = my_queue.list.next;
            list_del_init(pos);
        }
        spin_unlock_irqrestore(&my_queue.lock, flag);
        if ( NULL == pos)
        {
            wait_event_interruptible(my_queue.wait, (!list_empty(&my_queue.list)));
        }
        else{
            break;
        }
    }
    return (bio_t *)container_of(pos, bio_t, list);
}

void recycle_bio(bio_t * bio)
{
    unsigned long flag = 0;

  
    spin_lock_irqsave(&my_queue.lock, flag);
    list_add_tail(&bio->list, &my_queue.list);
    spin_unlock_irqrestore(&my_queue.lock, flag);
    wake_up_interruptible(&my_queue.wait);

    return ;
}

int init_bio()
{
    bio_t * bio = NULL;

  
    spin_lock_init(&my_queue.lock);
    INIT_LIST_HEAD(&my_queue.list);
    waitqueue_head(&my_queue.wait);
    for(i = 0; i < my_queue.len; i++)
    {
        bio = (bio_t *)kmalloc(sizeof(bio_t), GFP_KERNEL);
        if( NULL == bio)
        {
            return -1;
        }

        list_add_tail(&bio->list, &my_queue.list);
    }
    return 0;
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值