7.1并发引起竞态;多个中断也可能引发并发而导致竞态;解决竞争的途径是对共享资源的互斥访问;
7.2中断屏蔽
中断屏蔽使得中断与进程之间并发不在发生,内核抢占进程之间的并发也可以避免。
Local_irq_disable()
。。。。
。。。
。。。。
Local_irq_enable()
只能禁止本cpu的中断。不能解决SMP引发的竞态。。
单独使用中断屏蔽不是一个好方法,它适合和自旋锁使用。
Local_irq_save()
Local_irq_restore()
Local_bh_disable()
Local_bh_enable();
7.3原子操作
声明原子变量,然后利用它来控制进程的执行。
Static atomic_t xxx_available=ATOMIC_INIT ();//定义原子变量
Static int xxx_open(struct inode *inode,struct file *filp)
{
….
If(!atomic_dec_and_test(&xxx_available)
{atomic_inc(&xxx-available);
Return -EBUSY;
}
….
Return 0;
}
Static int xxx_release(struct inode *inode,struct file *filp)
{
Atomic_inc(&xxx_available);
Return 0;
}
7.4自旋锁
为了获得自旋锁,在某cpu上运行的代码先执行一个原子操作。
把他当做变量看待。
自旋锁的使用范例:
spinlock_t lock;
spin_lock_init(&lock);
spin_lock(&lock);//获取自旋锁
..../
spin_unlock(&lock);//释放自旋
还有一些自旋锁的衍生的函数。。可以使用。。。。。
使用自旋锁会降低系统的性能。
自旋锁可能导致系统死锁。原因:递归调用一个自旋锁。自旋锁占用期间不要调用会引起阻塞的函数。。
7.4.2读写自旋锁
可以同时有多个读,但只能有一个写进程;同时读和写不能同时进行。
例子:
rwlock_t lock;//define a rwlock
rwlock_init(&lock);//初始化rwlock
//读取获取锁
read_lock(&lock);
..../
read_unlock(&lock);
//写获取锁
write_lock_irqsave(&lock,flags);
...
...
write_unlock_irqrestore(&lock,flags);
7.5信号量
信号量与自旋锁相识,但信号量获取不到时不会原地打转,而是进入休眠状态。。。。
1定义信号量
struct semaphore sem;
2初始化信号量
void sema_init(struct semaphore *sem,int val);
void init_MUTEX(struct semaphore *sem);
void init_MUTEX_LOCKED(struct semaphore *sem);
声明与定义:
DECLARE_MUTEX(name);
DECLARE_MUTEX_LOCKED(name);
3获取信号量
void down(struct semaphore *sem)
int down_interruptible(struct semaphore *sem)
int_trylock(struct semaphore *sem)
4释放信号量
void up(struc semaphore *sem)
例子:
DECLARE_MUTEX(mutex_sem)
down(&mutex_sem);
...
critical section
...
up(&mutex_sem);
7.5.2 信号量被初始化为0,它可以用于同步操作
7.5.3完成量用于同步
struct completion my_completion;
init_completion(&my_completion);//DECLARE_COMPLETION(my_completion);
void wait_for_completion(struct completion *c);
唤醒完成量:
void complete(struct completion *c);
void complete_all(struct completion *c);
7.5.4自旋锁VS信号量
选择的依据是临界区的性质和系统的特点:
在多cpu中需要自旋锁来互斥。
信号量是进初级的,进程休眠带来上下文切换,只有当进程占用的时间比较长的时候,用信号量才是一个比较好的选择。
当要保护的临界区访问时间比较短的时候,用自旋锁是非常方便的。因为自旋锁一直占用cpu,所以等待的时间越短越好。
信号量所保护的临界区可包含可能引起阻塞的代码,而自旋锁要绝对要避免用来保护包含这样代码的临界区。
信号量运行于进程上下文。
7.5.5读写信号量
例子:
rw_semaphore rw_sem;
init_rwsem(&rw_sem);
down_read(&rw_sem);
...
...
up_read(&rw_sem);
down_write(&rw_sem);
...
...
up_write(&rw_sem);
7.6互斥体
例子:
struct mutex my_mutex;
mutex_init(&my_mutex);
mutex_lock(&my_mutex);
.../
mutex_unlock(&my_lock);
增加并发控制的globalmem驱动:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define GLOBALMEM_SIZE 0x1000 /*全局内存最大4K字节*/
#define MEM_CLEAR 0x1 /*清0全局内存*/
#define GLOBALMEM_MAJOR 254 /*预设的globalmem的主设备号*/
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 %d bytes(s) from %d\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 %d bytes(s) from %d\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(&globalfifo_devp->sem); /*初始化信号量*/
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); /*释放设备号*/
}
MODULE_LICENSE("Dual BSD/GPL");
module_param(globalmem_major, int, S_IRUGO);
module_init(globalmem_init);
module_exit(globalmem_exit);