scull-pipe.c

/*
 * pipe.c -- fifo driver for scull
 *
 * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
 * Copyright (C) 2001 O'Reilly & Associates
 *
 * The source code in this file can be freely used, adapted,
 * and redistributed in source or binary form, so long as an
 * acknowledgment appears in derived source files.  The citation
 * should list that the code comes from the book "Linux Device
 * Drivers" by Alessandro Rubini and Jonathan Corbet, published
 * by O'Reilly & Associates.   No warranty is attached;
 * we cannot take responsibility for errors or fitness for use.
 *
 */
 
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/sched.h> 
#include <linux/kernel.h>	/* printk(), min() */
#include <linux/slab.h>		/* kmalloc() */
#include <linux/fs.h>		/* everything... */
#include <linux/proc_fs.h>
#include <linux/errno.h>	/* error codes */
#include <linux/types.h>	/* size_t */
#include <linux/fcntl.h>
#include <linux/poll.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>

#include "scull.h"		/* local definitions */

struct scull_pipe {
        wait_queue_head_t inq, outq;       /* read and write queues */
        char *buffer, *end;                /* begin of buf, end of buf */
        int buffersize;                    /* used in pointer arithmetic */
        char *rp, *wp;                     /* where to read, where to write */
        int nreaders, nwriters;            /* number of openings for r/w */
        struct fasync_struct *async_queue; /* asynchronous readers */
        struct semaphore sem;              /* mutual exclusion semaphore */
        struct cdev cdev;                  /* Char device structure */
};

/* parameters */
static int scull_p_nr_devs = SCULL_P_NR_DEVS;	/* number of pipe devices */
int scull_p_buffer =  SCULL_P_BUFFER;	/* buffer size */
dev_t scull_p_devno;			/* Our first device number */

module_param(scull_p_nr_devs, int, 0);	/* FIXME check perms */
module_param(scull_p_buffer, int, 0);

static struct scull_pipe *scull_p_devices;

static int scull_p_fasync(int fd, struct file *filp, int mode);
static int spacefree(struct scull_pipe *dev);
/*
 * Open and close
 */


static int scull_p_open(struct inode *inode, struct file *filp)
{
	struct scull_pipe *dev;

	dev = container_of(inode->i_cdev, struct scull_pipe, cdev);
	filp->private_data = dev;

	if (down_interruptible(&dev->sem))
		return -ERESTARTSYS;
	if (!dev->buffer) {
		/* allocate the buffer */
		dev->buffer = kmalloc(scull_p_buffer, GFP_KERNEL);
		if (!dev->buffer) {
			up(&dev->sem);
			return -ENOMEM;
		}
	}
	dev->buffersize = scull_p_buffer;
	dev->end = dev->buffer + dev->buffersize;
	dev->rp = dev->wp = dev->buffer; /* rd and wr from the beginning */

	/* use f_mode,not  f_flags: it's cleaner (fs/open.c tells why) */
	if (filp->f_mode & FMODE_READ)
		dev->nreaders++;
	if (filp->f_mode & FMODE_WRITE)
		dev->nwriters++;
	up(&dev->sem);

	return nonseekable_open(inode, filp);
}



static int scull_p_release(struct inode *inode, struct file *filp)
{
	struct scull_pipe *dev = filp->private_data;

	/* remove this filp from the asynchronously notified filp's */
	scull_p_fasync(-1, filp, 0);
	down(&dev->sem);
	if (filp->f_mode & FMODE_READ)
		dev->nreaders--;
	if (filp->f_mode & FMODE_WRITE)
		dev->nwriters--;
	if (dev->nreaders + dev->nwriters == 0) {
		kfree(dev->buffer);
		dev->buffer = NULL; /* the other fields are not checked on open */
	}
	up(&dev->sem);
	return 0;
}


/*
 * Data management: read and write
 */

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)
			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;
}

/* Wait for space for writing; caller must hold device semaphore.  On
 * error the semaphore will be released before returning. */
static int scull_getwritespace(struct scull_pipe *dev, struct file *filp)
{
	while (spacefree(dev) == 0) { /* full */
		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);
		if (spacefree(dev) == 0)
			schedule();
		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;
	}
	return 0;
}	

/* 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 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;

	/* Make sure there's space to write */
	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);

	/* finally, awake any reader */
	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;
}

static unsigned int scull_p_poll(struct file *filp, poll_table *wait)
{
	struct scull_pipe *dev = filp->private_data;
	unsigned int mask = 0;

	/*
	 * The buffer is circular; it is considered full
	 * if "wp" is right behind "rp" and empty if the
	 * two are equal.
	 */
	down(&dev->sem);
	poll_wait(filp, &dev->inq,  wait);
	poll_wait(filp, &dev->outq, wait);
	if (dev->rp != dev->wp)
		mask |= POLLIN | POLLRDNORM;	/* readable */
	if (spacefree(dev))
		mask |= POLLOUT | POLLWRNORM;	/* writable */
	up(&dev->sem);
	return mask;
}





