一、描述

      嵌入式开发系统中,有各种硬件资源,而有些硬件资源使用时候是需要进程独占的。也就是说,同一时刻只有一个进程允许使用这个硬件资源,其他的进程只能放弃执行或者挂起等待。在设计其对应驱动的时候,就需要做独占处理。

example: 

      led灯驱动,4盏LED灯,在open的时候调用驱动,对其引脚进行配置。如果没有进程独占驱动的处理机制,效果如下:

      根据测试结果可以得到结论,调用了4次应用程序led_test,每一次调用open("/dev/leds", 0),都返回了一个/dev/leds的fd,fd是相同的,都是3。应用程序led_test的4次运行,都成功得到了执行,进程pid号分别为680、681、682、683。当调用open("/dev/leds", 0)时候,对应的就会调用驱动的leds_open函数,然后进行4次初始化。

      所以要实现只有一个进程使用该leds驱动,就需要在驱动模块的leds_open函数动手脚,具体实现方法如下。

二、原子操作

1、定义一个全局原子变量

static atomic_t open_ability = ATOMIC_INIT(1);

2、修改drivers_open函数

static int drivers_open(struct inode *inode, struct file *file)
{    
    if (!atomic_dec_and_test(&open_ability))
    {
        atomic_inc(&open_ability);
        return -EBUSY;
    }
        ............
}

      如果是第一次打开或者处于关闭之后未打开状态,那么可以打开,if判断为false,执行之后的open代码段;如果已经打开了,就不能打开,返回-EBUSY.

3、修改drivers_close函数

int drivers_close(struct inode *inode, struct file *file)
{
    atomic_inc(&open_ability);
        ............      
    return 0;
}

      打开之后,关闭驱动文件,就需要释放open_ability.

4、实现思路总结

      通过引入一个变量open_ability,为硬件驱动设计一个锁,只允许一个进程对其独占;当进程使用完驱动之后,就可以释放这个资源,以提供给其他应用程序来使用。

5、测试效果

      可以看到第一次打开驱动成功,但是第二次打开驱动失败了。而且,这种方法实现的效果是,直接由驱动程序返回打开失败的消息-EBUSY.

 三、信号量--互斥锁

1、定义一个互斥锁,并将互斥锁初始值设为1

static DECLARE_MUTEX(leds_lock);  //利用宏来实现定义,并初始化

2、修改drivers_open函数

static int drivers_open(struct inode *inode, struct file *file)
{    
        /* 获取信号量,如果没有获得,那么就进入睡眠状态 */
        down(&leds_lock);
        ............
}    

3、修改drivers_close函数

int drivers_close(struct inode *inode, struct file *file)
{
    ............
    up(&leds_lock);      
    return 0;
}

4、实现思路总结

      利用互斥锁,来实现对硬件驱动的独占,显然是很适合的,因为互斥锁设计的初衷就是来解决这类问题。

5、测试效果

      可以看到第一次成功打开了驱动,第二次进入了不可中断的休眠状态。也就是说,当pid号645的应用程序led_test调用调用open("/dev/leds", 0)时候,驱动程序中的down(leds_lock)令进程进入了不可中断的休眠状态,直到第一次运行pid号644的应用程序led_test释放互斥锁,才能够重新得到运行。

      备注:STAT一栏中的,S代表“休眠状态”;D代表“不可中断的休眠状态”。

6、与原子操作实现的区别

      原子操作,当第二次打开驱动文件的时候,直接返回-EBUSY,也就是说是非阻塞的;而互斥锁的这种方法,当第二次打开驱动文件的时候,由驱动程序中的down()函数迫使进程进入不可中断的休眠状态,可以说是阻塞的。

      不过,如果将down()函数换成down_trylock()函数,实现的效果也是非阻塞的。

 

参考资料:韦东山linux视频教程

              linux中原子操作实现方式

posted on 2017-05-26 15:58  amanlikethis  阅读(1687)  评论(0编辑  收藏  举报