需求:同一时间只能有一个程序打开驱动程序
初步思路:设置一个标记,如果打开一次,标记改变,则下次不可打开,关闭程序时,标记复位
但是有漏洞——如何保证打开程序到标记改变期间不被其他程序打断?
在open函数中,设置一个标记
static int canopen = 1;
static int sixth_drv_open(struct inode *inode, struct file *file)
{
if (--canopen != 0)
{
canopen++;
return -EBUSY;
}
..........
}
同样的,在close函数中添加复原canopen的语句
canopen++;
意思是,每打开一次,canopen就会自减1,那么再次打开时就无法打开,关闭时自加1,复原canopen标记。
但是,open中的判断语句,对应的汇编语句又有多条,读出变量->修改变量->写回,如果在写回之前,有另外的进程也读取到了这个canopen变量,那么也就可以执行后续的代码,即同时有多个进程打开了同一个设备文件。
原子操作的方式
要用到原子操作,使得canopen的读取和修改写回操作不可打断。
static atomic_t canopen = ATOMIC_INIT(1);
在open函数中,执行自减操作
if (!atomic_dec_and_test(&canopen))
{
atomic_inc(&canopen);
return -EBUSY;
}
atomic_dec_and_test(&canopen)会测试canopen变量自减操作后是否为0,如果是0则结果为真,否则为假。
在这里,由于初值为1,执行自减操作后为0,结果为真,这与我们的预期相反,所以取反。
信号量的方式
即用之前先申请,用完后释放。
定义
static DECLARE_MUTEX(button_lock);
在2.6.36版本后的内核就没有DECLARE_MUTEX这个宏了,取而代之的是DEFINE_SEMAPHORE宏,在后来同互斥信号量相关的init_MUTEX、init_MUTEX_LOCKED也从<linux/semaphore.h>文件中移除了。
申请
open函数中获取信号量
down(&button_lock)
释放
up(&button_lock)
这是,如果执行两次测试程序,即打开两次设备文件,则第二个程序不会直接返回错误,而是在申请阶段休眠等待,如果将第一个程序kill掉,则第二个程序会申请信号量成功,从而接着执行。
阻塞和非阻塞
阻塞,即程序遇到不满足的条件时会挂起,等满足条件后再次执行,非阻塞会直接返回错误或者不停地查询状态。