- 论坛徽章:
- 3
|
并发控制,是多任务操作系统必须面临和解决的一个问题。并发与互斥,主要是用于保护临界资源,如果不站在操作系统进程调度的角度,就很难理解并发与互斥的概念和应用。无论是抢占式操作系统,还是分时操作系统,对于临界资源的保护,都必须采用互斥的机制。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 Baohua Song
- <[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>
- #define GLOBALMEM_SIZE 0x1000 /*全局内存最大4K字节*/
- #define MEM_CLEAR 0x1 /*清0全局内存*/
- //#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("Song Baohua");
- MODULE_LICENSE("Dual BSD/GPL");
- module_param(globalmem_major, int, S_IRUGO);
- module_init(globalmem_init);
- module_exit(globalmem_exit);
复制代码
Makefile:
- TARGET = globalmem_lock
- KDIR = /lib/modules/$(shell uname -r)/build
- PWD = $(shell pwd)
- obj-m := $(TARGET).o
- default:
- make -C $(KDIR) M=$(PWD) modules
- clean:
- $(RM) *.o *.ko *.mod.c Module.symvers modules.order
复制代码
[ 本帖最后由 dreamice 于 2009-11-11 09:21 编辑 ] |
评分
-
查看全部评分
|