static int scull_p_fasync(int fd, struct file *filp, int mode)
{
	struct scull_pipe *dev = filp->private_data;

	return fasync_helper(fd, filp, mode, &dev->async_queue);
}


/********************************************************************************/
/* FIXME this should use seq_file */
#ifdef SCULL_DEBUG
static void scullp_proc_offset(char *buf, char **start, off_t *offset, int *len)
{
	if (*offset == 0)
		return;
	if (*offset >= *len) {	/* Not there yet */
		*offset -= *len;
		*len = 0;
	}
	else {			/* We're into the interesting stuff now */
		*start = buf + *offset;
		*offset = 0;
	}
}


static int scull_read_p_mem(char *buf, char **start, off_t offset, int count,
		int *eof, void *data)
{
	int i, len;
	struct scull_pipe *p;

#define LIMIT (PAGE_SIZE-200)	/* don't print any more after this size */
	*start = buf;
	len = sprintf(buf, "Default buffersize is %i\n", scull_p_buffer);
	for(i = 0; i<scull_p_nr_devs && len <= LIMIT; i++) {
		p = &scull_p_devices[i];
		if (down_interruptible(&p->sem))
			return -ERESTARTSYS;
		len += sprintf(buf+len, "\nDevice %i: %p\n", i, p);
/*		len += sprintf(buf+len, "   Queues: %p %p\n", p->inq, p->outq);*/
		len += sprintf(buf+len, "   Buffer: %p to %p (%i bytes)\n", p->buffer, p->end, p->buffersize);
		len += sprintf(buf+len, "   rp %p   wp %p\n", p->rp, p->wp);
		len += sprintf(buf+len, "   readers %i   writers %i\n", p->nreaders, p->nwriters);
		up(&p->sem);
		scullp_proc_offset(buf, start, &offset, &len);
	}
	*eof = (len <= LIMIT);
	return len;
}


#endif
/********************************************************************************/


/*
 * The file operations for the pipe device
 * (some are overlayed with bare scull)
 */
struct file_operations scull_pipe_fops = {
	.owner =	THIS_MODULE,
	.llseek =	no_llseek,
	.read =		scull_p_read,
	.write =	scull_p_write,
	.poll =		scull_p_poll,
	.ioctl =	scull_ioctl,
	.open =		scull_p_open,
	.release =	scull_p_release,
	.fasync =	scull_p_fasync,
};


/*
 * Set up a cdev entry.
 */
static void scull_p_setup_cdev(struct scull_pipe *dev, int index)
{
    int err, devno = scull_p_devno + index;
    
    cdev_init(&dev->cdev, &scull_pipe_fops);//设备绑定file_operation,所有设备都绑定了同一个
    dev->cdev.owner = THIS_MODULE;
    err = cdev_add (&dev->cdev, devno, 1);//设备绑定设备号
    /* Fail gracefully if need be */
    if (err)
        printk(KERN_NOTICE "Error %d adding scullpipe%d", err, index);
}

/*
 * Initialize the pipe devs; return how many we did.
 */
int scull_p_init(dev_t firstdev)
{
	int i, result;

	result = register_chrdev_region(firstdev, scull_p_nr_devs, "scullp");

	if (result < 0) {
		printk(KERN_NOTICE "Unable to get scullp region, error %d\n", result);
		return 0;
	}
	scull_p_devno = firstdev;
	scull_p_devices = kmalloc(scull_p_nr_devs * sizeof(struct scull_pipe), GFP_KERNEL);
	if (scull_p_devices == NULL) {
		unregister_chrdev_region(firstdev, scull_p_nr_devs);
		return 0;
	}
	memset(scull_p_devices, 0, scull_p_nr_devs * sizeof(struct scull_pipe));
	for (i = 0; i < scull_p_nr_devs; i++) {
		init_waitqueue_head(&(scull_p_devices[i].inq));
		init_waitqueue_head(&(scull_p_devices[i].outq));
		init_MUTEX(&scull_p_devices[i].sem);
		scull_p_setup_cdev(scull_p_devices + i, i);


	}
/********************************************************************************/
#ifdef SCULL_DEBUG
	create_proc_read_entry("scullpipe", 0, NULL, scull_read_p_mem, NULL);
#endif
/********************************************************************************/
	return scull_p_nr_devs;
}

/*
 * This is called by cleanup_module or on failure.
 * It is required to never fail, even if nothing was initialized first
 */
void scull_p_cleanup(void)
{
	int i;

#ifdef SCULL_DEBUG
	remove_proc_entry("scullpipe", NULL);
#endif

	if (!scull_p_devices)
		return; /* nothing else to release */

	for (i = 0; i < scull_p_nr_devs; i++) {
		cdev_del(&scull_p_devices[i].cdev);
		kfree(scull_p_devices[i].buffer);
	}
	kfree(scull_p_devices);
	unregister_chrdev_region(scull_p_devno, scull_p_nr_devs);
	scull_p_devices = NULL; /* pedantic */
}
数据结构图


