驱动开发住常见的一个问题:就是一个驱动可以被多个进程同时打开,使用,这样会导致驱动功能混乱。
./app & ./app & ./app 可以同时打开这个设备,可通过文件描述符调用驱动的其他接口操作这个设备。
如果想只一个进程使用这个设备,只需要在open接口函数做打开判断。
示例:
static int open_flag = 0;
//打开设备时候执行的程序
static int chrdev_open(struct inode *pinode, struct file *pfile)
{
//打开判断
if(open_flag)
return -EBUSY;
open_flag = 1; //设置 设备已经被打开的标志
printk(KERN_EMERG "line:%d,%s is call\n", __LINE__, __FUNCTION__);
return 0;
}
//关闭设备时执行的程序
static int chrdev_release(struct inode *pinode, struct file *pfile)
{
open_flag = 0; //设置 设备已经被打开的标志
printk(KERN_EMERG "line:%d,%s is call\n", __LINE__, __FUNCTION__);
return 0;
}
以上的效果实现,但是不安全。
分析:
open_flag = 1; 这条语句编译汇编 最少得3条。 只需要执行时候没有一次完成,中途被其他进程打开,刚刚这个进程又调用open打开这个设备。这样,新进程也可以打开成功。
怎么样才可以安全做一次性执行完成这三个步骤?
关系统中断; -->关中断后不会任务调度情况,这样就是安全。
open_flag = 1;
开系统中断; -->重新恢复系统调度
示例:
unsigned long flags;
raw_local_irq_save(flags); //关中断
open_flag = 1; //设置 设备已经被打开的标志
raw_local_irq_restore(flags); //开中断
Linux内核已经提供相关的一些,很方便实现这样的效果。原子操作,信号量,互斥信号量,自旋锁。
原子操作:
1.概念:
原子,是最小的可以独立存在的物质单元,是不可分割。把一个完整的,不可中断的操作过程称为原子操作。Linux系统中的原子本质就是对一个Int类型变量进行操作,但是,它整个操作操作进行控制,保证这个过程是一次性完成。
2. 数据结构
Types.h (include\linux)
typedef struct {
volatile int counter;
} atomic_t;
本质 就是一个int类型变量,可以这个机制很简单,内核只提供对这个变量的+,-,读,赋值操作相关的接口。volatile 修饰字段告诉 gcc 不要对该类型的数据做优化处理,对它的访问都是对内存的访问,而不是对寄存器的访问。
3. 相关的API
Atomic.h (include\linux)
Atomic.h (include\asm-generic)
ATOMIC_INIT(v);
宏原型 | #define ATOMIC_INIT(i) { (i) } |