学习ldd3--阻塞型 IO(第六章)
来源:互联网 发布:linux重命名文件的命令 编辑:程序博客网 时间:2024/05/19 03:20
作者:张伟AreS
/*******************************************************************************/
代码:D:\学习\个人学习笔记及网络经典文章\学习LDD3笔记\ldd3_examples\scull\main.c
D:\学习\个人学习笔记及网络经典文章\学习LDD3笔记\ldd3_examples\scull\pipe.c
代码:D:\学习\个人学习笔记及网络经典文章\学习LDD3笔记\ldd3_examples\scull\main.c
D:\学习\个人学习笔记及网络经典文章\学习LDD3笔记\ldd3_examples\scull\pipe.c
先学习下手动休眠方式:
创建和初始化一个等待队列:DEFINE_WAIT(my_wait);其中, name 是等待队列入口项的名
也可分两步:wait_queue_t my_wait; init_wait(&my_wait);
添加你的等待队列入口到队列, 并且设置进程状态. 2个任务都由这个函数处理:
void prepare_to_wait(wait_queue_head_t *queue, wait_queue_t *wait, int state);
queue和wait分别地是等待队列头和进程入口.state是进程的新状态;它应当或者是TASK_INTERRUPTIBLE(给可中断的睡眠,这常常是你所要的)或者TASK_UNINTERRUPTIBLE(给
不可中断睡眠).
在调用 prepare_to_wait 之后, 进程可调用 schedule()进行休眠。从schedule()返回时,进程状态为TASK_RUNNING
创建和初始化一个等待队列:DEFINE_WAIT(my_wait);其中, name 是等待队列入口项的名
也可分两步:wait_queue_t my_wait; init_wait(&my_wait);
添加你的等待队列入口到队列, 并且设置进程状态. 2个任务都由这个函数处理:
void prepare_to_wait(wait_queue_head_t *queue, wait_queue_t *wait, int state);
queue和wait分别地是等待队列头和进程入口.state是进程的新状态;它应当或者是TASK_INTERRUPTIBLE(给可中断的睡眠,这常常是你所要的)或者TASK_UNINTERRUPTIBLE(给
不可中断睡眠).
在调用 prepare_to_wait 之后, 进程可调用 schedule()进行休眠。从schedule()返回时,进程状态为TASK_RUNNING
schedule()返回后,就需要清理:void finish_wait(wait_queue_head_t *queue, wait_queue_t *wait);
阻塞进程,使用休眠
阻塞进程,使用休眠
读取函数scull_p_read:
static ssize_t scull_p_read (struct file *filp, char _ _ user *buf,size_t count, loff_t *f_ops)
{
struct scull_pipe *dev = filp->private_data;
if (down_interruptible(&dev->dem))//返回0表示信号量成功,返回1表示申请失败
return -ERESTARTYS;
while(dev-rp = = dev->wp)//无数据可读
{
up(&dev->dem);//释放信号量锁
if(filp->f_flags & O_NONBLOCK)//如果用户请求是非阻塞,则不能阻塞进程,退出。
return -EAGAIN;
if(wait_event_interrupible(dev->inq,(dev->rp!= dev->wp)))//阻塞读进程(即此进程),返回非0表示阻塞被中断唤醒,返回0,表示成功休眠读进程到dev->rp队列。
return -ERESTARTYS;
if(down_interruptible(&dev->dem)//当进程被唤醒,重新加锁准备进行读取,但先要重新进行while循环判断唤醒条件是否为真
return -ERESTARTYS;
}
/*数据准备就绪*/
if(dev->wp>dev->rp)
count = min(count,(size_t)(dev->wp-dev->rp));
else
count = min(count,(size_t)(dev->end-dev->rp));//dev->end指针指向此空间末端
/*
*调用copy_to_user将数据拷贝到用户空间过程中,可能会休眠。
*此时,虽然进程拥有互斥锁,但这种情况下拥有互斥锁休眠是可以接受的,
*因为我们知道内核会把数据复制到用户空间并唤醒我们,同时不会试图锁上同一个信号量
*/
if(copy_to_user(buf,dev->rp,count))//返回0表示读取count个值成功,返回非零数字表示还需读取字节数。dev->buff指针指向此空间开始处
{ up(&dev->dem);
returtn -EFAULT;
}
dev->rp+=count;
if(dev->rp==dev->end)
dev->rp == dev->buff;
up(&dev->dem);
/*最后唤醒写进程*/
wake_up_interruptible(&dev->outq);
reurn count;
}
static ssize_t scull_p_read (struct file *filp, char _ _ user *buf,size_t count, loff_t *f_ops)
{
struct scull_pipe *dev = filp->private_data;
if (down_interruptible(&dev->dem))//返回0表示信号量成功,返回1表示申请失败
return -ERESTARTYS;
while(dev-rp = = dev->wp)//无数据可读
{
up(&dev->dem);//释放信号量锁
if(filp->f_flags & O_NONBLOCK)//如果用户请求是非阻塞,则不能阻塞进程,退出。
return -EAGAIN;
if(wait_event_interrupible(dev->inq,(dev->rp!= dev->wp)))//阻塞读进程(即此进程),返回非0表示阻塞被中断唤醒,返回0,表示成功休眠读进程到dev->rp队列。
return -ERESTARTYS;
if(down_interruptible(&dev->dem)//当进程被唤醒,重新加锁准备进行读取,但先要重新进行while循环判断唤醒条件是否为真
return -ERESTARTYS;
}
/*数据准备就绪*/
if(dev->wp>dev->rp)
count = min(count,(size_t)(dev->wp-dev->rp));
else
count = min(count,(size_t)(dev->end-dev->rp));//dev->end指针指向此空间末端
/*
*调用copy_to_user将数据拷贝到用户空间过程中,可能会休眠。
*此时,虽然进程拥有互斥锁,但这种情况下拥有互斥锁休眠是可以接受的,
*因为我们知道内核会把数据复制到用户空间并唤醒我们,同时不会试图锁上同一个信号量
*/
if(copy_to_user(buf,dev->rp,count))//返回0表示读取count个值成功,返回非零数字表示还需读取字节数。dev->buff指针指向此空间开始处
{ up(&dev->dem);
returtn -EFAULT;
}
dev->rp+=count;
if(dev->rp==dev->end)
dev->rp == dev->buff;
up(&dev->dem);
/*最后唤醒写进程*/
wake_up_interruptible(&dev->outq);
reurn count;
}
学习写入函数scull_p_write之前,先学习处理真正休眠的代码:
/*使用spacefree函数判断是否有空间可写*/
/* How much space is free? */
static int spacefree(struct scull_pipe *dev)
{
if (dev->rp == dev->wp)//如果没有数据可读,说明空间是空的,全部可写
return dev->buffersize - 1;
return ((dev->rp + dev->buffersize - dev->wp) % dev->buffersize) - 1;//计算剩余空着可写入的空间
}
/*手动设置休眠*/
static int scull_getwritespace(struct scull_pipe *dev, struct file *filp)
{
while (spacefree(dev) == 0) { /* 没有空间可以写入,spacefree函数在上面定义*/
DEFINE_WAIT(wait);//创建并初始化一个等待队列入口
up(&dev->sem);
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
PDEBUG("\"%s\" writing: going to sleep\n",current->comm);
prepare_to_wait(&dev->outq, &wait, TASK_INTERRUPTIBLE);//将等待队列入口wait添加到dev->ouq等待队列头中
if (spacefree(dev) == 0)//检查休眠等待条件,如果不作检查,可能引入竞态
/*
*如果在上行的if判断和下行的schedule()调度之间,有了可写入空间,那么会发生什么情况?
*这种情况下没有任何问题,只要进程已经把自己放到了等待队列中并修改了进程状态,就不会有任何问题,
*schedule会把进程状态重新设置为TASK_RUNNING
*/
schedule();//当前进程让出CPU,进入等待休眠
finish_wait(&dev->outq, &wait);
if (signal_pending(current))
return -ERESTARTSYS; /* signal: tell the fs layer to handle it */
if (down_interruptible(&dev->sem))
return -ERESTARTSYS;
//注意wihle循环,被唤醒后重新判断是否可写
}
return 0;
}
学习写入函数scull_p_write,和读取函数类似:
static ssize_t scull_p_write(struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)
{
struct scull_pipe *dev = filp->private_data;
int result;
/*使用spacefree函数判断是否有空间可写*/
/* How much space is free? */
static int spacefree(struct scull_pipe *dev)
{
if (dev->rp == dev->wp)//如果没有数据可读,说明空间是空的,全部可写
return dev->buffersize - 1;
return ((dev->rp + dev->buffersize - dev->wp) % dev->buffersize) - 1;//计算剩余空着可写入的空间
}
/*手动设置休眠*/
static int scull_getwritespace(struct scull_pipe *dev, struct file *filp)
{
while (spacefree(dev) == 0) { /* 没有空间可以写入,spacefree函数在上面定义*/
DEFINE_WAIT(wait);//创建并初始化一个等待队列入口
up(&dev->sem);
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
PDEBUG("\"%s\" writing: going to sleep\n",current->comm);
prepare_to_wait(&dev->outq, &wait, TASK_INTERRUPTIBLE);//将等待队列入口wait添加到dev->ouq等待队列头中
if (spacefree(dev) == 0)//检查休眠等待条件,如果不作检查,可能引入竞态
/*
*如果在上行的if判断和下行的schedule()调度之间,有了可写入空间,那么会发生什么情况?
*这种情况下没有任何问题,只要进程已经把自己放到了等待队列中并修改了进程状态,就不会有任何问题,
*schedule会把进程状态重新设置为TASK_RUNNING
*/
schedule();//当前进程让出CPU,进入等待休眠
finish_wait(&dev->outq, &wait);
if (signal_pending(current))
return -ERESTARTSYS; /* signal: tell the fs layer to handle it */
if (down_interruptible(&dev->sem))
return -ERESTARTSYS;
//注意wihle循环,被唤醒后重新判断是否可写
}
return 0;
}
学习写入函数scull_p_write,和读取函数类似:
static ssize_t scull_p_write(struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)
{
struct scull_pipe *dev = filp->private_data;
int result;
if (down_interruptible(&dev->sem))
return -ERESTARTSYS;
return -ERESTARTSYS;
/* Make sure there's space to write */
result = scull_getwritespace(dev, filp);
if (result)
return result; /* scull_getwritespace called up(&dev->sem) */
result = scull_getwritespace(dev, filp);
if (result)
return result; /* scull_getwritespace called up(&dev->sem) */
/* ok, space is there, accept something */
count = min(count, (size_t)spacefree(dev));
if (dev->wp >= dev->rp)
count = min(count, (size_t)(dev->end - dev->wp)); /* to end-of-buf */
else /* the write pointer has wrapped, fill up to rp-1 */
count = min(count, (size_t)(dev->rp - dev->wp - 1));
PDEBUG("Going to accept %li bytes to %p from %p\n", (long)count, dev->wp, buf);
if (copy_from_user(dev->wp, buf, count)) {
up (&dev->sem);
return -EFAULT;
}
dev->wp += count;
if (dev->wp == dev->end)
dev->wp = dev->buffer; /* wrapped */
up(&dev->sem);
count = min(count, (size_t)spacefree(dev));
if (dev->wp >= dev->rp)
count = min(count, (size_t)(dev->end - dev->wp)); /* to end-of-buf */
else /* the write pointer has wrapped, fill up to rp-1 */
count = min(count, (size_t)(dev->rp - dev->wp - 1));
PDEBUG("Going to accept %li bytes to %p from %p\n", (long)count, dev->wp, buf);
if (copy_from_user(dev->wp, buf, count)) {
up (&dev->sem);
return -EFAULT;
}
dev->wp += count;
if (dev->wp == dev->end)
dev->wp = dev->buffer; /* wrapped */
up(&dev->sem);
/* finally, awake any reader */
wake_up_interruptible(&dev->inq); /* blocked in read() and select() */
wake_up_interruptible(&dev->inq); /* blocked in read() and select() */
/* and signal asynchronous readers, explained late in chapter 5 */
if (dev->async_queue)
kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
PDEBUG("\"%s\" did write %li bytes\n",current->comm, (long)count);
return count;
}
if (dev->async_queue)
kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
PDEBUG("\"%s\" did write %li bytes\n",current->comm, (long)count);
return count;
}
/******************************************************************************/
- 学习ldd3--阻塞型 IO(第六章)
- 学习ldd3--ioctl(第六章)
- 学习ldd3--poll(第六章)
- 学习ldd3--llseek(第六章)
- 学习ldd3--简单休眠(第六章)
- 学习ldd3--异步通知(第六章)
- 学习ldd3--访问控制(第六章)
- LTP 第六章 开发IO阻塞测试集
- 学习ldd3--tasklet(第七章)
- LDD3源码分析之阻塞型I/O
- LDD3源码分析之阻塞型I/O
- LDD3源码分析之阻塞型I/O
- LDD3源码分析之阻塞型I/O
- LDD3源码分析之阻塞型I/O
- LDD3源码分析之阻塞型I/O
- 嵌入式Web服务器学习之阻塞IO/非阻塞IO
- ldd3 5 继续学习ldd3
- 阻塞型io和非阻塞型io访问
- 从内存理解c语言中变量的存储类型
- 学习ldd3--异步通知(第六章)
- c_str
- 使用 Eclipse Memory Analyzer 检测内存泄漏问题
- 在Windows上安裝Cygwin/GMT系統
- 学习ldd3--阻塞型 IO(第六章)
- 民办院校招生乱象调查
- visitor模式
- 杭州烟花爆炸事故无人重伤-游客衣服包裹头逃生-杭州-烟花爆炸-烧伤
- 学习ldd3--llseek(第六章)
- 大师们对软件开发作的经典总结
- 学习ldd3--访问控制(第六章)
- 关于jsp中OnSubmit="return check()"感觉像无法进入的问题
- Bash Shell PS1: 10 Examples to Make Your Linux Prompt like Angelina Jolie