【Linux设备驱动程序(第三版)】----阻塞与非阻塞型操作
来源:互联网 发布:mac密码正确但无法进入 编辑:程序博客网 时间:2024/05/16 12:05
【Linux设备驱动程序(第三版)】----阻塞与非阻塞型操作
pipi.c
#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/fs.h>//file_operations, file#include <linux/proc_fs.h>//proc#include <linux/errno.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/poll.h>#include <linux/cdev.h>//cdev#include <asm/uaccess.h>//copy_to_user & copy_from_user#include <linux/init.h>#include <linux/ioctl.h>//ioctlMODULE_LICENSE("Dual BSD/GPL");static int scullp_major = 250;static int scullp_minor = 0;static int scull_p_nr_devs = 1;static int scull_p_buffer = 4000;dev_t scull_p_devno;struct scull_pipe{wait_queue_head_t inq, outq;char *buffer, *end;int buffersize;char *rp, *wp;int nreaders, nwriters;struct semaphore sem;struct cdev cdev;};struct scull_pipe *scull_p_devices;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){up(&dev->sem);if(filp->f_flags & O_NONBLOCK)return -EAGAIN;if(wait_event_interruptible(dev->inq, (dev->rp != dev->wp)))return -ERESTARTSYS;if(down_interruptible(&dev->sem))return -ERESTARTSYS;}if(dev->wp > dev->rp)count = min(count, (size_t)(dev->wp - dev->rp));elsecount = 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;up(&dev->sem);wake_up_interruptible(&dev->outq);return count;}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 int scull_getwritespace(struct scull_pipe *dev, struct file *filp){while(spacefree(dev) == 0){DEFINE_WAIT(wait);up(&dev->sem);if(filp->f_flags & O_NONBLOCK)return -EAGAIN;prepare_to_wait(&dev->outq, &wait, TASK_INTERRUPTIBLE);if(spacefree(dev) == 0)schedule();finish_wait(&dev->outq, &wait);if(signal_pending(current))return -ERESTARTSYS;if(down_interruptible(&dev->sem))return -ERESTARTSYS;}return 0;}ssize_t scull_p_write(struct file *filp, 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;result = scull_getwritespace(dev, filp);if(result)return result;count = min(count, (size_t)spacefree(dev));if(dev->wp >= dev->rp)count = min(count, (size_t)(dev->end - dev->wp));elsecount = min(count, (size_t)(dev->rp - dev->wp - 1));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;up(&dev->sem);wake_up_interruptible(&dev->inq);return count;}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){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;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;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;}up(&dev->sem);return 0;}struct file_operations scull_pipe_fops = {.owner = THIS_MODULE,.open = scull_p_open,.release = scull_p_release,.read = scull_p_read,.write = scull_p_write,};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);if(err)printk(KERN_NOTICE "Error %d adding scull%d", err, index);}static void scull_cleanup_module(void){int i;if(!scull_p_devices)return;if(scull_p_devices){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;}static int __init scull_init_module(void){int result, i;dev_t firstdev = 0;firstdev = MKDEV(scullp_major, scullp_minor);result = register_chrdev_region(firstdev, scull_p_nr_devs, "scullp");if(result < 0){printk(KERN_WARNING "scull:can't get major %d\n", scullp_major);return result;}scull_p_devno = firstdev;scull_p_devices = kmalloc(scull_p_nr_devs * sizeof(struct scull_pipe), GFP_KERNEL);if(!scull_p_devices){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);}return 0;}module_init(scull_init_module);module_exit(scull_cleanup_module);
Makefile
obj-m:= pipe.omodules-objs:= pipe.oKDIR:= /usr/src/linux-headers-2.6.31-14-generic/PWD:= $(shell pwd)default:make -C $(KDIR) M=$(PWD) modulesclean:rm -rf *.ko *.mod.c *.mod.o *.o *.markers *.symvers *.order
创建设备节点
mknod /dev/scullp c 250 0
装载驱动
insmod pipe.ko
测试
打开一个终端,输入:
cat /dev/scullp
此时,线程阻塞。
打开另一个终端,输入:
echo "Test" > /dev/scullp
此时,被阻塞的线程运行,并输出:Test
卸载
rmmod pipe
- 【Linux设备驱动程序(第三版)】----阻塞与非阻塞型操作
- Linux设备驱动程序学习 高级字符驱动程序操作[阻塞型I/O和非阻塞I/O]
- 设备的阻塞与非阻塞操作
- linux设备驱动中的阻塞与非阻塞(一)
- linux设备驱动中的阻塞与非阻塞(二)
- linux设备驱动中的阻塞与非阻塞(一)
- linux设备驱动中的阻塞与非阻塞(二)
- Linux设备驱动程序之阻塞非阻塞IO----轮询操作
- Linux设备驱动中的阻塞与非阻塞I/O-ubantu14.04第四个驱动程序
- Linux 驱动程序笔记3--- 阻塞型字符设备驱动 --- O_NONBLOCK --- 非阻塞标志
- Linux设备驱动程序——高级字符驱动程序操作(阻塞型I/O)
- 深入浅出Linux设备驱动编程--设备的阻塞与非阻塞操作
- 深入浅出LDD-5-设备的阻塞与非阻塞操作
- linux设备驱动的阻塞与非阻塞的IO操作
- Linux 设备驱动编程之阻塞与非阻塞
- Linux设备驱动编程之阻塞与非阻塞
- 深入浅出Linux设备驱动之阻塞与非阻塞
- Linux设备驱动编程之阻塞与非阻塞 1
- 射击游戏终极篇(不知道怎么贴代码)
- 关于utl_file的初步使用
- 高人的blog
- 大小端转换的例子
- jsp下载文件的实现方法及注意事项
- 【Linux设备驱动程序(第三版)】----阻塞与非阻塞型操作
- 英文系统下传输中文字符的问题!
- 深入理解Android消息处理系统——Looper、Handler、Thread
- C# graphic 的DrawLines 与DrawPath 加粗时线出现分叉现象的解决
- 2011年第四届江苏省大学生机器人大赛比赛规则----机器人自主创新设计比赛
- repo 命令的用法
- Windows Phone 7回车键获取
- Creating a Data Access Layer C#
- SQL参数化查询