/***************************************************************************************************
在 深入浅出LDD-4-设备的驱动的并发控制1的基础上
我们给 globalvar 的驱动程序增加 open()和 release()函数,
并在其中借助自旋锁来保护对全局变量 int globalvar_count(记录打开设备的进程数)
的访问来实现设备只能被一个进程打开(必须确保 globalvar_count 最多只能为 1)
****************************************************************************************************/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
MODULE_LICENSE("GPL");
#define MAJOR_NUM 254
static ssize_t globalvar_read(struct file *, char *, size_t, loff_t*);
static ssize_t globalvar_write(struct file *, const char *, size_t, loff_t*);
static int globalvar_open(struct inode *inode, struct file *filp);
static int globalvar_release(struct inode *inode, struct file *filp);
struct file_operations globalvar_fops =
{
read: globalvar_read;
write: globalvar_write;
open: globalvar_open;
release:globalvar_release;
};
static int global_var = 0;
static int globalvar_count = 0;
static struct semaphore sem;
static spinlock_t spin = SPIN_LOCK_UNLOCKED;
static int __init globalvar_init(void)
{
int ret;
ret = register_chrdev(MAJOR_NUM, "globalvar", &globalvar_fops);
if (ret)
{
printk("globalvar register failure");
}
else
{
printk("globalvar register success");
init_MUTEX(&sem);
}
return ret;
}
static void __exit globalvar_exit(void)
{
int ret;
ret = unregister_chrdev(MAJOR_NUM, "globalvar");
if (ret)
{
printk("globalvar unregister failure");
}
else
{
printk("globalvar unregister success");
}
}
static int globalvar_open(struct inode *inode, struct file *filp)
{
//获得自选锁
spin_lock(&spin);
//临界资源访问
if (globalvar_count)
{
spin_unlock(&spin);
return - EBUSY;
}
globalvar_count++;
//释放自选锁
spin_unlock(&spin);
return 0;
}
static int globalvar_release(struct inode *inode, struct file *filp)
{
globalvar_count--;
return 0;
}
static ssize_t globalvar_read(struct file *filp, char *buf, size_t len, loff_t *off)
{
if (down_interruptible(&sem))
{
return - ERESTARTSYS;
}
if (copy_to_user(buf, &global_var, sizeof(int)))
{
up(&sem);
return - EFAULT;
}
up(&sem);
return sizeof(int);
}
static ssize_t globalvar_write(struct file *filp, const char *buf, size_t len,loff_t *off)
{
if (down_interruptible(&sem))
{
return - ERESTARTSYS;
}
if (copy_from_user(&global_var, buf, sizeof(int)))
{
up(&sem);
return - EFAULT;
}
up(&sem);
return sizeof(int);
}
module_init(globalvar_init);
module_exit(globalvar_exit);