摘要:并发控制,是多任务操作系统必须面临和解决的一个问题。并发与互斥,主要是用于保护临界资源,如果不站在操作系统进程调度的角度,就很难理解并发与互斥的概念和应用。无论是抢占式操作系统,还是分时操作系统,对于临界资源的保护,都必须采用互斥的机制。Linux内核中,有多种并发控制的机制:自旋锁、原子变量、信号量、读写锁等等。不同的并发机制对应于不同的应用场合,比如说,自旋锁可以应用到中断处理函数中,信号量则不可以。本文主要从一个globalmem_lock例子来阐述信号量的使用。注:该例子取自《Linux设备驱动开发详解》,并做了编译告警的一些改动。
参考代码
/*====================================================================== A globalmem driver as an example of char device drivers This example is to introduce how to use locks to avoid race conditions
The initial developer of the original code is ZP1015 <[email]author@linuxdriver.cn[/email]>. All Rights Reserved. ======================================================================*/ #include <linux/module.h> #include <linux/types.h> #include <linux/fs.h> #include <linux/errno.h> #include <linux/mm.h> #include <linux/sched.h> #include <linux/init.h> #include <linux/cdev.h> #include <asm/io.h> #include <asm/system.h> #include <asm/uaccess.h>
/*全局内存最大4K字节*/ #define GLOBALMEM_SIZE 0x1000
/*清0全局内存*/ #define MEM_CLEAR 0x1
//#define GLOBALMEM_MAJOR 254 /*预设的globalmem的主设备号*/ #define GLOBALMEM_MAJOR 0 //[color=Red]我这里设为0,主要是为了让系统自动分配主设备号,如果不这样,有些系统可能insmod不成功[/color]
static globalmem_major = GLOBALMEM_MAJOR;
/*globalmem设备结构体*/ struct globalmem_dev { struct cdev cdev; /*cdev结构体*/ unsigned char mem[GLOBALMEM_SIZE]; /*全局内存*/ struct semaphore sem; /*并发控制用的信号量*/ };
struct globalmem_dev *globalmem_devp; /*设备结构体指针*/
/*文件打开函数*/ int globalmem_open(struct inode *inode, struct file *filp) { /*将设备结构体指针赋值给文件私有数据指针*/ filp->private_data = globalmem_devp; return 0; }
/*文件释放函数*/ int globalmem_release(struct inode *inode, struct file *filp) { return 0; }
/* ioctl设备控制函数 */ static int globalmem_ioctl(struct inode *inodep, struct file *filp, unsigned int cmd, unsigned long arg) { struct globalmem_dev *dev = filp->private_data; /*获得设备结构体指针*/
switch (cmd) { case MEM_CLEAR: if (down_interruptible(&dev->sem)) { return - ERESTARTSYS; } memset(dev->mem, 0, GLOBALMEM_SIZE); up(&dev->sem); //释放信号量
printk(KERN_INFO "globalmem is set to zero\n"); break;
default: return - EINVAL; } return 0; }
/*读函数*/ static ssize_t globalmem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos) { unsigned long p = *ppos; unsigned int count = size; int ret = 0; struct globalmem_dev *dev = filp->private_data; /*获得设备结构体指针*/
/*分析和获取有效的写长度*/ if (p >= GLOBALMEM_SIZE) return count ? - ENXIO: 0;
if (count > GLOBALMEM_SIZE - p) count = GLOBALMEM_SIZE - p;
if (down_interruptible(&dev->sem))//获得信号量 { return - ERESTARTSYS; }
/*内核空间->用户空间*/ if (copy_to_user(buf, (void*)(dev->mem + p), count)) { ret = - EFAULT; } else { *ppos += count; ret = count;
printk(KERN_INFO "read %u bytes(s) from %lu\n", count, p); }
up(&dev->sem); //释放信号量
return ret; }
/*写函数*/ static ssize_t globalmem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos) { unsigned long p = *ppos; unsigned int count = size; int ret = 0; struct globalmem_dev *dev = filp->private_data; /*获得设备结构体指针*/
/*分析和获取有效的写长度*/ if (p >= GLOBALMEM_SIZE) return count ? - ENXIO: 0; if (count > GLOBALMEM_SIZE - p) count = GLOBALMEM_SIZE - p;
if (down_interruptible(&dev->sem))//获得信号量 { return - ERESTARTSYS; } /*用户空间->内核空间*/ if (copy_from_user(dev->mem + p, buf, count)) ret = - EFAULT; else { *ppos += count; ret = count;
printk(KERN_INFO "written %u bytes(s) from %lu\n", count, p); }
up(&dev->sem); //释放信号量 return ret; }
/* seek文件定位函数 */ static loff_t globalmem_llseek(struct file *filp, loff_t offset, int orig) { loff_t ret = 0; switch (orig) { case 0: /*相对文件开始位置偏移*/ if (offset < 0) { ret = - EINVAL; break; }
if ((unsigned int)offset > GLOBALMEM_SIZE) { ret = - EINVAL; break; }
filp->f_pos = (unsigned int)offset; ret = filp->f_pos; break;
case 1: /*相对文件当前位置偏移*/ if ((filp->f_pos + offset) > GLOBALMEM_SIZE) { ret = - EINVAL; break; }
if ((filp->f_pos + offset) < 0) { ret = - EINVAL; break; }
filp->f_pos += offset; ret = filp->f_pos; break;
default: ret = - EINVAL; break; } return ret; }
/*文件操作结构体*/ static const struct file_operations globalmem_fops = { .owner = THIS_MODULE, .llseek = globalmem_llseek, .read = globalmem_read, .write = globalmem_write, .ioctl = globalmem_ioctl, .open = globalmem_open, .release = globalmem_release, };
/*初始化并注册cdev*/ static void globalmem_setup_cdev(struct globalmem_dev *dev, int index) { int err, devno = MKDEV(globalmem_major, index);
cdev_init(&dev->cdev, &globalmem_fops); dev->cdev.owner = THIS_MODULE; dev->cdev.ops = &globalmem_fops; err = cdev_add(&dev->cdev, devno, 1);
if (err) printk(KERN_NOTICE "Error %d adding LED%d", err, index); }
/*设备驱动模块加载函数*/ int globalmem_init(void) { int result; dev_t devno = MKDEV(globalmem_major, 0);
/* 申请设备号*/ if (globalmem_major) result = register_chrdev_region(devno, 1, "globalmem"); else /* 动态申请设备号 */ { result = alloc_chrdev_region(&devno, 0, 1, "globalmem"); globalmem_major = MAJOR(devno); }
if (result < 0) return result;
/* 动态申请设备结构体的内存*/ globalmem_devp = kmalloc(sizeof(struct globalmem_dev), GFP_KERNEL);
if (!globalmem_devp) /*申请失败*/ { result = - ENOMEM; goto fail_malloc; }
memset(globalmem_devp, 0, sizeof(struct globalmem_dev));
globalmem_setup_cdev(globalmem_devp, 0); init_MUTEX(&globalmem_devp->sem); /*初始化信号量*/ printk("register globalmem success\n"); return 0;
fail_malloc: unregister_chrdev_region(devno, 1);
return result; }
/*模块卸载函数*/ void globalmem_exit(void) { cdev_del(&globalmem_devp->cdev); /*注销cdev*/ kfree(globalmem_devp); /*释放设备结构体内存*/ unregister_chrdev_region(MKDEV(globalmem_major, 0), 1); /*释放设备号*/ printk("unregister globalmem success\n"); }
MODULE_AUTHOR("ZP1015"); MODULE_LICENSE("Dual BSD/GPL");
module_param(globalmem_major, int, S_IRUGO);
module_init(globalmem_init); module_exit(globalmem_exit);
|