blocking and unblocking mechanism for linux drivern code


概念:


1> 阻塞操作      是指在执行设备操作时,若不能获得资源,则挂起进程直到满足操作条件后再进行操作。被挂起的进程进入休眠,被从调度器移走,直到条件满足;


2> 非阻塞操作  在不能进行设备操作时,并不挂起,它或者放弃,或者不停地查询,直到可以进行操作。非阻塞应用程序通常使用select系统调用查询是否可以对设备进行无阻塞的访问最终会引发设备驱动中poll函数执行。

  



1
/* 2 * Theme for understanding the blocking and unblocking mechanism in device 3 * driven module and difference of both modes 4 * 5 * Two aspects should be considered,firstly, when reading process is proceeding, 6 * data must be existed in FIFO. Secconly, FIFO is non-full is prerequisite for 7 * the writing process. 8 * 9 *Copyright (C) Continential- weizhen.diao@conti.engineering.com 10 * 11 */ 12 13 #include <linux/module.h> 14 #include <linux/types.h> 15 #include <linux/sched.h> 16 #include <linux/init.h> 17 #include <linux/cdev.h> 18 #include <linux/slab.h> 19 #include <linux/poll.h> 20 21 #define conti_globalfifo_SIZE 0x1000 22 #define FIFO_CLEAR 0x1 23 24 /*major devive number*/ 25 #define conti_globalfifo_MAJOR 231 26 27 static int conti_globalfifo_major = conti_globalfifo_MAJOR; 28 module_param(conti_globalfifo_major, int, S_IRUGO); 29 30 /*conti_globalfifo device struct*/ 31 struct conti_globalfifo_dev { 32 struct cdev cdev; 33 unsigned int current_len; 34 unsigned char mem[conti_globalfifo_SIZE]; 35 struct mutex mutex; //signal for concurrency control 36 wait_queue_head_t r_wait; //list of kernel bidirectional loops for blocking reading 37 wait_queue_head_t w_wait; //list of kernel bidirectional loops for blocking writing 38 }; 39 40 struct conti_globalfifo_dev *conti_globalfifo_devp; 41 42 static int conti_globalfifo_open(struct inode *inode, struct file *filp) 43 { 44 filp->private_data = conti_globalfifo_devp; 45 return 0; 46 } 47 48 static int conti_globalfifo_release(struct inode *inode, struct file *filp) 49 { 50 return 0; 51 } 52 53 static long conti_globalfifo_ioctl(struct file *filp, unsigned int cmd, 54 unsigned long arg) 55 { 56 struct conti_globalfifo_dev *dev = filp->private_data; 57 58 switch (cmd) { 59 case FIFO_CLEAR: 60 mutex_lock(&dev->mutex); 61 dev->current_len = 0; 62 memset(dev->mem, 0, conti_globalfifo_SIZE); 63 mutex_unlock(&dev->mutex); 64 65 printk(KERN_INFO "conti_globalfifo is set to zero\n"); 66 break; 67 68 default: 69 return -EINVAL; 70 } 71 return 0; 72 } 73 74 static unsigned int conti_globalfifo_poll(struct file *filp, poll_table * wait) 75 { 76 unsigned int mask = 0; 77 struct conti_globalfifo_dev *dev = filp->private_data; 78 79 mutex_lock(&dev->mutex); 80 81 poll_wait(filp, &dev->r_wait, wait); 82 poll_wait(filp, &dev->w_wait, wait); 83 84 if (dev->current_len != 0) { 85 mask |= POLLIN | POLLRDNORM; 86 } 87 88 if (dev->current_len != conti_globalfifo_SIZE) { 89 mask |= POLLOUT | POLLWRNORM; 90 } 91 92 mutex_unlock(&dev->mutex); 93 return mask; 94 } 95 96 static ssize_t conti_globalfifo_read(struct file *filp, char __user *buf, 97 size_t count, loff_t *ppos) 98 { 99 int ret; 100 struct conti_globalfifo_dev *dev = filp->private_data; 101 DECLARE_WAITQUEUE(wait, current); 102 103 mutex_lock(&dev->mutex); 104 add_wait_queue(&dev->r_wait, &wait); 105 106 while (dev->current_len == 0) { 107 if (filp->f_flags & O_NONBLOCK) { 108 ret = -EAGAIN; 109 goto out; 110 } 111 __set_current_state(TASK_INTERRUPTIBLE); 112 mutex_unlock(&dev->mutex); 113 114 schedule(); 115 if (signal_pending(current)) { 116 ret = -ERESTARTSYS; 117 goto out2; 118 } 119 120 mutex_lock(&dev->mutex); 121 } 122 123 if (count > dev->current_len) 124 count = dev->current_len; 125 126 if (copy_to_user(buf, dev->mem, count)) { 127 ret = -EFAULT; 128 goto out; 129 } else { 130 memcpy(dev->mem, dev->mem + count, dev->current_len - count); 131 dev->current_len -= count; 132 printk(KERN_INFO "read %d bytes(s),current_len:%d\n", count, 133 dev->current_len); 134 135 wake_up_interruptible(&dev->w_wait); 136 137 ret = count; 138 } 139 out: 140 mutex_unlock(&dev->mutex); 141 out2: 142 remove_wait_queue(&dev->w_wait, &wait); 143 set_current_state(TASK_RUNNING); 144 return ret; 145 } 146 147 static ssize_t conti_globalfifo_write(struct file *filp, const char __user *buf, 148 size_t count, loff_t *ppos) 149 { 150 struct conti_globalfifo_dev *dev = filp->private_data; 151 int ret; 152 DECLARE_WAITQUEUE(wait, current); 153 154 mutex_lock(&dev->mutex); 155 add_wait_queue(&dev->w_wait, &wait); 156 157 while (dev->current_len == conti_globalfifo_SIZE) { 158 if (filp->f_flags & O_NONBLOCK) { 159 ret = -EAGAIN; 160 goto out; 161 } 162 __set_current_state(TASK_INTERRUPTIBLE); 163 164 mutex_unlock(&dev->mutex); 165 166 schedule(); 167 if (signal_pending(current)) { 168 ret = -ERESTARTSYS; 169 goto out2; 170 } 171 172 mutex_lock(&dev->mutex); 173 } 174 175 if (count > conti_globalfifo_SIZE - dev->current_len) 176 count = conti_globalfifo_SIZE - dev->current_len; 177 178 if (copy_from_user(dev->mem + dev->current_len, buf, count)) { 179 ret = -EFAULT; 180 goto out; 181 } else { 182 dev->current_len += count; 183 printk(KERN_INFO "written %d bytes(s),current_len:%d\n", count, 184 dev->current_len); 185 186 wake_up_interruptible(&dev->r_wait); 187 188 ret = count; 189 } 190 191 out: 192 mutex_unlock(&dev->mutex); 193 out2: 194 remove_wait_queue(&dev->w_wait, &wait); 195 set_current_state(TASK_RUNNING); 196 return ret; 197 } 198 199 static const struct file_operations conti_globalfifo_fops = { 200 .owner = THIS_MODULE, 201 .read = conti_globalfifo_read, 202 .write = conti_globalfifo_write, 203 .unlocked_ioctl = conti_globalfifo_ioctl, 204 .poll = conti_globalfifo_poll, 205 .open = conti_globalfifo_open, 206 .release = conti_globalfifo_release, 207 }; 208 209 static void conti_globalfifo_setup_cdev(struct conti_globalfifo_dev *dev, int index) 210 { 211 int err, devno = MKDEV(conti_globalfifo_major, index); 212 213 cdev_init(&dev->cdev, &conti_globalfifo_fops); 214 dev->cdev.owner = THIS_MODULE; 215 err = cdev_add(&dev->cdev, devno, 1); 216 if (err) 217 printk(KERN_NOTICE "Error %d adding conti_globalfifo%d", err, index); 218 } 219 220 static int __init conti_globalfifo_init(void) 221 { 222 int ret; 223 dev_t devno = MKDEV(conti_globalfifo_major, 0); 224 225 if (conti_globalfifo_major) 226 ret = register_chrdev_region(devno, 1, "conti_globalfifo"); 227 else { 228 ret = alloc_chrdev_region(&devno, 0, 1, "conti_globalfifo"); 229 conti_globalfifo_major = MAJOR(devno); 230 } 231 if (ret < 0) 232 return ret; 233 234 conti_globalfifo_devp = kzalloc(sizeof(struct conti_globalfifo_dev), GFP_KERNEL); 235 if (!conti_globalfifo_devp) { 236 ret = -ENOMEM; 237 goto fail_malloc; 238 } 239 240 conti_globalfifo_setup_cdev(conti_globalfifo_devp, 0); 241 242 mutex_init(&conti_globalfifo_devp->mutex); 243 init_waitqueue_head(&conti_globalfifo_devp->r_wait); 244 init_waitqueue_head(&conti_globalfifo_devp->w_wait); 245 246 return 0; 247 248 fail_malloc: 249 unregister_chrdev_region(devno, 1); 250 return ret; 251 } 252 module_init(conti_globalfifo_init); 253 254 static void __exit conti_globalfifo_exit(void) 255 { 256 cdev_del(&conti_globalfifo_devp->cdev); 257 kfree(conti_globalfifo_devp); 258 unregister_chrdev_region(MKDEV(conti_globalfifo_major, 0), 1); 259 } 260 module_exit(conti_globalfifo_exit); 261 262 MODULE_AUTHOR(" <Hemingway <weizhen.diao@conti.engineering.com>>");
263 MODULE_LICENSE("GPL v2");

 

posted @ 2016-10-08 20:38  刁海威  阅读(318)  评论(0编辑  收藏  举报