****************************************************************************************************************************
line 348为scullp申请一个设备号,成功后会在/pro/devices里记录设备名scullp和主设备号
用scull_load脚本读取主设备号,在/dev下mknod字符设备文件 scullpipe0, scullpipe1, scullpipe2, scullpipe3
若是DEBUG版本,执行line369 create_proc_read_entry 函数在/proc下生成一个 scullpipe虚拟文件

1.line348 申请4个设备号--scull_p_nr_devs=4,主设备号相同均为MAJOR(fistdev),次设备号分别是MIMOR(fistdev),MIMOR(fistdev+1),MIMOR(fistdev+2),MIMOR(fistdev+3),
2.line355 创建4块内存区域,分别当成4个字符设备scull_pipe

3.line365 调用4次scull_p_setup_cdev,每次注册一个scull_pipe设备(实际是scull_pipe->cdev)为每个设备绑定上面申请的设备号
函数原型
static void scull_p_setup_cdev(struct scull_pipe *dev, int index)
{
	int err, devno = scull_p_devno + index;
    
	cdev_init(&dev->cdev, &scull_pipe_fops);//设备绑定file_operation,所有设备都绑定了同一个
	dev->cdev.owner = THIS_MODULE;
	err = cdev_add (&dev->cdev, devno, 1);//设备绑定设备号
	/* Fail gracefully if need be */
	if (err)
		printk(KERN_NOTICE "Error %d adding scullpipe%d", err, index);
}
参数是设备和设备序号(设备序号index不代表是次设备号,
比如要申请4个设备,得到的第一个设备号fistdev=248 4,则设备序号index为1的设备号应该是248 5)

***********************************************************************************************************************
scull_load

/dev/scullpipe0,/dev/scullpipe1,/dev/scullpipe2,/dev/scullpipe3分别对应line 355创建的4个设备
mknod /dev/${device}pipe0 c $major 4  
mknod /dev/${device}pipe1 c $major 5  
mknod /dev/${device}pipe2 c $major 6  
mknod /dev/${device}pipe3 c $major 7  
****************************************************************************************************************************
实现
阻塞型read,write
即用户进程每次read系统调用时,如果没有可用数据,即rp=wp,进程要阻塞
比如用如下程序测试读/dev/scullpipe0

    /********************************read_test.c**************/  
    #include <stdio.h>  
    #include <unistd.h>  
    #include <stdlib.h>  
    #include <sys/types.h>  
    #include <sys/stat.h>  
    #include <sys/ioctl.h>  
    #include <fcntl.h>  
    #include <linux/fs.h>  
    #include <errno.h>  
    #include <string.h>  
    #define COUNT 10
    int main(int argc,char* argv[])  
    {     
        fprintf(stderr, "press Ctrl-C to stop\n");  
        int fd = open(argv[1], 0);  
        if (fd < 0) {  
            perror("open file ");  
            return 1;  
        }  
        char *buffer=malloc(COUNT);  
        int i;  
        for(i=0;i<2;i++)  
        {  
           // lseek(fd,i,SEEK_SET);  
            int len = read(fd, buffer, COUNT);
            if (len > 0) {  
                printf("value: %s\n", buffer);  
            } else {  
                perror("error:");  
                return 1;  
            }  
        }  
      	free(buffer);  
        close(fd);  
    }  
1.先执行[root@localhost scull]# ./read_test  /dev/scullpipe0
由于scullpipe0空,rp=wp,进程被line131阻塞
if (wait_event_interruptible(dev->inq, (dev->rp != dev->wp)))
2.再执行[root@localhost scull]# echo hello>/dev/scullpipe0
此时 read_test打印出
value: hello
但进程 read_test仍然被阻塞,因为进程要循环调用两次read,第一次read虽然要读10bytes,但是scullpipe0里只有5bytes,所以就读取了5bytes,并立即返回进行下一次read系统调用,这由line139决定
 count = min(count, (size_t)(dev->wp - dev->rp));
