《Linux内核编程》第六章:Linux设备驱动中的并发控制

来源:互联网 发布:末代沙皇的公主们 知乎 编辑:程序博客网 时间:2024/06/07 03:20

  本文基于mstar801平台Linux2.6.35.11内核版本。

  对于内核临界区域临界资源的保护,也是Linux设备驱动的关键部分。因为设备驱动牵扯到会同时被许多用户态进程使用情况。

  本章我们分析Linux内核态的信号量机制。

一、首先说明操作系统PV操作

  PV操作与信号灯的处理相关,P表示通过的意思(其实就是减1,当为0时不能通过),V表示释放的意思(其实就是加1)。

二、Linux内核信号量相关定义及实现

1.先看看头文件定义

  kernel2.6.35.11/include/linux/semaphore.h

......struct semaphore {   spinlock_t lock;             //应该是这个信号量的自旋锁   unsigned int count;          //表示的是这个信号量的计数器   struct list_head wait_list;    //顾名思义应该是等待链表了 };......#define DECLARE_MUTEX(name)\struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)  //定义一个信号量 extern void down(struct semaphore *sem);  //获得信号量,对应P操作、即减1extern void up(struct semaphore *sem);    //释放信号量,对应V操作、即加1......

2.看看down和up函数的实现

  kernel2.6.35.11/kernel/semaphore.c

......void down(struct semaphore *sem){  unsigned long flags;  spin_lock_irqsave(&sem->lock, flags); //原子操作,加锁  if (likely(sem->count > 0))    sem->count--;    //如果count>0,表示可以使用;直接减减  else    __down(sem);    //否则,将调用__down()函数将进程放进等待队列里边;等待后边唤醒。  spin_unlock_irqrestore(&sem->lock, flags);  //释放锁}EXPORT_SYMBOL(down);  //符号导出,这是Linux内核通信手段。这样此变量在内核态全局都可用......void up(struct semaphore *sem){  unsigned long flags;  spin_lock_irqsave(&sem->lock, flags);  if (likely(list_empty(&sem->wait_list)))    sem->count++;     //如果等待链表为空,表示没有正在等待此信号量的进程,count++就行   else    __up(sem);    //如果等待链表不为空,也就是还有进程在等待此信号量;我们还必须调用__up()函数唤醒之前进程  spin_unlock_irqrestore(&sem->lock, flags);}EXPORT_SYMBOL(up);  //符号导出,这是Linux内核通信手段。这样此变量在内核态全局都可用......

三、如何在内核模块中使用信号量进行并发控制

  eg:相关代码片段

#include <linux/semaphore.h>......DECLARE_MUTEX(my_sem);  //定义一个信号量,并置my_sem.count = 1down(&my_sem);......    //临界区代码up(&my_sem);......