/* How to use: * # echo "" > /var/log/messages //clear file * # insmod pipe.ko * # mknod /dev/myp c 250 0 * # make poll_test * # ./poll_test * You can see * no data * no data * ... * * Then open a new terminal * # echo "12345" > /dev/myp * and return to the first terminal * you can see * no data * no data * ... * 12345 */ //pipe.c #include <linux/module.h> #include <linux/moduleparam.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 <linux/wait.h> /* wait_event_interruptible() */ //#include <asm/semaphore.h> /* down_interruptible() up() */ #include <linux/semaphore.h> #include <linux/sched.h> //error: ‘TASK_INTERRUPTIBLE’ undeclared #define MYDEBUG 1 //turn on debug info printing switch #define BUF_SIZE 1024 //pipe's buffer size /* ioctl */ #define MY_P_IOC_MAGIC 'p' //use 'p' as magic number #define MY_P_IOCRESET _IO(MY_P_IOC_MAGIC, 0)//clear content of device buffer #define MY_P_IOFILL _IOW(MY_P_IOC_MAGIC, 1, char)//fill device buffer with argument value #define MY_P_IOXCH _IOWR(MY_P_IOC_MAGIC,2, char*) //read out the charactor from buffer,and filled with new value #define MY_P_IOC_MAXNR 2 // print debug infomation #define print_debug_info() / do { / printk (KERN_NOTICE " %s called success /n", __func__);/ }while (0) struct my_pipe { wait_queue_head_t inq, outq; // read and write queue char* buffer, *end; //begin of buffer,end of buffer int buffersize; // sizeof buffer int nreaders, nwriters; // number of openings for r/w char* rp, *wp; // where to read, where to write struct fasync_struct *async_r_queue; //asynchronous reader queue // struct fasync_struct *async_w_queue; // asynchronous writer queue struct semaphore sem;//mutual exclusion semaphore struct cdev cdev;// Char device structure }; int mydev_major, mydev_minor;//record the device major and minor number struct my_pipe * my_p_dev; // pointer to our device int my_p_buf_size = BUF_SIZE; // size of my_pipe's buffer //declaration of functions void my_p_clearup_module (void); int my_p_setup_cdev(struct my_pipe* my_p_dev, dev_t devno); int my_p_init_module (void); static int my_p_open(struct inode *inode, struct file *filp); static int my_p_release(struct inode *inode, struct file *filp); static ssize_t my_p_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos); static ssize_t my_p_read (struct file *filp, char __user *buf, size_t count, loff_t *f_pos); int my_p_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); static unsigned int my_p_poll(struct file *filp, poll_table *wait); struct file_operations my_p_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .read = my_p_read, .write = my_p_write, .poll = my_p_poll, .ioctl = my_p_ioctl, .open = my_p_open, .release = my_p_release, .fasync = 0, }; int my_p_init_module (void) { int result = 0; dev_t dev; result = alloc_chrdev_region(&dev, 0/*minor*/, 1/*dev nums*/,"my_pipe"); mydev_major = MAJOR(dev);//store the major and minor number of our device mydev_minor = MINOR(dev); if (result < 0) { printk (KERN_WARNING "my_pipe: alloc major error!/n"); return result; } #ifdef MYDEBUG else { printk (KERN_WARNING "my_pipe: major is %d/n", mydev_major); } #endif // allocate device structure my_p_dev = kmalloc (sizeof(struct my_pipe), GFP_KERNEL); if (!my_p_dev) { printk (KERN_WARNING "my_pipe: alloc struct my_pipe error!/n"); goto fail; } //init our device items memset (my_p_dev, 0, sizeof(my_p_dev)); init_waitqueue_head(&my_p_dev->inq); init_waitqueue_head(&my_p_dev->outq); init_MUTEX(&my_p_dev->sem); my_p_dev->buffer = NULL;//This is very important if (my_p_setup_cdev(my_p_dev, dev) < 0) { printk (KERN_NOTICE "my_p_setup_cdev called error/n"); goto fail; } #ifdef MYDEBUG print_debug_info(); // current function success #endif return 0; fail: my_p_clearup_module(); return result; } int my_p_setup_cdev(struct my_pipe* my_p_dev, dev_t devno) { int result; cdev_init(&my_p_dev->cdev, &my_p_fops); my_p_dev->cdev.owner = THIS_MODULE; my_p_dev->cdev.ops = &my_p_fops; result = cdev_add (&my_p_dev->cdev, devno, 1); printk(KERN_NOTICE "result is %d/n", result); if (result < 0) { printk (KERN_NOTICE "my_p_dev setup error! /n"); return -EFAULT; } //#ifdef MYDEGUG print_debug_info();//success //#endif return result; } /* free the device mem and free the device struct */ void my_p_clearup_module (void) { dev_t devno = MKDEV(mydev_major, mydev_minor); //The queue memery has been freed by my_p_release cdev_del (&my_p_dev->cdev); // unregister charactor number region unregister_chrdev_region(devno, 1); //here we should free the device struct kfree (my_p_dev); //#ifdef MYDEGUG print_debug_info();//success //#endif } static int my_p_open(struct inode *inode, struct file *filp) { struct my_pipe *dev; dev = container_of(inode->i_cdev, struct my_pipe, cdev);//get and //save device's pointer filp->private_data = dev; if (down_interruptible(&dev->sem)) return -ERESTARTSYS; if (!dev->buffer) { dev->buffer = kmalloc(my_p_buf_size, GFP_KERNEL);//allocate the buffer if(!dev->buffer){ up(&dev->sem); return -ENOMEM; } printk(KERN_NOTICE "mem allocate success/n"); // } dev->buffersize = my_p_buf_size; dev->end = dev->buffer + dev->buffersize; dev->rp = dev->buffer; dev->wp = dev->buffer; } if (filp->f_mode & FMODE_READ) dev->nreaders++; if (filp->f_mode & FMODE_WRITE) dev->nwriters++; up(&dev->sem); //#ifdef MYDEGUG print_debug_info();//success //#endif // return 0; return nonseekable_open(inode, filp);//don't want the seekable file descriptor } static int my_p_release(struct inode *inode, struct file *filp) { struct my_pipe *dev; dev = filp->private_data; // get device pointer /* remove this filp from the asynchronously notified filp's */ //my_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; printk(KERN_NOTICE "mem release succes/n"); } up(&dev->sem); //#ifdef MYDEGUG print_debug_info();//success //#endif return 0; } /* Full return 1, or return 0 */ int is_full(struct my_pipe* dev) { char* p = NULL; p = dev->wp; p ++; if (p > dev->end) p = dev->buffer; if (p == dev->rp) return 1;//full return 0;//not full } static ssize_t my_p_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { struct my_pipe* dev = filp->private_data; int max_num = 0; printk(KERN_NOTICE "%s is entered/n", __func__); if (down_interruptible(&dev->sem)){ return -ERESTARTSYS; } while (is_full(dev) == 1) { up(&dev->sem); if (filp->f_flags & O_NONBLOCK) return -EAGAIN; if (wait_event_interruptible(dev->inq,is_full(dev) != 0)) 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 , now there is place to write to max_num = (int)(dev->rp - dev->wp -1 + my_p_buf_size) % my_p_buf_size; printk(KERN_NOTICE "max_num is %d/t count is %d", max_num, (int)count); count = min(count, (size_t)max_num); if (copy_from_user(dev->wp, buf, count)) { up(&dev->sem); printk(KERN_NOTICE "copy error in %s/n", __func__); return -EFAULT; } dev->wp += count; if (dev->wp == dev->end - 1)//pointer wrapted dev->wp = dev->buffer; up(&dev->sem); wake_up_interruptible(&dev->outq); // blocked in read() and select() //#ifdef MYDEGUG print_debug_info();//success //#endif return count; } static ssize_t my_p_read (struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { struct my_pipe* dev = filp->private_data; int max_num = 0; printk(KERN_NOTICE "%s is entered/n", __func__); if (down_interruptible(&dev->sem)){ return -ERESTARTSYS; } printk(KERN_NOTICE "%s before while/n", __func__); while (dev->rp == dev->wp) { // nothing to read up(&dev->sem); // release the lock if (filp->f_flags & O_NONBLOCK) return -EAGAIN; if (wait_event_interruptible(dev->outq, (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; } printk(KERN_NOTICE "%s after while/n", __func__); /* ok, data is there, return something */ max_num = (dev->wp - dev->rp + my_p_buf_size) % my_p_buf_size; count = min((size_t)max_num, count); if (copy_to_user(buf, dev->rp, count)) { up(&dev->sem); return -EFAULT; } //update the read pointer dev->rp += count; if (dev->rp == dev->end - 1) dev->rp = dev->buffer; up(&dev->sem); /* finally, awake any writer */ wake_up_interruptible(&dev->inq); // blocked in write() and select() //#ifdef MYDEGUG print_debug_info();//success //#endif return count; } int my_p_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { int err = 0; int retval = 0; struct my_pipe* dev = filp->private_data; char swap = '/0'; /* * extract the type and number bitfields, and don't decode * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok() */ printk(KERN_NOTICE "%s called start.../n", __func__); if (_IOC_TYPE(cmd) != MY_P_IOC_MAGIC) return -ENOTTY; if (_IOC_NR(cmd) > MY_P_IOC_MAXNR) return -ENOTTY; if (_IOC_DIR(cmd) & _IOC_READ) err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); else if (_IOC_DIR(cmd) & _IOC_WRITE) err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); if (err) return -EFAULT; if (down_interruptible(&dev->sem)) return -ERESTARTSYS; switch (cmd) { case MY_P_IOCRESET://clear content of device buffer if (dev->buffer) { dev->wp = dev->buffer; dev->rp = dev->buffer; } break; case MY_P_IOFILL://fill device buffer with argument value printk(KERN_NOTICE "%s called in switch/n", __func__); if (dev->buffer) { printk(KERN_NOTICE "parameter is %c/n", (char)arg); memset(dev->buffer, (char)arg, dev->buffersize - 1); dev->wp = dev->end - 1; dev->rp = dev->buffer; printk(KERN_NOTICE "dev->rp's content is %c /ndev->wp's content is %c /n", *dev->rp, *dev->wp); break; } retval = -EINVAL; break; case MY_P_IOXCH://read out the charactor from buffer,and filled with new value if (dev->buffer) { swap = *(dev->buffer); memset(dev->buffer, *((char*)arg), dev->buffersize -1); put_user(swap, (char*)arg); break; } retval = -EINVAL; break; default: retval = -ENOTTY; } up(&dev->sem); return retval; } static unsigned int my_p_poll(struct file *filp, poll_table *wait) { struct my_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); /* add two queue too poll_table */ poll_wait(filp, &dev->inq, wait); poll_wait(filp, &dev->outq, wait); if (dev->rp != dev->wp) mask |= POLLIN | POLLRDNORM; /* readable */ if (!is_full(dev)) mask |= POLLOUT | POLLWRNORM; /* writable */ up(&dev->sem); return mask; } MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("[email protected]"); module_init(my_p_init_module); module_exit(my_p_clearup_module);
------------------------------用户空间测试程序-------------------
//poll_test.c /* * This is an example of how to use poll() in * userspace. * We use poll() to wait the specified fd when * it can be read. * How to use: * # make poll_test * # touch test.txt //create a empty file * # ./poll_test * # echo "12345" > test.txt */ #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <sys/ioctl.h> #include <errno.h> #include <poll.h> #include <string.h> int main(void) { struct pollfd pf; int fd; char buf[1024] = ""; int count = 0;//indicate how many chars we get fd = open ("/dev/myp", O_RDWR); if (fd < 0) { fprintf(stderr, "/dev/myp open errro:%s/n", strerror(errno)); exit(1); } memset(&pf, 0, sizeof(pf)); pf.fd = fd;// which fd to check pf.events = POLLIN | POLLOUT;//if the fd can be read without block while (!(pf.revents & POLLIN)) { if (poll(&pf, 1, -1) < 0) { fprintf(stderr, "poll error:%s/n", strerror(errno)); exit(1); } printf("no data /n"); } /* Here we can read the fd without block*/ if ((count = read(fd, buf, 1023)) < 0) {//read data from test.txt fprintf(stderr, "read error:%s/n", strerror(errno)); exit(1); } buf[count] = '/0'; //Then we can print out the data we received printf("data is %s/n", buf); return 0; }