# 等待队列
## 基本函数
```
wait_queue_head_t my_queue; 定义
init_waitqueue_head(&my_queue); 初始化等待队列
DECLARE_WAIT_QUEUE_HEAD(name) 定义并初始化等待队列头
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);
void remove_wait_queue(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry);
void wait_event(queue, condition)
void wait_event_interruptible(queue, condition) 可以被信号打断
void wait_event_timeout(queue, condition, timeout)
void wait_event_interruptible_timeout(queue, condition, timeout) jiffy为单位
void wake_up(wait_queue_head_t *queue);
void wake_up_interruptible(wait_queue_head_t *queue);
```
## 自动等待
```
ssize_t sleepy_read (struct file *filp, char __user *buf, size_t count, loff_t *pos)
{
printk(KERN_DEBUG "process %i (%s) going to sleep\n",
current->pid, current->comm);
wait_event_interruptible(wq, flag != 0);
flag = 0;
printk(KERN_DEBUG "awoken %i (%s)\n", current->pid, current->comm);
return 0; /* EOF */
}
ssize_t sleepy_write (struct file *filp, const char __user *buf, size_t count,
loff_t *pos)
{
printk(KERN_DEBUG "process %i (%s) awakening the readers...\n",
current->pid, current->comm);
flag = 1;
wake_up_interruptible(&wq);
return count; /* succeed, to avoid retrial */
}
```
## 手动等待
```
#if 0
/* 加入等待队列,等待被唤醒, 也就是有按键按下 */
ret = wait_event_interruptible(dev->r_wait,
atomic_read(&dev->releasekey));
if (ret) {
goto wait_error;
}
#endif
DECLARE_WAITQUEUE(wait, current); /* 定义一个等待队列 */
if(atomic_read(&dev->releasekey) == 0) { /* 没有按键按下 */
add_wait_queue(&dev->r_wait, &wait); /* 添加到等待队列头 */
__set_current_state(TASK_INTERRUPTIBLE);/* 设置任务状态 */
schedule(); /* 进行一次任务切换 */
if(signal_pending(current)) { /* 判断是否为信号引起的唤醒 */
ret = -ERESTARTSYS;
goto wait_error;
}
__set_current_state(TASK_RUNNING); /* 设置为运行状态 */
remove_wait_queue(&dev->r_wait, &wait); /* 将等待队列移除 */
}
```
```
static ssize_t imx6uirq_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
int ret = 0;
unsigned char keyvalue = 0;
unsigned char releasekey = 0;
struct imx6uirq_dev *dev = (struct imx6uirq_dev *)filp->private_data;
if (filp->f_flags & O_NONBLOCK){ /* 非阻塞访问 */
if(atomic_read(&dev->releasekey) == 0)/* 没有按键按下,返回-EAGAIN */
return -EAGAIN;
} else {/* 阻塞访问 */
/* 加入等待队列,等待被唤醒,也就是有按键按下 */
ret = wait_event_interruptible(dev->r_wait, atomic_read(&dev->releasekey));
if (ret) {
goto wait_error;
}
}
keyvalue = atomic_read(&dev->keyvalue);
releasekey = atomic_read(&dev->releasekey);
if (releasekey) { /* 有按键按下 */
if (keyvalue & 0x80) {
keyvalue &= ~0x80;
ret = copy_to_user(buf, &keyvalue, sizeof(keyvalue));
} else {
goto data_error;
}
atomic_set(&dev->releasekey, 0);/* 按下标志清零 */
} else {
goto data_error;
}
return 0;
wait_error:
return ret;
data_error:
return -EINVAL;
}
void timer_function(unsigned long arg)
{
unsigned char value;
unsigned char num;
struct irq_keydesc *keydesc;
struct imx6uirq_dev *dev = (struct imx6uirq_dev *)arg;
num = dev->curkeynum;
keydesc = &dev->irqkeydesc[num];
value = gpio_get_value(keydesc->gpio); /* 读取IO值 */
if(value == 0){ /* 按下按键 */
atomic_set(&dev->keyvalue, keydesc->value);
}
else{ /* 按键松开 */
atomic_set(&dev->keyvalue, 0x80 | keydesc->value);
atomic_set(&dev->releasekey, 1);/* 标记松开按键,即完成一次完整的按键过程 */
}
/* 唤醒进程 */
if(atomic_read(&dev->releasekey)) {/* 完成一次按键过程 */
/* wake_up(&dev->r_wait); */
wake_up_interruptible(&dev->r_wait);
}
}
```
## 说明
```
```
# 轮训 Poll
## 基本函数
```
unsigned int(*poll) (struct file *filp, struct poll_table *wait);
//添加wait到等待队列, 作用L让参数queue对应的等待队列可以唤醒select睡眠进程
void poll_wait(struct file *filp, wait_queue_heat_t *queue, poll_table *wait);
```
## 实例
```
static struct file_operations imx6uirq_fops = {
.owner = THIS_MODULE,
.open = imx6uirq_open,
.read = imx6uirq_read,
.poll = imx6uirq_poll,
.release = imx6uirq_release,
};
unsigned int imx6uirq_poll(struct file *filp, struct poll_table *wait)
{
unsigned int mask = 0;
struct imx6uirq_dev *dev = (struct imx6uirq_dev *)filp->private_data;
poll_wait(filp, &dev->r_wait, wait);/* 将等待队列头添加到poll_table中 */
if(atomic_read(&dev->releasekey)) {/* 按键按下 */
mask = POLLIN | POLLRDNORM;/* 返回PLLIN */
}
return mask;
}
```