当前位置: 技术问答>linux和unix
有关驱动开发里面队列的问题
来源: 互联网 发布时间:2016-11-16
本文导语: static ssize_t globalfifo_write(struct file *filp,const char __user *buf,size_t count,loff_t *ppos) { int ret; DECLARE_WAITQUEUE(wait,current); down(&globalfifo_devp->sem); add_wait_queue(&globalfifo_devp->w_wait,&wait); if(globalfifo_devp->current_len==GLOBALFIFO_SIZE) { if(fi...
static ssize_t globalfifo_write(struct file *filp,const char __user *buf,size_t count,loff_t *ppos)
{
int ret;
DECLARE_WAITQUEUE(wait,current);
down(&globalfifo_devp->sem);
add_wait_queue(&globalfifo_devp->w_wait,&wait);
if(globalfifo_devp->current_len==GLOBALFIFO_SIZE)
{
if(filp->f_flags & O_NONBLOCK)
{
ret=-EAGAIN;
goto out;
}
__set_current_state(TASK_INTERRUPTIBLE);
up(&globalfifo_devp->sem);
schedule();
if(signal_pending(current))
{
ret=-ERESTARTSYS;
goto out2;
}
down(&globalfifo_devp->sem);
}
if(count>GLOBALFIFO_SIZE-globalfifo_devp->current_len)
count=GLOBALFIFO_SIZE-globalfifo_devp->current_len;
if(copy_from_user(globalfifo_devp->mem+globalfifo_devp->current_len,buf,count))
{
ret=-EFAULT;
goto out;
}
else
{
globalfifo_devp->current_len +=count;
printk(KERN_INFO"written %d bytes ,curren_len:%dn",count,globalfifo_devp->current_len);
wake_up_interruptible(&globalfifo_devp->r_wait);
ret=count;
}
out:up(&globalfifo_devp->sem);
out2:remove_wait_queue(&globalfifo_devp->w_wait,&wait);
set_current_state(TASK_RUNNING);
return ret;
}
static ssize_t globalfifo_read(struct file *filp,char __user *buf,size_t count,loff_t *ppos)
{
int ret;
DECLARE_WAITQUEUE(wait,current);
down(&globalfifo_devp->sem);
add_wait_queue(&globalfifo_devp->r_wait,&wait);
if(globalfifo_devp->current_len==0)
{
if(filp->f_flags & O_NONBLOCK)
{
ret = -EAGAIN;
goto out;
}
__set_current_state(TASK_INTERRUPTIBLE);
up(&globalfifo_devp->sem);
schedule();
if(signal_pending(current))
{
ret =-ERESTARTSYS;
goto out2;
}
down(&globalfifo_devp->sem);
}
if(count>globalfifo_devp->current_len)
count=globalfifo_devp->current_len;
if(copy_to_user(buf,globalfifo_devp->mem,count))
{
ret=-EFAULT;
goto out;
}
else
{
memcpy(globalfifo_devp->mem,globalfifo_devp->mem+count,globalfifo_devp->current_len-count);
globalfifo_devp->current_len-=count;
printk(KERN_INFO"read %d bytes,current_len:%dn",count,globalfifo_devp->current_len);
wake_up_interruptible(&globalfifo_devp->w_wait);
ret=count;
}
out:up(&globalfifo_devp->sem);
out2:remove_wait_queue(&globalfifo_devp->w_wait,&wait);
return ret;
}
上面这段代码是读和写的,有几个问题
1.我执行cat /dev/globalfifo &后,然后echo "hello" > /dev/globalfifo,这个时候输出hello没错,但是不是程序应该直接结束吗?怎么好像可以再重复,好像没有while循环之类的把程序又跳到globalfifo_read的开头
2.DECLARE_WAITQUEUE(wait,current)的wait和current是在内核中就定义的吗?如果是那么read和write是否是在同一个等待队列里面?
3.当我执行cat /dev/globalfifo后,程序阻塞在哪条语句里面?
|
DECLARE_WAITQUEUE(wait,current)
这个应该是定义了一个名字叫做wait的 waitqueue 结构, current是内核的预定义的宏,表示当前进程task结构。
关键是 add_wait_queue(&globalfifo_devp->r_wait,&wait);
这个把wait加到 一个全局的等待队列里面去了,所以你read和write函数都是等待的同一个&globalfifo_devp->r_wait 。
wake_up_interruptible(&globalfifo_devp->w_wait);
的时候就唤醒对方了。
当你执行 cat /dev/globalfifo的时候,因为这时globalfifo_devp->current_len==0)
所以你执行到 schedule();的时候会把自己调度出去,也就是说停到这里了,一直等待对方的唤醒。
当有写入的时候就执行的到wake_up在唤醒这个读进程了。
你看到的cat /dev/globalfifo 不会退出的原因是因为是,cat 会尝试读一直度到文件末尾。所以你第一个 globalfifo_read 返回hello时,cat认为你文件里面还有内容,会进行第二次globalfifo_read 的。你要设置 globalfifo_read 的返回值让cat知道已经读到文件末尾才行的。 不然第二次进来的时候有会断在那里。 你可以传个参数给cat让他只读指定的长度看看。
这个应该是定义了一个名字叫做wait的 waitqueue 结构, current是内核的预定义的宏,表示当前进程task结构。
关键是 add_wait_queue(&globalfifo_devp->r_wait,&wait);
这个把wait加到 一个全局的等待队列里面去了,所以你read和write函数都是等待的同一个&globalfifo_devp->r_wait 。
wake_up_interruptible(&globalfifo_devp->w_wait);
的时候就唤醒对方了。
当你执行 cat /dev/globalfifo的时候,因为这时globalfifo_devp->current_len==0)
所以你执行到 schedule();的时候会把自己调度出去,也就是说停到这里了,一直等待对方的唤醒。
当有写入的时候就执行的到wake_up在唤醒这个读进程了。
你看到的cat /dev/globalfifo 不会退出的原因是因为是,cat 会尝试读一直度到文件末尾。所以你第一个 globalfifo_read 返回hello时,cat认为你文件里面还有内容,会进行第二次globalfifo_read 的。你要设置 globalfifo_read 的返回值让cat知道已经读到文件末尾才行的。 不然第二次进来的时候有会断在那里。 你可以传个参数给cat让他只读指定的长度看看。