Chinaunix首页 | 论坛 | 博客
  • 博客访问: 631052
  • 博文数量: 1008
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 5175
  • 用 户 组: 普通用户
  • 注册时间: 2012-07-31 09:44
文章分类
文章存档

2012年(1008)

我的朋友

分类:

2012-08-01 11:28:29

原文地址:等待队列例程 作者:luozhiyong131

  1. # 文件名:Makefile
  2. # 说明:kpipe 例程 Makefile
  3. # 模块名
  4. MOD_NAME := kpipe
  5. # 模块源码(不能出现与模块名相同的文件名)
  6. SRCS := \
  7. EXTRA_CFLAGS = -DDEBUG
  8. OBJS := $(SRCS:.c=.o)
  9. ifeq ($(KERNELRELEASE),)
  10. KERNELDIR ?= /lib/modules/$(shell uname -r)/build
  11. PWD := $(shell pwd)
  12. default:
  13. $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
  14. clean:
  15. -rm -f $(MOD_NAME).ko
  16. -rm -f $(MOD_NAME).o
  17. -rm -f $(OBJS)
  18. -rm -rf .tmp_versions
  19. -rm -f .*.cmd
  20. -rm -f *.mod.c
  21. -rm -f *.mod.o
  22. -rm -f Module.symvers
  23. -rm -f modules.order
  24. else
  25. $(MOD_NAME)-objs := $(OBJS)
  26. obj-m := $(MOD_NAME).o
  27. endif
  1. /* 文件名:kpipe.c */
  2. /* 说明:等待队列例程 */

  3. #include <linux/module.h> /* 模块编程 */
  4. #include <linux/fs.h> /* 设备号、文件操作接口 */
  5. #include <linux/cdev.h> /* 字符设备编程接口 */
  6. #include <linux/uaccess.h> /* 访问用户态内存接口 */
  7. #include <linux/sched.h> /* 进程调度相关 */
  8. #include <linux/wait.h> /* 等待队列接口 */

  9. MODULE_LICENSE("GPL"); /* 版权声明 */

  10. #define BUF_SIZE 256 /* 内核缓冲区的大小 */

  11. /* 以下类型表示 kpipe 设备 */
  12. struct kpipe_dev {
  13.     struct cdev cdev; /* 内嵌一个字符设备作为代表向内核注册 */
  14.     char *buf; /* 保存内核缓冲区的首地址 */
  15.     int len; /* 保存内核缓冲区的长度 */
  16.     int head; /* 环形缓冲区头指针 */
  17.     int tail; /* 环形缓冲区尾指针 */
  18.     dev_t dev; /* 保存对应的设备号 */
  19.     wait_queue_head_t rq; /* 读等待队列 */
  20.     wait_queue_head_t wq; /* 写等待队列 */
  21.     struct mutex lock; /* 同步变量 */
  22. };

  23. /* 判断设备缓冲区是否空 */
  24. static inline int is_empty(const struct kpipe_dev *dev)
  25. {
  26.     return dev->head == dev->tail;
  27. }

  28. /* 判断设备缓冲区是否满 */
  29. static inline int is_full(const struct kpipe_dev *dev)
  30. {
  31.     /* 让缓冲区的实际容量是 BUF_SIZE-1, 以避免无法区分空与满的情况,
  32.      * 当尾指针正好在头指针之前时就认为缓冲区满 */
  33.     return dev->tail+1 == dev->head ||
  34.         (dev->tail == BUF_SIZE-1 && dev->head == 0);
  35. }

  36. /* 判断设备缓冲区中数据是否回绕 */
  37. static inline int is_rewind(const struct kpipe_dev *dev)
  38. {
  39.     return dev->head > dev->tail;
  40. }

  41. /* 得到设备缓冲区中的数据个数 */
  42. static inline int nr_bytes(const struct kpipe_dev *dev)
  43. {
  44.     if (is_rewind(dev)) {
  45.         return dev->len - dev->head + dev->tail;
  46.     } else {
  47.         return dev->tail - dev->head;
  48.     }
  49. }

  50. /* 得到设备缓冲区中的空位个数 */
  51. static inline int nr_holes(const struct kpipe_dev *dev)
  52. {
  53.     if (is_rewind(dev)) {
  54.         return dev->head - dev->tail - 1;
  55.     } else {
  56.         return dev->len - dev->tail + dev->head - 1;
  57.     }
  58. }

  59. /* 打开操作 */
  60. static int kpipe_open(struct inode *inode, struct file *file)
  61. {
  62.     /* 由 inode 对应的字符设备指针得到 kpipe 设备的地址 */
  63.     struct kpipe_dev *dev = container_of(inode->i_cdev,
  64.             struct kpipe_dev, cdev);
  65.     pr_debug("kpipe_open: be called!\n");
  66.     /* 将 kpipe 设备的地址保存在打开的文件中 */
  67.     file->private_data = dev;
  68.     /* 返回 0 表示打开成功 */
  69.     return 0;
  70. }

  71. /* 关闭操作 */
  72. static int kpipe_release(struct inode *inode, struct file *file)
  73. {
  74.     pr_debug("kpipe_release: be called!\n");
  75.     /* 无操作,返回 0 表示成功 */
  76.     return 0;
  77. }

  78. /* 读操作 */
  79. static ssize_t kpipe_read(struct file *file, char __user *buf,
  80.         size_t count, loff_t *pos)
  81. {
  82.     int err; /* 用于暂存错误码 */
  83.     int bytes; /* 用于保存读取的字节数 */
  84.     /* 从 file 中得到对应的 kpipe 设备 */
  85.     struct kpipe_dev *dev = (struct kpipe_dev *)file->private_data;
  86.     pr_debug("kpipe_read: count = %d.\n", count);
  87.     /* 参数合法性检查 */
  88.     if (count < 0) return -EINVAL; /* 非法参数 */
  89.     if (count == 0) return 0; /* 直接返回 0 */
  90.     if (is_empty(dev)) { /* 缓冲区为空 */
  91.         /* 非阻塞方式下返回 -EAGAIN */
  92.         if (file->f_flags & O_NONBLOCK) return -EAGAIN;
  93.         /* 等待直到缓冲区不空 */
  94.         err = wait_event_interruptible(dev->rq, !is_empty(dev));
  95.         /* 发生信号则返回 -EINTR */
  96.         if (err == -ERESTARTSYS) return -EINTR;
  97.     }
  98.     /* 以下进入临界区,不允许多个进程同时修改头尾指针 */
  99.     mutex_lock(&dev->lock); /* 加锁 */
  100.     /* 限制读取的个数不超过缓冲区中数据的个数 */
  101.     if (count > nr_bytes(dev)) count = nr_bytes(dev);
  102.     bytes = 0; /* 已读取的字节数为 0 */
  103.     if (is_rewind(dev) && count > dev->len-dev->head) {
  104.         /* 读取的区域经过缓冲区末尾,需要读两次 */
  105.         bytes = dev->len-dev->head; /* 计算要读取的字节数 */
  106.         if (copy_to_user(buf, dev->buf+dev->head, bytes) > 0) {
  107.             pr_debug("kpipe_read: copy_to_user() FAILED!\n");
  108.             return -EFAULT;
  109.         }
  110.         dev->head = 0; /* 重设头指针使后续的读取从头开始 */
  111.     }
  112.     /* 如果是第二次读,目标地址应后移 bytes, 读取个数减少 bytes */
  113.     if (copy_to_user(buf+bytes, dev->buf+dev->head, count-bytes) > 0) {
  114.         pr_debug("kpipe_read: copy_to_user() FAILED!\n");
  115.         return -EFAULT;
  116.     }
  117.     /* 更新头指针位置 */
  118.     dev->head += count-bytes;
  119.     mutex_unlock(&dev->lock); /* 解锁 */
  120.     /* 唤醒写操作阻塞的进程 */
  121.     wake_up_interruptible(&dev->wq);
  122.     return count;
  123. }

  124. /* 写操作 */
  125. static ssize_t kpipe_write(struct file *file, const char __user *buf,
  126.         size_t count, loff_t *pos)
  127. {
  128.     int err; /* 用于暂存错误码 */
  129.     int bytes; /* 用于保存写入的字节数 */
  130.     /* 从 file 中得到对应的 kpipe 设备 */
  131.     struct kpipe_dev *dev = (struct kpipe_dev *)file->private_data;
  132.     pr_debug("kpipe_write: count = %d.\n", count);
  133.     /* 参数合法性检查 */
  134.     if (count < 0) return -EINVAL; /* 非法参数 */
  135.     if (count == 0) return 0; /* 直接返回 0 */
  136.     if (is_full(dev)) {
  137.         /* 非阻塞方式下返回 -EAGAIN */
  138.         if (file->f_flags & O_NONBLOCK) return -EAGAIN;
  139.         /* 等待直到缓冲区不满 */
  140.         err = wait_event_interruptible(dev->wq, !is_full(dev));
  141.         /* 发生信号则返回 -EINTR */
  142.         if (err == -ERESTARTSYS) return -EINTR;
  143.     }
  144.     /* 以下进入临界区,不允许多个进程同时修改头尾指针 */
  145.     mutex_lock(&dev->lock); /* 加锁 */
  146.     /* 限制写入的个数不超过缓冲区中空位的个数 */
  147.     if (count > nr_holes(dev)) count = nr_holes(dev);
  148.     bytes = 0; /* 已写入的字节数为 0 */
  149.     if (!is_rewind(dev) && count > dev->len-dev->tail) {
  150.         /* 写入的区域经过缓冲区末尾,需要写两次 */
  151.         bytes = dev->len-dev->tail; /* 计算要写入的字节数 */
  152.         if (copy_from_user(dev->buf+dev->tail, buf, bytes) > 0) {
  153.             pr_debug("kpipe_read: copy_from_user() FAILED!\n");
  154.             return -EFAULT;
  155.         }
  156.         dev->tail = 0; /* 重设尾指针使后续的写入从头开始 */
  157.     }
  158.     /* 如果是第二次写,目标地址应后移 bytes, 写入个数减少 bytes */
  159.     if (copy_from_user(dev->buf+dev->tail, buf+bytes, count-bytes) > 0) {
  160.         pr_debug("kpipe_read: copy_from_user() FAILED!\n");
  161.         return -EFAULT;
  162.     }
  163.     /* 更新尾指针位置 */
  164.     dev->tail += count-bytes;
  165.     mutex_unlock(&dev->lock); /* 解锁 */
  166.     /* 唤醒读操作阻塞的进程 */
  167.     wake_up_interruptible(&dev->rq);
  168.     return count;
  169. }

  170. /* 定位操作 */
  171. static loff_t kpipe_llseek(struct file *file, loff_t offset, int whence)
  172. {
  173.     /* 因为 kpipe 设备类似于 FIFO, 没有读写位置的概念,故直接返回错误码 */
  174.     return -ESPIPE;
  175. }

  176. /* 设备的文件操作,全局变量 */
  177. static struct file_operations kpipe_fops = {
  178.     .owner = THIS_MODULE, /* 所属模块 */
  179.     .open = kpipe_open, /* 打开操作 */
  180.     .release = kpipe_release, /* 关闭操作 */
  181.     .read = kpipe_read, /* 读操作 */
  182.     .write = kpipe_write, /* 写操作 */
  183.     .llseek = kpipe_llseek, /* 定位操作 */
  184. };

  185. /* 全局变量,表示一个 kpipe 设备 */
  186. static struct kpipe_dev kpipe;

  187. /* 模块的初始化函数 */
  188. static __init int kpipe_init(void)
  189. {
  190.     int err; /* 用于保存错误码 */
  191.     pr_debug("kpipe_init: be called!\n");
  192.     /* 初始化互斥体 */
  193.     mutex_init(&kpipe.lock);
  194.     /* 分配设备号 */
  195.     if ((err = alloc_chrdev_region(&kpipe.dev, 0, 1, "kpipe")) < 0) {
  196.         pr_debug("kpipe_init: alloc_chrdev_region() ERR = %d!\n", -err);
  197.         goto alloc_chrdev_region_fail;
  198.     }
  199.     pr_debug("kpipe_init: dev = (%d, %d).\n",
  200.             MAJOR(kpipe.dev), MINOR(kpipe.dev));
  201.     /* 分配内核缓冲区 */
  202.     if ((kpipe.buf = kmalloc(BUF_SIZE, GFP_KERNEL)) == NULL) {
  203.         pr_debug("kpipe_init: kmalloc() ERR!\n");
  204.         err = -ENOMEM; /* 此错误号表示内存不足 */
  205.         goto kmalloc_kpipe_buf_fail;
  206.     }
  207.     /* 保存缓冲区的长度 */
  208.     kpipe.len = BUF_SIZE;
  209.     /* 初始化缓冲区头尾指针 */
  210.     kpipe.head = 0;
  211.     kpipe.tail = 0;
  212.     /* 初始化等待队列 */
  213.     init_waitqueue_head(&kpipe.rq);
  214.     init_waitqueue_head(&kpipe.wq);
  215.     /* 初始化字符设备 */
  216.     cdev_init(&kpipe.cdev, &kpipe_fops);
  217.     kpipe.cdev.owner = kpipe_fops.owner;
  218.     /* 注册字符设备 */
  219.     if ((err = cdev_add(&kpipe.cdev, kpipe.dev, 1)) < 0) {
  220.         pr_debug("kpipe_init: cdev_add() ERR = %d!\n", -err);
  221.         goto cdev_add_fail;
  222.     }
  223.     return 0; /* 返回 0 表示初始化成功 */
  224. /* 以下为出错处理,各个清理操作按初始化时的倒序排列,出错时跳转到相应的位置,
  225.  * 这是驱动编程中常用的做法 */
  226. cdev_add_fail:
  227.     kfree(kpipe.buf); /* 释放所分配的内存 */
  228. kmalloc_kpipe_buf_fail:
  229.     unregister_chrdev_region(kpipe.dev, 1); /* 注销所注册的设备号 */
  230. alloc_chrdev_region_fail:
  231.     mutex_destroy(&kpipe.lock); /* 销毁互斥体 */
  232.     return err;
  233. }
  234. module_init(kpipe_init); /* 指定 kpipe_init 为模块的初始化函数 */

  235. /* 模块的退出函数 */
  236. static __exit void kpipe_exit(void)
  237. {
  238.     pr_debug("kpipe_exit: be called!\n");
  239.     /* 模块退出时进行清理,按初始化时的倒序操作 */
  240.     cdev_del(&kpipe.cdev); /* 注销字符设备 */
  241.     kfree(kpipe.buf); /* 释放所分配的内存 */
  242.     unregister_chrdev_region(kpipe.dev, 1); /* 注销所注册的设备号 */
  243.     mutex_destroy(&kpipe.lock); /* 销毁互斥体 */
  244. }
  245. module_exit(kpipe_exit); /* 指定 kpipe_exit 为模块的退出函数 */
阅读(209) | 评论(0) | 转发(0) |
0

上一篇:定时器例程

下一篇:内核模块例程

给主人留下些什么吧!~~