linux2.6.32内核信号量的实现
来源:互联网 发布:健身软件电脑版 编辑:程序博客网 时间:2024/05/22 04:44
首先看看信号量的相关数据结构:
<include/linux/semaphore.h>
struct semaphore{
spinlock_t lock; #lock应该是这个信号量的自旋锁
unsigned intcount; #count表示的是这个信号量的计数器
struct list_head wait_list;#wait_list顾名思义应该是等待链表了
};
信号量的初始化:
<include/linux/semaphore.h>
#define DECLARE_MUTEX(name) \
struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)
#define __SEMAPHORE_INITIALIZER(name, n) \
{ \
.lock = __SPIN_LOCK_UNLOCKED((name).lock), \ #初始化自旋锁
.count = n, \ #将信号量计数器赋值为n
.wait_list = LIST_HEAD_INIT((name).wait_list), \ #初始化等待队列
}
也可以用以下方法来初始化信号量:
<include/linux/semaphore.h>
staticinline void sema_init(struct semaphore*sem, int val)
{
static struct lock_class_key __key;
*sem = (struct semaphore) __SEMAPHORE_INITIALIZER(*sem, val);
lockdep_init_map(&sem->lock.dep_map,"semaphore->lock",&__key, 0);
}
#define init_MUTEX(sem) sema_init(sem, 1)
#define init_MUTEX_LOCKED(sem) sema_init(sem, 0)
PV操作:
P操作
<kernel/semaphore.c>
void up(struct semaphore*sem)
{
unsigned long flags;
spin_lock_irqsave(&sem->lock, flags);
if (likely(list_empty(&sem->wait_list)))#如果等待链表为空,表示没有正在等待此信号量的进程,count++就行
sem->count++;
else
__up(sem);
spin_unlock_irqrestore(&sem->lock, flags);
}
static noinlinevoid __sched __up(struct semaphore*sem)
{
#取出等待链表中的最前面的那个进程
struct semaphore_waiter *waiter = list_first_entry(&sem->wait_list,
struct semaphore_waiter,list);
list_del(&waiter->list);#将这个进程从等待链表中删除
waiter->up = 1;
wake_up_process(waiter->task);#唤醒这个进程
}
此函数从等待列表中移出最前面的那个进程,然后唤醒它
struct semaphore_waiter{
struct list_head list;#链表项
struct task_struct *task; #进程结构,也可以叫做进程PCB
int up;
};
这个结构主要就是用来辅助把进程放到信号量的等待队列,后面的V操作会再介绍它
V操作:
<kernel/semaphore.c>
void down(struct semaphore*sem)
{
unsigned long flags;
spin_lock_irqsave(&sem->lock, flags);#要对sem进行操作了,加锁
if (likely(sem->count> 0))#如果count>0,直接count--就行了
sem->count--;
else
__down(sem);#调用__down()
spin_unlock_irqrestore(&sem->lock, flags);#对sem操作完毕,释放锁
}
如果count是<=0的,那么调用__down()来把进程放进等待队列里,现在看看__down()是怎么实现的
static noinlinevoid __sched __down(struct semaphore*sem)
{
__down_common(sem, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}
static inline int __sched __down_common(struct semaphore*sem, long state, long timeout)
{
struct task_struct *task = current;#得到当前正在运行的进程
struct semaphore_waiter waiter;
list_add_tail(&waiter.list,&sem->wait_list);#将waiter加到链表sem->wait_list后面
waiter.task = task;#waiter的task设置成正在运行的这个进程
waiter.up = 0;
for (;;){
if (signal_pending_state(state, task))#如果进程被一个意外的信号中断,直接放弃等待(从等待链表中删除),返回-EINTR错误号
goto interrupted;
if (timeout<= 0)#如果等待时间到,从等待链表中删除之,返回-ETIME错误号
goto timed_out;
__set_task_state(task, state);#设置进程状态为TASK_UNINTERRUPTIBLE
spin_unlock_irq(&sem->lock);
timeout = schedule_timeout(timeout);#调度
spin_lock_irq(&sem->lock);
if (waiter.up)
return 0;
}
timed_out:
list_del(&waiter.list);
return -ETIME;
interrupted:
list_del(&waiter.list);
return -EINTR;
}
该函数首先申请一个semaphore_waiter结构,
<kernel/semaphore.c>
struct semaphore_waiter{
struct list_head list;
struct task_struct *task;
int up;
};
然后将这个结构加入到sem信号量的等待链表sem->wait_list中,接着将当前进程task填入waiter.task中,
然后在一个循环中进行进程调度schedule_timeout,每进行一次调度,timeout会减小
如果当前进程task的状态位就绪,则跳转到interrupt,从信号量列表sem-wait_list中删除这个任务对应的节点
如果遇到意外的信号或者等待时间到,从信号量列表sem-wait_list中删除这个任务对应的节点,返回相应的错误号
内核还提供了其他几种V操作:
static noinline int __down_interruptible(struct semaphore *sem);
static noinline int __down_killable(struct semaphore *sem);
static noinline int __down_timeout(struct semaphore *sem, long jiffies);
这里就不一一介绍了
读者也可以参考这篇文章
内核同步机制-信号量
- linux2.6.32内核信号量的实现
- linux2.6内核信号量学习
- dm365 linux2.6.32内核实现BT656的输入驱动
- Linux2.6内核中链表的实现
- Linux2.6内核中链表的实现
- [S3C6410]Linux2.6.28到Linux2.6.32的内核移植
- linux2.6.32.2的mini2440内核配置
- linux2.6.32.2的mini2440内核配置
- Linux内核源码之信号量的实现
- Linux2.6内核的原子操作的实现
- Linux2.6内核的原子操作的实现
- Linux2.6内核下键盘输入设备驱动的实现
- Linux2.6.10内核下PCIExpressNative热插拔框架的实现机制
- dm365 linux2.6.32内核实现656传输驱动lcd
- Linux2.6.32内核下按键作为输入子系统实现
- linux2.4.37内核的安装
- linux2.6 内核的 initrd
- linux2.6.32内核到mini2440
- 怎样添加发送到--------------SendTo文件夹
- 一个二维数组的排序
- ubuntu中字符串匹配中大小写不分
- GridView 加载本地某个文件夹下的所有图片
- 【平衡二叉树】宠物收养所
- linux2.6.32内核信号量的实现
- Loadrunner性能测试一个实例
- MFC 关于SendMessage 消息参数 传送字符串,结构体
- 关于inline函数
- 如何让你的QTP脚本执行效率更高?
- 如何反编绎APK文件
- 如何减小与“大牛”之间的差距
- 罗马数字记法、写法
- 二、IoC控制反转(或依赖注入)