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

  本文基于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操作、即减1
extern 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 = 1
down(&my_sem);
......    //临界区代码
up(&my_sem);
......






 

你可能感兴趣的:(《Linux内核编程》第六章:Linux设备驱动中的并发控制)