然后第二次read系统调用时,尽管scullpipe0不为空,但rp=wp,所以又阻塞
3.再执行[root@localhost scull]# echo hi>/dev/scullpipe0
此时 read_test打印出
value: hi
并且进程 read_test结束
当然如果2中执行 echo hellohelloh>/dev/scullpipe0,由于scullpipe0中数据已经大于10bytes,则 read_test会顺利执行两次read而不被阻塞而结束
可见用户程序每次对设备文件执行read系统调用时,会不会发生阻塞,什么情况下发生阻塞,完全由相应设备的file_operation的read函数决定
本例中仅仅是当wp=rp时会阻塞,而进程每次read字节数>文件中可用字节数时,没有采取阻塞,而是返回给进程可用字节
如果用strace测试一下内部情况可以看到:
[root@localhost scull]# strace ./read_test   /dev/scullpipe0
execve("./read_test", ["./read_test", "/dev/scullpipe0"], [/* 44 vars */]) = 0
brk(0)                                  = 0x8498000
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77b9000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=142866, ...}) = 0
mmap2(NULL, 142866, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7796000
close(3)                                = 0
open("/lib/libc.so.6", O_RDONLY)        = 3
read(3, "\177ELF\1\1\1\3\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\220\377l\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1847224, ...}) = 0
mmap2(0x6b9000, 1612328, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x110000
mprotect(0x293000, 4096, PROT_NONE)     = 0
mmap2(0x294000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x183) = 0x294000
mmap2(0x297000, 10792, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x297000
close(3)                                = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7795000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb77956c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0x294000, 8192, PROT_READ)     = 0
mprotect(0x6b5000, 4096, PROT_READ)     = 0
munmap(0xb7796000, 142866)              = 0
write(2, "press Ctrl-C to stop\n", 21press Ctrl-C to stop
)  = 21
open("/dev/scullpipe0", O_RDONLY)       = 3
brk(0)                                  = 0x8498000
brk(0x84b9000)                          = 0x84b9000
brk(0)                                  = 0x84b9000
read(3, "hello\n", 10)                  = 6
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77b8000
write(1, "value: hello\n", 13value: hello
)          = 13
write(1, "\n", 1
)                       = 1
read(3, "hi\n", 10)                     = 3
write(1, "value: hi\nlo\n", 13value: hi
lo
)         = 13
write(1, "\n", 1
)                       = 1
close(3)                                = 0
exit_group(0)                           = ?
[root@localhost scull]# 

留意一下line29要读10bytes但实际读了6bytes(hello\n),line36要读10bytes但实际读了3bytes(hi\n)
同样可以测试一下head和cat的工作原理
比如要读scullpipe0前3行,先执行strace head -3 /dev/scullpipe0,然后输入3次 echo hi>/dev/scullpipe0,反应如下
[root@localhost scull]# strace head -3 /dev/scullpipe0
execve("/usr/bin/head", ["head", "-3", "/dev/scullpipe0"], [/* 44 vars */]) = 0
brk(0)                                  = 0x8a12000
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78fc000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=142866, ...}) = 0
mmap2(NULL, 142866, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb78d9000
close(3)                                = 0
open("/lib/libc.so.6", O_RDONLY)        = 3
read(3, "\177ELF\1\1\1\3\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\220\377l\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1847224, ...}) = 0
mmap2(0x6b9000, 1612328, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x6b9000
mprotect(0x83c000, 4096, PROT_NONE)     = 0
mmap2(0x83d000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x183) = 0x83d000
mmap2(0x840000, 10792, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x840000
close(3)                                = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78d8000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb78d86c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0x83d000, 8192, PROT_READ)     = 0
mprotect(0x6b5000, 4096, PROT_READ)     = 0
munmap(0xb78d9000, 142866)              = 0
brk(0)                                  = 0x8a12000
brk(0x8a33000)                          = 0x8a33000
brk(0)                                  = 0x8a33000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=99158720, ...}) = 0
mmap2(NULL, 2097152, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb76d8000
close(3)                                = 0
open("/dev/scullpipe0", O_RDONLY|O_LARGEFILE) = 3
read(3, "hi\n", 8192)                   = 3
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78fb000
write(1, "hi\n", 3hi
)                     = 3
read(3, "hi\n", 8192)                   = 3
write(1, "hi\n", 3hi
)                     = 3
read(3, "hi\n", 8192)                   = 3
_llseek(3, 0, 0xbf819cc0, SEEK_CUR)     = -1 ESPIPE (Illegal seek)
fstat64(3, {st_mode=S_IFCHR|0664, st_rdev=makedev(247, 4), ...}) = 0
write(1, "hi\n", 3hi
)                     = 3
close(3)                                = 0
close(1)                                = 0
munmap(0xb78fb000, 4096)                = 0
close(2)                                = 0
exit_group(0)                           = ?
留意line31,36,39,看出head内的read每次要读8192bytes
再看一下cat
先执行strace cat  /dev/scullpipe0,然后一直输入 echo hi>/dev/scullpipe0,反应如下
[root@localhost scull]# strace cat /dev/scullpipe0
execve("/bin/cat", ["cat", "/dev/scullpipe0"], [/* 44 vars */]) = 0
brk(0)                                  = 0x9362000
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7821000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=142866, ...}) = 0
mmap2(NULL, 142866, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb77fe000
close(3)                                = 0
open("/lib/libc.so.6", O_RDONLY)        = 3
read(3, "\177ELF\1\1\1\3\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\220\377l\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1847224, ...}) = 0
mmap2(0x6b9000, 1612328, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x110000
mprotect(0x293000, 4096, PROT_NONE)     = 0
mmap2(0x294000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x183) = 0x294000
mmap2(0x297000, 10792, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x297000
close(3)                                = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77fd000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb77fd6c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0x294000, 8192, PROT_READ)     = 0
mprotect(0x6b5000, 4096, PROT_READ)     = 0
munmap(0xb77fe000, 142866)              = 0
brk(0)                                  = 0x9362000
brk(0x9383000)                          = 0x9383000
brk(0)                                  = 0x9383000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=99158720, ...}) = 0
mmap2(NULL, 2097152, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb75fd000
close(3)                                = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
open("/dev/scullpipe0", O_RDONLY|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFCHR|0664, st_rdev=makedev(247, 4), ...}) = 0
read(3, "hi\n", 32768)                  = 3
write(1, "hi\n", 3hi
)                     = 3
read(3, "hi\n", 32768)                  = 3
write(1, "hi\n", 3hi
)                     = 3
read(3, "hi\n", 32768)                  = 3
write(1, "hi\n", 3hi
)                     = 3
read(3, "hi\n", 32768)                  = 3
write(1, "hi\n", 3hi
)                     = 3
read(3, "hi\n", 32768)                  = 3
write(1, "hi\n", 3hi
)                     = 3
read(3, 
看来cat是每次读取32768bytes=32KB,并且是一直循环读
***********************************************************************************************************************
当然,在读/dev/scull0是不阻塞的,每次执行read系统调用,不管有没有数据,都会返回
比如先向scull0里写点数据
[root@localhost scull]# ll pipe.c
-rw-r--r--. 1 502 games 11368 Sep 14 16:29 pipe.c
[root@localhost scull]# cat pipe.c >/dev/scull0
用read_test测试
[root@localhost scull]# ./read_test   /dev/scull0
press Ctrl-C to stop
value: /*
 * pipe
value: .c -- fifo

[root@localhost scull]# strace ./read_test   /dev/scull0
execve("./read_test", ["./read_test", "/dev/scull0"], [/* 44 vars */]) = 0
brk(0)                                  = 0x9d96000
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7798000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=142866, ...}) = 0
mmap2(NULL, 142866, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7775000
close(3)                                = 0
open("/lib/libc.so.6", O_RDONLY)        = 3
read(3, "\177ELF\1\1\1\3\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\220\377l\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1847224, ...}) = 0
mmap2(0x6b9000, 1612328, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x6b9000
mprotect(0x83c000, 4096, PROT_NONE)     = 0
mmap2(0x83d000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x183) = 0x83d000
mmap2(0x840000, 10792, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x840000
close(3)                                = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7774000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb77746c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0x83d000, 8192, PROT_READ)     = 0
mprotect(0x6b5000, 4096, PROT_READ)     = 0
munmap(0xb7775000, 142866)              = 0
write(2, "press Ctrl-C to stop\n", 21press Ctrl-C to stop
)  = 21
open("/dev/scull0", O_RDONLY)           = 3
brk(0)                                  = 0x9d96000
brk(0x9db7000)                          = 0x9db7000
brk(0)                                  = 0x9db7000
read(3, "/*\n * pipe", 10)              = 10
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7797000
write(1, "value: /*\n", 10value: /*
)             = 10
write(1, " * pipe\n", 8 * pipe
)                = 8
read(3, ".c -- fifo", 10)               = 10
write(1, "value: .c -- fifo\n", 18value: .c -- fifo
)     = 18
close(3)                                = 0
exit_group(0)                           = ?

read_test按照循环执行了两次read,每次都读了10bytes

用head测试
[root@localhost scull]# head -3  /dev/scull0
/*
 * pipe.c -- fifo driver for scull
 *

[root@localhost scull]# strace head -3  /dev/scull0
execve("/usr/bin/head", ["head", "-3", "/dev/scull0"], [/* 44 vars */]) = 0
brk(0)                                  = 0x9c6b000
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78c5000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=142866, ...}) = 0
mmap2(NULL, 142866, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb78a2000
close(3)                                = 0
open("/lib/libc.so.6", O_RDONLY)        = 3
read(3, "\177ELF\1\1\1\3\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\220\377l\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1847224, ...}) = 0
mmap2(0x6b9000, 1612328, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x6b9000
mprotect(0x83c000, 4096, PROT_NONE)     = 0
mmap2(0x83d000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x183) = 0x83d000
mmap2(0x840000, 10792, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x840000
close(3)                                = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78a1000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb78a16c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0x83d000, 8192, PROT_READ)     = 0
mprotect(0x6b5000, 4096, PROT_READ)     = 0
munmap(0xb78a2000, 142866)              = 0
brk(0)                                  = 0x9c6b000
brk(0x9c8c000)                          = 0x9c8c000
brk(0)                                  = 0x9c8c000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=99158720, ...}) = 0
mmap2(NULL, 2097152, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb76a1000
close(3)                                = 0
open("/dev/scull0", O_RDONLY|O_LARGEFILE) = 3
read(3, "/*\n * pipe.c -- fifo driver for "..., 8192) = 4000
_llseek(3, -3959, [41], SEEK_CUR)       = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78c4000
write(1, "/*\n", 3/*
)                     = 3
write(1, " * pipe.c -- fifo driver for scu"..., 35 * pipe.c -- fifo driver for scull
) = 35
write(1, " *\n", 3 *
)                     = 3
close(3)                                = 0
close(1)                                = 0
munmap(0xb78c4000, 4096)                = 0
close(2)                                = 0
exit_group(0)                           = ?
[root@localhost scull]# 
仅读一次,在line36 read了4000bytes,但调用3次write到标准输出...

再看一下cat
[root@localhost scull]# cat   /dev/scull0
/*
 * pipe.c -- fifo driver for scull
 *
 * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
 * Copyright (C) 2001 O'Reilly & Associates
 *
 * The source code in this file can be freely used, adapted,
 * and redistributed in source or binary form, so long as an
 * acknowledgment appears in derived source files.  The citation
 * should list that the code comes from the book "Linux Device
 * Drivers" by Alessandro Rubini and Jonathan Corbet, published
 * by O'Reilly & Associates.   No warranty is attached;
 * we cannot take responsibility for errors or fitness for use.
 *
 */
 
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/sched.h> 
#include <linux/kernel.h>	/* printk(), min() */
#include <linux/slab.h>		/* kmalloc() */
...
[root@localhost scull]# strace cat   /dev/scull0
execve("/bin/cat", ["cat", "/dev/scull0"], [/* 44 vars */]) = 0
brk(0)                                  = 0x9926000
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78b5000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=142866, ...}) = 0
mmap2(NULL, 142866, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7892000
close(3)                                = 0
open("/lib/libc.so.6", O_RDONLY)        = 3
read(3, "\177ELF\1\1\1\3\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\220\377l\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1847224, ...}) = 0
mmap2(0x6b9000, 1612328, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x6b9000
mprotect(0x83c000, 4096, PROT_NONE)     = 0
mmap2(0x83d000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x183) = 0x83d000
mmap2(0x840000, 10792, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x840000
close(3)                                = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7891000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb78916c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0x83d000, 8192, PROT_READ)     = 0
mprotect(0x6b5000, 4096, PROT_READ)     = 0
munmap(0xb7892000, 142866)              = 0
brk(0)                                  = 0x9926000
brk(0x9947000)                          = 0x9947000
brk(0)                                  = 0x9947000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=99158720, ...}) = 0
mmap2(NULL, 2097152, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7691000
close(3)                                = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
open("/dev/scull0", O_RDONLY|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFCHR|0664, st_rdev=makedev(247, 0), ...}) = 0
read(3, "/*\n * pipe.c -- fifo driver for "..., 32768) = 4000
write(1, "/*\n * pipe.c -- fifo driver for "..., 4000/*
 * pipe.c -- fifo driver for scull
 *
 * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
 * Copyright (C) 2001 O'Reilly & Associates
 *
 * The source code in this file can be freely used, adapted,
 * and redistributed in source or binary form, so long as an
 * acknowledgment appears in derived source files.  The citation
 * should list that the code comes from the book "Linux Device
 * Drivers" by Alessandro Rubini and Jonathan Corbet, published
 * by O'Reilly & Associates.   No warranty is attached;
 * we cannot take responsibility for errors or fitness for use.
 *
 */
 
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/sched.h> 
#include <linux/kernel.h>    /* printk(), min() */
#include <linux/slab.h>        /* kmalloc() */
#include <linux/fs.h>        /* everything... */
#include <linux/proc_fs.h>
#include <linux/errno.h>    /* error codes */
#include <linux/types.h>    /* size_t */
#include <linux/fcntl.h>
#include <linux/poll.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>

#include "scull.h"        /* local definitions */

struct scull_pipe {
        wait_queue_head_t inq, outq;       /* read and write queues */
        char *buffer, *end;                /* begin of buf, end of buf */
        int buffersize;                    /* used in pointer arithmetic */
        char *rp, *wp;                     /* where to read, where to write */
        int nreaders, nwriters;            /* number of openings for r/w */
        struct fasync_struct *async_queue; /* asynchronous readers */
        struct semaphore sem;              /* mutual exclusion semaphore */
        struct cdev cdev;                  /* Char device structure */
};

/* parameters */
static int scull_p_nr_devs = SCULL_P_NR_DEVS;    /* number of pipe devices */
int scull_p_buffer =  SCULL_P_BUFFER;    /* buffer size */
dev_t scull_p_devno;            /* Our first device number */

module_param(scull_p_nr_devs, int, 0);    /* FIXME check perms */
module_param(scull_p_buffer, int, 0);

static struct scull_pipe *scull_p_devices;

static int scull_p_fasync(int fd, struct file *filp, int mode);
static int spacefree(struct scull_pipe *dev);
/*
 * Open and close
 */


static int scull_p_open(struct inode *inode, struct file *filp)
{
    struct scull_pipe *dev;

    dev = container_of(inode->i_cdev, struct scull_pipe, cdev);
    filp->private_data = dev;

    if (down_interruptible(&dev->sem))
        return -ERESTARTSYS;
    if (!dev->buffer) {
        /* allocate the buffer */
        dev->buffer = kmalloc(scull_p_buffer, GFP_KERNEL);
        if (!dev->buffer) {
            up(&dev->sem);
            return -ENOMEM;
        }
    }
    dev->buffersize = scull_p_buffer;
    dev->end = dev->buffer + dev->buffersize;
    dev->rp = dev->wp = dev->buffer; /* rd and wr from the beginning */

    /* use f_mode,not  f_flags: it's cleaner (fs/open.c tells why) */
    if (filp->f_mode & FMODE_READ)
        dev->nreaders++;
    if (filp->f_mode & FMODE_WRITE)
        dev->nwriters++;
    up(&dev->sem);

    return nonseekable_open(inode, filp);
}



static int scull_p_release(struct inode *inode, struct file *filp)
{
    struct scull_pipe *dev = filp->private_data;

    /* remove this filp from the asynchronously notified filp's */
    scull_p_fasync(-1, filp, 0);
    down(&dev->sem);
    if (filp->f_mode & FMODE_READ)
        dev->nreaders--;
    if (filp->f_mode & FMODE_WRITE)
        dev->nwriters--;
    if (dev->nreaders + dev->nwriters == 0) {
        kfree(dev->buffer);
        dev->buffer = NULL; /* the other fields are not checked on open */
    }
    up(&dev->sem);
    return 0;
}


/*
 * Data management: read and write
 */

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)
            return -EAGAIN;
        PDEBUG("\"%s\" reading: going to sleep\n", current->comm);
        if (wait_event_interruptible(dev->inq, (dev->rp != dev->wp)))
            return -ERESTARTSY) = 4000
read(3, "S; /* signal: tell the fs layer "..., 32768) = 4000
write(1, "S; /* signal: tell the fs layer "..., 4000S; /* 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;
}

/* Wait for space for writing; caller must hold device semaphore.  On
 * error the semaphore will be released before returning. */
static int scull_getwritespace(struct scull_pipe *dev, struct file *filp)
{
    while (spacefree(dev) == 0) { /* full */
        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);
        if (spacefree(dev) == 0)
            schedule();
        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;
    }
    return 0;
}    

/* 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 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;

    /* Make sure there's space to write */
    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);

    /* finally, awake any reader */
    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;
}

