美文网首页我用 Linux
Linux内核--阻塞式I/O

Linux内核--阻塞式I/O

作者: shenyifu | 来源:发表于2016-05-24 14:10 被阅读237次

阻塞式i/o

如果无法立即满足请求,一个驱动程序应该如何响应:

比如一个进程尝试写,但是你的设备没有准备好接受数据,因为你的缓冲区是满的。调用过程通常不关心这些问题;程序员只是希望在必要的工作之后,呼叫读写,并有呼叫返回完成.因此,在这种情况下,你的驱动程序应该(默认)阻止进程,让它睡眠,直到请求可以继续。

睡眠

什么是睡眠:

当一个进程所请求的资源或操作无法立即完成,该进程的状态会被改变,它被放入阻塞队列知道有相应的事件发生,它才会被唤醒。

睡眠的规矩

1、如果线程A持有锁,比如自旋锁,那A一定不能睡眠

2、一定要记得,当线程A被唤醒的时候,A不知道这段时间发生了什么,任何假设都是不成立的。

3、当然还有一点线程A睡眠前,一定要确保有另一个线程B一定会把A叫醒。

如何找到睡眠的进程

当进程睡眠的时候它会到等待队列中注册,负责叫醒的线程只要到该等待队列中把所有睡眠的线程叫醒就行了。

等待队列被定义在<linux/wait.h>中。
一般的等待队列是这样声明和初始化的:

wait_queue_head_t my_queue;
init_waitqueue_head(&my_queue);

Sleeping API

wait_event(queue , condition);
wait_event_interruptible(queue , condition);
wait_event_timeout(queue , condition , timeout);
wait_event_interruptible_timeout(queue , condition , timeout);
void wake_up(wait_queue_head_t *queue);
void wake_up_interruptible(wait_queue_head_t *queue);

如何实现一个阻塞式的i/o如管道:

ssize_t scull_read(struct file *filp , char __user *buf, size_t count,loff_t *f_pos)
{
if (down_interruptible(&mutex))
return -ERESTARTSYS;
ssize_t retval = 0;
while (size == 0) {
up(&mutex);
if (wait_event_interruptible(inq, (size != 0)))
return -ERESTARTSYS; /* signal: tell the fs layer to
handle it */
if (down_interruptible(&mutex))
return -ERESTARTSYS;
}
if (count > size)
count = size;
if (outp + count > MAX_SIZE){
if (copy_to_user(buf, store + outp, MAX_SIZE - outp)) {
      retval = -EFAULT;
      goto out;
    }
    if (copy_to_user(buf+ MAX_SIZE - outp, store, count + outp-MAX_SIZE)) {
      retval = -EFAULT;
      goto out;
    }

}else{
if (copy_to_user(buf, store + outp , count)) {
retval = -EFAULT;
goto out;
}}
outp += count;
outp = (outp + count) % MAX_SIZE;
retval = count;
size -= count;
out:
up(&mutex);
wake_up_interruptible(&outq);
return retval;
}

ssize_t scull_write(struct file *filp , char __user *buf, size_t count,loff_t *f_pos)
{
if (down_interruptible(&mutex))
return -ERESTARTSYS;
ssize_t retval = 0;
while (size == MAX_SIZE) {
up(&mutex);
if (wait_event_interruptible(outq, (size != MAX_SIZE)))
return -ERESTARTSYS; /* signal: tell the fs layer tohandle it */
if (down_interruptible(&mutex))
return -ERESTARTSYS;
}
if (count > MAX_SIZE - size)
count =MAX_SIZE - size;
if (outp + count +size > MAX_SIZE){
 if (copy_from_user(store + outp+size , buf, MAX_SIZE - outp - size)) {
      retval = -EFAULT;
      goto out;
    }
    if (copy_from_user(store, buf+MAX_SIZE - outp - size, count+outp + size-MAX_SIZE)) {
      retval = -EFAULT;
      goto out;
    }

}else{
 if (copy_from_user(store + outp +size , buf, MAX_SIZE - outp - size)) {
      retval = -EFAULT;
      goto out;
    }}
size+= count;
retval = count;
out:
up(&mutex);
wake_up_interruptible(&inq);
return retval;
}

其他部分请参考:Linux内核--简单的字符设备scull

相关文章

  • Linux I/O模型的前世今生

    Linux I/O模型 阻塞式I/O模型 非阻塞式I/O模型 I/O复用式模型 信号驱动式I/O模型 异步I/O模...

  • Linux内核--阻塞式I/O

    阻塞式i/o 如果无法立即满足请求,一个驱动程序应该如何响应: 比如一个进程尝试写,但是你的设备没有准备好接受数据...

  • 关于I/O模型的记录

    I/O模型的种类 阻塞式I/O、非阻塞式I/O、I/O复用(select, poll)、信号驱动式I/O(SIGI...

  • Netty理论一:Java IO与NIO

    1、Linux IO模型 1、《Unix网络编程》把I/O模型分成五类阻塞式I/O模型:整个过程都是阻塞的——BI...

  • Unix网络编程-I/O模型

    1. I/O 模型 Unix下可用的5种I/O模型: 阻塞式I/O; 非阻塞式I/O; I/O复用(select ...

  • Socket

    一、I/O 模型阻塞式 I/O非阻塞式 I/OI/O 复用信号驱动 I/O异步 I/O五大 I/O 模型比较 二、...

  • io多路复用 select poll epoll

    unix下的五中I/0模型: 阻塞式I/O 非阻塞式I/O I/O多路复用 信号驱动式I/O 异步I/O(POSI...

  • Uinx系统下的I/O模型

    5种I/O模型的基本区别: 阻塞式I/O 非阻塞式I/O I/O复用(select,poll,epoll) 信号驱...

  • Unix系统下的I/O模型

    Unix系统下一共有5种I/O模型: 阻塞式I/O; 非阻塞式I/O; I/O复用(select 和 poll);...

  • Linux5种I/O模型

    Linux的5种I/O模型分别为: 1)阻塞I/O(blocking I/O)2)非阻塞I/O(nonblocki...

网友评论

    本文标题:Linux内核--阻塞式I/O

    本文链接:https://www.haomeiwen.com/subject/zldirttx.html