linux源码之信号量(semaphore/rw_semaphore )分析

本文详细分析了Linux内核4.14.159版中信号量(semaphore)和读写信号量(rw_semaphore)的实现原理,包括初始化、down和up操作。通过理解这些锁机制,可以更好地选择适用于不同场景的同步方法,并解决可能的死锁问题。文章首先介绍信号量的初始化和使用,然后详细探讨了读写信号量的获取与释放流程。
摘要由CSDN通过智能技术生成

本文kernel代码分析基于以下
1.linux-4.14.159
2.64bit代码处理逻辑

学习目的:1.写代码涉及锁的实现时能更好的选择不同的锁 2 死锁问题涉及信号量时能更熟练的debug。

我们知道linux内核中存在进程、中断、软中断等相互之间的同步问题,在SMP下这些使用场景会变的尤为复杂,因此linux内核提供了semaphore、spinlock、mutex,rcu、atomic等锁机制来解决这些问题。然而每种锁机制都有不同的实现原理以使用场景,在性能方面也是会存在一定差异,因此对于不同场景下的问题我们能选择最适用的机制才是最好的。

此篇我们重点看下semaphore以及rw_semaphore 这些锁机制的内核源码实现。

一. semaphore

 信号量常用于进程间的同步问题
 信号量允许计数值大于1,也就是说允许多个进程进入临界区访问共享资源
 当计数值等于1,只允许一个进程进入,此时信号量类似mutex
 信号量不允许在中断处理中使用(中断不允许睡眠),因为其获取失败后会进入不可中断的睡眠状态(TASK_UNINTERRUPTIBLE)

1.1 semaphore使用首先需要初始化,看下面初始化相关的结构体:

struct semaphore {
      
	raw_spinlock_t		lock;   //@1
	unsigned int		count;   //@2
	struct list_head	wait_list; //@3
};

struct semaphore_waiter {
    //@4
	struct list_head list; 
	struct task_struct *task; 
	bool up; 
};    
@1. lock为自旋锁用于count的互斥访问。自旋锁用于很短时间就能完成的操作,不允许睡眠和进程切换

@2. count为计数值,为最大同时可访问临界区的进程数量

@3. 信号量申请不成功后,其申请者会放到wait_list等待队列中

@4. 等待队列定义,list用于关联到信号量的wait_list,task为等待的进程,up为从等待队列释放时会设为true

1.2 初始化后我们看使用场景。

down(sem);
...临界区资源...
up(sem);

down用于获取信号量,up用于释放信号量,我们重点看下源码实现

down

void down(struct semaphore *sem)  //@1
{
   
	unsigned long flags;
	raw_spin_lock_irqsave(&sem->lock, flags); //@2
	if (likely(sem->count > 0))
		sem->count--; //@3
	else
		__down(sem);//@4
	raw_spin_unlock_irqrestore(&sem->lock, flags);
}

static noinline void __sched __down(struct semaphore *sem)
{
   
	__down_common(sem, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}

@1. 获取信号量,如果获取失败会休眠直到信号量被释放。官方建议使用down_interruptible、down_killable,这几个接口的唯一差异是调用时传入参数不一样。
  down为TASK_UNINTERRUPTIBLE,表示睡眠过程不接受信号打断,
  down_interruptible为TASK_INTERRUPTIBLE,表示睡眠过程可接受信号打断,返回值表明是信号量申请成功还是信号打断
  down_killable为TASK_KILLABLE,表明睡眠过程中可因致命信号被中断,几个都是类似的。

@2.使用自旋锁关中断、抢占保护,目的是保证对count的原子访问

@3.可用计数大于0,申请成功进入临界区资源,可用计数需要减1

@4 可用计数不满足大于0,调用__down->__down_common进一步处理;

static inline int __sched __down_common(struct semaphore *sem, long state,	long timeout)
{
   
	struct semaphore_waiter waiter;
	list_add_tail(&waiter.list, &sem->wait_list); //@5
	waiter.task = current;
	waiter.up = false;
	for (;;) {
   
		if (signal_pending_state(state, current)) //@6
			goto interrupted;
		if (unlikely(timeout <= 0)) //@7
			goto timed_out;
		__set_current_state(state); //@8
		raw_spin_unlock_irq(&sem->lock); //@9
		timeout = schedule_timeout(timeout); //@10
		raw_spin_lock_irq(&sem->lock);
		if (waiter.up) //@11
			return 0;
	}
 timed_out:
	list_del(&waiter.list);
	return -ETIME;
 interrupted:
	list_del(&waiter.list);
	return -EINTR;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值