static unsigned int scull_p_poll(struct file *filp, poll_table *wait)
{
    struct scull_pipe *dev = filp->private_data;
    unsigned int mask = 0;

    /*
     * The buffer is circular; it is considered full
     * if "wp" is right behind "rp" and empty if the
     * two are equal.
     */
    down(&dev->sem);
    poll_wait(filp, &dev->inq,  wait);
    poll_wait(filp, &dev->outq, wait);
    if (dev->rp != dev->wp)
        mask |= POLLIN | POLLRDNORM;    /* readable */
    if (spacefree(dev))
        mask |= POLLOUT | POLLWRNORM;    /* writable */
    up(&dev->sem);
    return mask;
}





static int scull_p_fasync(int fd, struct file *filp, int mode)
{
    struct scull_pipe *dev = filp->private_data;

    return fasync_helper(fd, filp, mode, &dev->async_queue);
}



/* FIXME this should use seq_file */
#ifdef SCULL_DEBUG
static void scullp_proc_offset(char *buf, char **start, off_t *offset, int *len)
{
    if (*offset == 0)
        return;
    if (*offset >= *len) {    /* Not there yet */
        *offset -= *len;
        *len = 0;
    }
    else {            /* We're into the interesting stuff now */
        *start = buf ) = 4000
read(3, "+ *offset;\n\t\t*offset = 0;\n\t}\n}\n\n"..., 32768) = 3368
write(1, "+ *offset;\n\t\t*offset = 0;\n\t}\n}\n\n"..., 3368+ *offset;
        *offset = 0;
    }
}


