init_waitqueue_head(wait_queue_head_t * queue);
还有一种简单的方式去初始化队列头(静态初始化)
DECLARE_WAIT_QUEUE_HEAD(name)它会将name 定义为一个 struct wait_queue_head_t 结构,并初始化
#define wait_event(wq, condition) #define wait_event_timeout(wq, condition, timeout) #define wait_event_interruptible(wq, condition) #define wait_event_interruptible_timeout(wq, condition, timeout)wq: 指对应的等待队列头
condition 表示检测的的条件,在condition为真时,睡眠终止。
含有 interruptible 的函数 表示睡眠可以被信号中断,当睡眠被信号中断事,函数返回负值(-ERESTARTSYS)
含有timeout 的函数 timeout 参数表示最长的等待时间,
有睡眠就有唤醒
在其他进程操作了设备 使等待进程的 等待条件(condition)为真,则需要在此进程中唤醒睡眠的进程
#define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL) #define wake_up_all(x) __wake_up(x, TASK_NORMAL, 0, NULL) #define wake_up_interruptible(x) __wake_up(x, TASK_INTERRUPTIBLE, 1, NULL) #define wake_up_interruptible_nr(x, nr) __wake_up(x, TASK_INTERRUPTIBLE, nr, NULL) #define wake_up_interruptible_all(x) __wake_up(x, TASK_INTERRUPTIBLE, 0, NULL)wake_up 会首先唤醒队列上1个 独占等待的进程(下边有简单的解释),如果没有则去唤醒其他所有的进程
wake_up_all 唤醒等待队列上的所有进程,不管独占 还是 非独占
wake_up_interruptible跟wake_up 类似, 不过他只会唤醒 队列中可中断的睡眠进程
wake_up_interruptible_all 会唤醒等待队列上的所有可中断睡眠,
wake_up_interruptible_nr 回唤醒等待队列上的nr个独占进程独占等待进程 : 因为在一个睡眠队列上,睡眠的进程可能会有很多,而每次唤醒之后只有一个进程唤醒执行,其他进程继续在等待队列上睡眠,这就导致了有些=重要的进程迟迟不呢个得到调用,为改善这个情况,有了独占进程的概念, 在睡眠时候我们可以指定一个参数WQ_FLAG_EXCLUSEVE标志会加到队列的尾部(不加此标志则默认加到队列头部), 在调用wake_up_xx 对应的函数时候会首先唤醒这些进程。
while(dev->datawr == dev->datard) { while(dev->datard == dev->datawr) //循环检测等待条件是否真正的满足 { up(&dev->semp) if(filp->f_flags & O_NONBLOCK) //判断是否是非阻塞打开 { return -EAGAIN; } D("[%s] reading going to sleep!", current->comm); if(wait_event_interruptible(dev->rdque, dev->datard != dev->datawr)) //使当前进程睡眠在读睡眠队列 { return -ERESTARTSYS; } D("waked up %d\n", __LINE__); ... if(down_interruptible(&dev->semp) < 0)//获取锁 { printk(KERN_ERR "[%s]get the mutex lock error %d, %s", current->comm, __LINE__, __func__); return -ERESTARTSYS; } else { D("have get the mutex %d\n", __LINE__); } } /*read data*/ wake_up_interruptible(dev->wrque)//读出数据 唤醒写睡眠队列上的进程 }
unsigned int (*poll) (struct file *filp, struct poll_table_struct *wait);在系统编程时候我们经常会只用到poll 或者 select函数去监听某个文件描述符是否可写或者可读等
static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)2、返回一个描述设备可读可写的掩码
#define POLLIN 0x0001 //设备可读 #define POLLPRI 0x0002 //无阻塞读取高优先级数据 #define POLLOUT 0x0004 //设备可写入 #define POLLERR 0x0008 //设备发生错误 #define POLLHUP 0x0010 //设备挂起 #define POLLRDNORM 0x0040 //normal data is ready now #define POLLWRNORM 0x0100 //normal data can be writen to deviceexample:
static int simple_poll(struct file *filp, struct poll_table_struct *wait) { struct simple_dev *dev = filp->private_data; unsigned int mask = 0; char *next_ptr; if(down_interruptible(&dev->semp)) { printk(KERN_ERR "get the semphore err %d \n",__LINE__); return -ERESTARTSYS; } D("have get the semphore %d\n", __LINE__); poll_wait(filp, &dev->inq, wait); poll_wait(filp, &dev->outq, wait); if(dev->datard != dev->datawr) { mask |= POLLIN | POLLRDNORM; //can be read } if(dev->datawr+1 == dev->dataend) next_ptr = dev->data; else next_ptr = dev->datawr+1; if(next_ptr != dev->datard) { mask |= POLLOUT | POLLWRNORM; //can be write } up(&dev->semp); return mask; }