从并发的需要,引起的竞争状态,到解决竞争状态的方法机制:
禁止中断
信号量
自旋锁
Completion
原子操作
目标:
掌握进程睡眠和唤醒的方法
掌握阻塞型I/O的实现方法
掌握poll/select系统调用的实现方法
阻塞:进程休眠和唤醒
非阻塞:非阻塞IO selec poll系统调用
休眠的意义?
从调度器的运行队列-》某个等待队列
唤醒等待队列可能发生的情况
当调用wake_up时,所有等待在该队列上的进程都被唤醒,并进入可运行状态
如果只有一个进程可获得资源,此时,其他的进程又将再次进入休眠
如果数量很大,被称为”疯狂售群”
独占等待
与普通休眠的不同
等待队列入口设置了WQ_FLAG_EXCLUSIVE标志时,则会被添加到等待队列的尾部。而没有这个标志的入口会被添加到头部。
在某个等待队列上调用wake_up时,它会在唤醒第一个具有WQ_FLAG_EXCLUSIVE标志的进程之后停止唤醒其他进程。
使进程进入独占等待函数:
-------------------poll函数-----------------------
void poll_wait(struct file *,wait_queue_head_t *,poll_table *);
向poll_table添加一个等待队列
如果当前没有文件描述符可用来执行I/0,则内核将使进程在传递到该系统调用的所有文件描述符对应的等待队列上等待。
http://blog.chinaunix.net/uid-30558445-id-5524932.html poll函数调用过程 描述简单。
poll_wait只是把本进程挂入某个队列,应用程序调用poll > sys_poll > do_sys_poll > poll_initwait,do_poll > do_pollfd > 我们自己写的poll
函数后,再调用schedule_timeout进入休眠。如果我们的驱动程序发现情况就绪,可以把这个队列上挂着的进程唤醒。可见,poll_wait的作用,只是为了让
驱动程序能找到要唤醒的进程。即使不用poll_wait,我们的程序也有机会被唤醒:chedule_timeout(__timeout),只是要休眠__time_out这段时间。
示例:
static unsigned int xxx_poll(struct file *filp,poll_table *wait)
{
struct xxx_pipe *dev = filp->private_data;
unsigned int mask=0;
down(&dev->sem);
poll_wait(filp,&dev->inq,wait);
poll_wait(filp,&dev->outq,wait);
if(read_buffer_not_empty) //如果接收buffer不为空,可读
mask |= POLLIN | POLLRDNORM; /*可读取*/
if(write_buffer_not_full) //如果写buffer不满,可写
mask |= POLLOUT | POLLWRNORM; /*可写入*/
up(&dev->sem);
return mask;
}