static int scull_read_p_mem(char *buf, char **start, off_t offset, int count,
        int *eof, void *data)
{
    int i, len;
    struct scull_pipe *p;

#define LIMIT (PAGE_SIZE-200)    /* don't print any more after this size */
    *start = buf;
    len = sprintf(buf, "Default buffersize is %i\n", scull_p_buffer);
    for(i = 0; i<scull_p_nr_devs && len <= LIMIT; i++) {
        p = &scull_p_devices[i];
        if (down_interruptible(&p->sem))
            return -ERESTARTSYS;
        len += sprintf(buf+len, "\nDevice %i: %p\n", i, p);
/*        len += sprintf(buf+len, "   Queues: %p %p\n", p->inq, p->outq);*/
        len += sprintf(buf+len, "   Buffer: %p to %p (%i bytes)\n", p->buffer, p->end, p->buffersize);
        len += sprintf(buf+len, "   rp %p   wp %p\n", p->rp, p->wp);
        len += sprintf(buf+len, "   readers %i   writers %i\n", p->nreaders, p->nwriters);
        up(&p->sem);
        scullp_proc_offset(buf, start, &offset, &len);
    }
    *eof = (len <= LIMIT);
    return len;
}


#endif



/*
 * The file operations for the pipe device
 * (some are overlayed with bare scull)
 */
