这是个很有趣的topic,而且这个东东影响到了kernel/driver和application之间的交互。
首先要来说下这个概念的东东。 当应用程序被block后,这个程序就进入了sleep状态。有可能会block的地方有:
1. open
2. read
3. write
一般情况下,文件的读写是阻塞的,可以通过fcntl()函数来设置为非阻塞读写。且这一点需要driver的配合 。
好,来看看一个实际的例子的片段。
driver部分:如果该文件设置了O_NONBLOCK,则直接返回-EAGAIN。
static ssize_t scull_p_read (struct file *filp, char __user *buf, size_t count,
loff_t *f_pos)
{
struct scull_pipe *dev = filp->private_data;
if (down_interruptible(&dev->sem))
return -ERESTARTSYS;
while (dev->rp == dev->wp) { /* nothing to read */
up(&dev->sem); /* release the lock */
if (filp->f_flags & O_NONBLOCK)
{
PDEBUG("nonblock version read\n" );
return -EAGAIN;
}
PDEBUG("\"%s\" reading: going to sleep\n", current->comm);
if (wait_event_interruptible(dev->inq, (dev->rp != dev->wp)))
return -ERESTARTSYS; /* signal: tell the fs layer to handle it */
/* otherwise loop, but first reacquire the lock */
if (down_interruptible(&dev->sem))
return -ERESTARTSYS;
}
/* ok, data is there, return something */
if (dev->wp > dev->rp)
count = min(count, (size_t)(dev->wp - dev->rp));
else /* the write pointer has wrapped, return data up to dev->end */
count = min(count, (size_t)(dev->end - dev->rp));
if (copy_to_user(buf, dev->rp, count)) {
up (&dev->sem);
return -EFAULT;
}
dev->rp += count;
if (dev->rp == dev->end)
dev->rp = dev->buffer; /* wrapped */
up (&dev->sem);
/* finally, awake any writers and return */
wake_up_interruptible(&dev->outq);
PDEBUG("\"%s\" did read %li bytes\n",current->comm, (long)count);
return count;
}
application部分:
使用fcntl()设置了O_NONBLOCK,这样在read的时候,就会立即返回。
而且再判断了返回值,EAGAIN表示需要再试。
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
char buffer[4096];
int main(int argc, char **argv)
{
int delay = 1, n, m = 0;
int fd;
if (argc > 1)
delay=atoi(argv[1]);
fd = open("/dev/scullpipe0",O_RDWR );
fcntl(fd, F_SETFL, fcntl(fd,F_GETFL) | O_NONBLOCK);
while (1) {
n = read(fd, buffer, 4096);
printf("return value from read is %d\n", n);
if (n >= 0)
m = write(1, buffer, n); /* stdout */
if ((n < 0 || m < 0) && (errno != EAGAIN ))
break;
sleep(delay);
}
perror(n < 0 ? "stdin" : "stdout");
exit(1);
}