scull-pipe.c
来源:互联网 发布:hexo源码 编辑:程序博客网 时间:2024/06/15 15:22
/* * 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_DEBUGstatic 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_DEBUGcreate_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_DEBUGremove_proc_entry("scullpipe", NULL);#endifif (!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
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/scullpipe0execve("./read_test", ["./read_test", "/dev/scullpipe0"], [/* 44 vars */]) = 0brk(0) = 0x8498000mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77b9000access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)open("/etc/ld.so.cache", O_RDONLY) = 3fstat64(3, {st_mode=S_IFREG|0644, st_size=142866, ...}) = 0mmap2(NULL, 142866, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7796000close(3) = 0open("/lib/libc.so.6", O_RDONLY) = 3read(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) = 512fstat64(3, {st_mode=S_IFREG|0755, st_size=1847224, ...}) = 0mmap2(0x6b9000, 1612328, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x110000mprotect(0x293000, 4096, PROT_NONE) = 0mmap2(0x294000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x183) = 0x294000mmap2(0x297000, 10792, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x297000close(3) = 0mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7795000set_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}) = 0mprotect(0x294000, 8192, PROT_READ) = 0mprotect(0x6b5000, 4096, PROT_READ) = 0munmap(0xb7796000, 142866) = 0write(2, "press Ctrl-C to stop\n", 21press Ctrl-C to stop) = 21open("/dev/scullpipe0", O_RDONLY) = 3brk(0) = 0x8498000brk(0x84b9000) = 0x84b9000brk(0) = 0x84b9000read(3, "hello\n", 10) = 6fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77b8000write(1, "value: hello\n", 13value: hello) = 13write(1, "\n", 1) = 1read(3, "hi\n", 10) = 3write(1, "value: hi\nlo\n", 13value: hilo) = 13write(1, "\n", 1) = 1close(3) = 0exit_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/scullpipe0execve("/usr/bin/head", ["head", "-3", "/dev/scullpipe0"], [/* 44 vars */]) = 0brk(0) = 0x8a12000mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78fc000access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)open("/etc/ld.so.cache", O_RDONLY) = 3fstat64(3, {st_mode=S_IFREG|0644, st_size=142866, ...}) = 0mmap2(NULL, 142866, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb78d9000close(3) = 0open("/lib/libc.so.6", O_RDONLY) = 3read(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) = 512fstat64(3, {st_mode=S_IFREG|0755, st_size=1847224, ...}) = 0mmap2(0x6b9000, 1612328, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x6b9000mprotect(0x83c000, 4096, PROT_NONE) = 0mmap2(0x83d000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x183) = 0x83d000mmap2(0x840000, 10792, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x840000close(3) = 0mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78d8000set_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}) = 0mprotect(0x83d000, 8192, PROT_READ) = 0mprotect(0x6b5000, 4096, PROT_READ) = 0munmap(0xb78d9000, 142866) = 0brk(0) = 0x8a12000brk(0x8a33000) = 0x8a33000brk(0) = 0x8a33000open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE) = 3fstat64(3, {st_mode=S_IFREG|0644, st_size=99158720, ...}) = 0mmap2(NULL, 2097152, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb76d8000close(3) = 0open("/dev/scullpipe0", O_RDONLY|O_LARGEFILE) = 3read(3, "hi\n", 8192) = 3fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78fb000write(1, "hi\n", 3hi) = 3read(3, "hi\n", 8192) = 3write(1, "hi\n", 3hi) = 3read(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), ...}) = 0write(1, "hi\n", 3hi) = 3close(3) = 0close(1) = 0munmap(0xb78fb000, 4096) = 0close(2) = 0exit_group(0) = ?留意line31,36,39,看出head内的read每次要读8192bytes
再看一下cat
先执行strace cat /dev/scullpipe0,然后一直输入 echo hi>/dev/scullpipe0,反应如下
[root@localhost scull]# strace cat /dev/scullpipe0execve("/bin/cat", ["cat", "/dev/scullpipe0"], [/* 44 vars */]) = 0brk(0) = 0x9362000mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7821000access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)open("/etc/ld.so.cache", O_RDONLY) = 3fstat64(3, {st_mode=S_IFREG|0644, st_size=142866, ...}) = 0mmap2(NULL, 142866, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb77fe000close(3) = 0open("/lib/libc.so.6", O_RDONLY) = 3read(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) = 512fstat64(3, {st_mode=S_IFREG|0755, st_size=1847224, ...}) = 0mmap2(0x6b9000, 1612328, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x110000mprotect(0x293000, 4096, PROT_NONE) = 0mmap2(0x294000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x183) = 0x294000mmap2(0x297000, 10792, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x297000close(3) = 0mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77fd000set_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}) = 0mprotect(0x294000, 8192, PROT_READ) = 0mprotect(0x6b5000, 4096, PROT_READ) = 0munmap(0xb77fe000, 142866) = 0brk(0) = 0x9362000brk(0x9383000) = 0x9383000brk(0) = 0x9383000open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE) = 3fstat64(3, {st_mode=S_IFREG|0644, st_size=99158720, ...}) = 0mmap2(NULL, 2097152, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb75fd000close(3) = 0fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0open("/dev/scullpipe0", O_RDONLY|O_LARGEFILE) = 3fstat64(3, {st_mode=S_IFCHR|0664, st_rdev=makedev(247, 4), ...}) = 0read(3, "hi\n", 32768) = 3write(1, "hi\n", 3hi) = 3read(3, "hi\n", 32768) = 3write(1, "hi\n", 3hi) = 3read(3, "hi\n", 32768) = 3write(1, "hi\n", 3hi) = 3read(3, "hi\n", 32768) = 3write(1, "hi\n", 3hi) = 3read(3, "hi\n", 32768) = 3write(1, "hi\n", 3hi) = 3read(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/scull0press Ctrl-C to stopvalue: /* * pipevalue: .c -- fifo[root@localhost scull]# strace ./read_test /dev/scull0execve("./read_test", ["./read_test", "/dev/scull0"], [/* 44 vars */]) = 0brk(0) = 0x9d96000mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7798000access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)open("/etc/ld.so.cache", O_RDONLY) = 3fstat64(3, {st_mode=S_IFREG|0644, st_size=142866, ...}) = 0mmap2(NULL, 142866, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7775000close(3) = 0open("/lib/libc.so.6", O_RDONLY) = 3read(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) = 512fstat64(3, {st_mode=S_IFREG|0755, st_size=1847224, ...}) = 0mmap2(0x6b9000, 1612328, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x6b9000mprotect(0x83c000, 4096, PROT_NONE) = 0mmap2(0x83d000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x183) = 0x83d000mmap2(0x840000, 10792, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x840000close(3) = 0mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7774000set_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}) = 0mprotect(0x83d000, 8192, PROT_READ) = 0mprotect(0x6b5000, 4096, PROT_READ) = 0munmap(0xb7775000, 142866) = 0write(2, "press Ctrl-C to stop\n", 21press Ctrl-C to stop) = 21open("/dev/scull0", O_RDONLY) = 3brk(0) = 0x9d96000brk(0x9db7000) = 0x9db7000brk(0) = 0x9db7000read(3, "/*\n * pipe", 10) = 10fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7797000write(1, "value: /*\n", 10value: /*) = 10write(1, " * pipe\n", 8 * pipe) = 8read(3, ".c -- fifo", 10) = 10write(1, "value: .c -- fifo\n", 18value: .c -- fifo) = 18close(3) = 0exit_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/scull0execve("/usr/bin/head", ["head", "-3", "/dev/scull0"], [/* 44 vars */]) = 0brk(0) = 0x9c6b000mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78c5000access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)open("/etc/ld.so.cache", O_RDONLY) = 3fstat64(3, {st_mode=S_IFREG|0644, st_size=142866, ...}) = 0mmap2(NULL, 142866, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb78a2000close(3) = 0open("/lib/libc.so.6", O_RDONLY) = 3read(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) = 512fstat64(3, {st_mode=S_IFREG|0755, st_size=1847224, ...}) = 0mmap2(0x6b9000, 1612328, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x6b9000mprotect(0x83c000, 4096, PROT_NONE) = 0mmap2(0x83d000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x183) = 0x83d000mmap2(0x840000, 10792, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x840000close(3) = 0mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78a1000set_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}) = 0mprotect(0x83d000, 8192, PROT_READ) = 0mprotect(0x6b5000, 4096, PROT_READ) = 0munmap(0xb78a2000, 142866) = 0brk(0) = 0x9c6b000brk(0x9c8c000) = 0x9c8c000brk(0) = 0x9c8c000open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE) = 3fstat64(3, {st_mode=S_IFREG|0644, st_size=99158720, ...}) = 0mmap2(NULL, 2097152, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb76a1000close(3) = 0open("/dev/scull0", O_RDONLY|O_LARGEFILE) = 3read(3, "/*\n * pipe.c -- fifo driver for "..., 8192) = 4000_llseek(3, -3959, [41], SEEK_CUR) = 0fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78c4000write(1, "/*\n", 3/*) = 3write(1, " * pipe.c -- fifo driver for scu"..., 35 * pipe.c -- fifo driver for scull) = 35write(1, " *\n", 3 *) = 3close(3) = 0close(1) = 0munmap(0xb78c4000, 4096) = 0close(2) = 0exit_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/scull0execve("/bin/cat", ["cat", "/dev/scull0"], [/* 44 vars */]) = 0brk(0) = 0x9926000mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb78b5000access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)open("/etc/ld.so.cache", O_RDONLY) = 3fstat64(3, {st_mode=S_IFREG|0644, st_size=142866, ...}) = 0mmap2(NULL, 142866, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7892000close(3) = 0open("/lib/libc.so.6", O_RDONLY) = 3read(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) = 512fstat64(3, {st_mode=S_IFREG|0755, st_size=1847224, ...}) = 0mmap2(0x6b9000, 1612328, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x6b9000mprotect(0x83c000, 4096, PROT_NONE) = 0mmap2(0x83d000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x183) = 0x83d000mmap2(0x840000, 10792, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x840000close(3) = 0mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7891000set_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}) = 0mprotect(0x83d000, 8192, PROT_READ) = 0mprotect(0x6b5000, 4096, PROT_READ) = 0munmap(0xb7892000, 142866) = 0brk(0) = 0x9926000brk(0x9947000) = 0x9947000brk(0) = 0x9947000open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE) = 3fstat64(3, {st_mode=S_IFREG|0644, st_size=99158720, ...}) = 0mmap2(NULL, 2097152, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7691000close(3) = 0fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0open("/dev/scull0", O_RDONLY|O_LARGEFILE) = 3fstat64(3, {st_mode=S_IFCHR|0664, st_rdev=makedev(247, 0), ...}) = 0read(3, "/*\n * pipe.c -- fifo driver for "..., 32768) = 4000write(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) = 4000read(3, "S; /* signal: tell the fs layer "..., 32768) = 4000write(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_DEBUGstatic 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 ) = 4000read(3, "+ *offset;\n\t\t*offset = 0;\n\t}\n}\n\n"..., 32768) = 3368write(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 */}) = 3368read(3, "", 32768) = 0close(3) = 0close(1) = 0close(2) = 0exit_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
- scull-pipe.c
- LDD3 scull pipe 模块
- scull-main.c
- scull-access.c
- c pipe
- scull
- Beginning C stdin pipe programming
- Linux C编程 - 管道pipe
- pipe 函数 (C语言)
- pipe 函数 (C语言)
- Linux C编程 - 管道pipe
- scull-scull.h
- pipe()
- pipe
- pipe
- pipe
- pipe
- PIPE
- 华为的一个笔试题:.将二叉树的两个孩子换位置,即左变右,右变左。不能用递规
- STM32 SPI1 remap时,与调试端口的冲突解决办法
- LoadRunner在EBS R12上运行的问题
- scull-main.c
- 新手学PHP之-流程控制之分支结构
- scull-pipe.c
- scull-access.c
- Python转换office word文件为HTML
- scull-scull.h
- 深入理解 C++ 指针(二)---指针的算术运算
- Android高手进阶教程(十一)----Android 在一个应用中如何启动另外一个已安装的应用!!!
- 配置Windows Server 2008 允许多用户远程桌面连接
- scull-scull_load , scripts
- 重返德军总部wolf3d iphone源码编译过程