struct file_operations scull_pipe_fops = {
    .owner =    THIS_MODULE,
    .llseek =    no_llseek,
    .read =        scull_p_read,
    .write =    scull_p_write,
    .poll =        scull_p_poll,
    .ioctl =    scull_ioctl,
    .open =        scull_p_open,
    .release =    scull_p_release,
    .fasync =    scull_p_fasync,
};


/*
 * Set up a cdev entry.
 */
static void scull_p_setup_cdev(struct scull_pipe *dev, int index)
{
    int err, devno = scull_p_devno + index;
    
    cdev_init(&dev->cdev, &scull_pipe_fops);
    dev->cdev.owner = THIS_MODULE;
    err = cdev_add (&dev->cdev, devno, 1);
    /* Fail gracefully if need be */
    if (err)
        printk(KERN_NOTICE "Error %d adding scullpipe%d", err, index);
}

 

/*
 * Initialize the pipe devs; return how many we did.
 */
int scull_p_init(dev_t firstdev)
{
    int i, result;
    printk("pipe.c firstdev=%d\n",firstdev);
    result = register_chrdev_region(firstdev, scull_p_nr_devs, "scullp");
    if (result < 0) {
        printk(KERN_NOTICE "Unable to get scullp region, error %d\n", result);
        return 0;
    }
    printk("\n");
    printk("pipe.c firstdev=%d\n",firstdev);
    printk("pipe.c MAJOR=%d\n",MAJOR(firstdev));
    printk("pipe.c MINOR=%d\n",MINOR(firstdev));
    printk("\n");
    scull_p_devno = firstdev;
    scull_p_devices = kmalloc(scull_p_nr_devs * sizeof(struct scull_pipe), GFP_KERNEL);
    if (scull_p_devices == NULL) {
        unregister_chrdev_region(firstdev, scull_p_nr_devs);
        return 0;
    }
    memset(scull_p_devices, 0, scull_p_nr_devs * sizeof(struct scull_pipe));
    for (i = 0; i < scull_p_nr_devs; i++) {
        init_waitqueue_head(&(scull_p_devices[i].inq));
        init_waitqueue_head(&(scull_p_devices[i].outq));
        init_MUTEX(&scull_p_devices[i].sem);
        scull_p_setup_cdev(scull_p_devices + i, i);
    }
#ifdef SCULL_DEBUG
    create_proc_read_entry("scullpipe", 0, NULL, scull_read_p_mem, NULL);
#endif
    return scull_p_nr_devs;
}

/*
 * This is called by cleanup_module or on failure.
 * It is required to never fail, even if nothing was initialized first
 */
void scull_p_cleanup(void)
{
    int i;

#ifdef SCULL_DEBUG
    remove_proc_entry("scullpipe", NULL);
#endif

    if (!scull_p_devices)
        return; /* nothing else to release */

    for (i = 0; i < scull_p_nr_devs; i++) {
        cdev_del(&scull_p_devices[i].cdev);
        kfree(scull_p_devices[i].buffer);
    }
    kfree(scull_p_devices);
    unregister_chrdev_region(scull_p_devno, scull_p_nr_devs);
    scull_p_devices = NULL; /* pedantic */
}
) = 3368
read(3, "", 32768)                      = 0
close(3)                                = 0
close(1)                                = 0
close(2)                                = 0
exit_group(0)                           = ?
[root@localhost scull]# 
可以看出从line31将scull0 open后,在
line33 read 4000
line166,read 4000
line309,read 3386
line440,read 0
共读了4次,总计11386bytes=文件的大小
也可看出,cat在while中调用read去读文件的时候,当读到的字节数是0的话,就会退出while循环
(但有一个奇怪的问题,cat调用read不是每次读32768bytes吗,怎么测试中每次才读4000bytes呢??????)
当然cat在读scullpipe0时,读到的字节数不会是0,因为如果scullpipe0中没可用数据,cat就被阻塞了,有数据之后再唤醒它,所以每次cat都会读到数据,所以一直不会退出循环
***********************************************************************************************************************

6.2.4. A Blocking I/O Example
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值