OK6410A 开发板 (八) 74 linux-5.11 OK6410A linux 内核同步机制 信号量(count=1)的实现
2022-08-19 来源:csdn
解决的问题是什么
所有异常原因
限制是什么
加锁函数会引起睡眠,所以不能...
实现
https://elixir.bootlin.com/linux/v4.0/source/kernel/locking/semaphore.c#L53
/*
向下-获取信号量
@sem:要获取的信号量
获取信号量。如果不允许更多任务获取信号量,则调用此函数将使任务进入睡眠状态,直到释放信号量。
不赞成使用此函数,请改用down_interruptible()或down_killable()。
*/
void down(struct semaphore *sem)
{
unsigned long flags;
raw_spin_lock_irqsave(&sem->lock, flags);
if (likely(sem->count > 0))
sem->count--;
else
__down(sem);
raw_spin_unlock_irqrestore(&sem->lock, flags);
}
EXPORT_SYMBOL(down);
https://elixir.bootlin.com/linux/v4.0/source/include/linux/spinlock.h#L215
#define raw_spin_lock_irqsave(lock, flags)
do {
typecheck(unsigned long, flags);
flags = _raw_spin_lock_irqsave(lock);
} while (0)
https://elixir.bootlin.com/linux/v4.0/source/kernel/locking/spinlock.c#L157
#ifndef CONFIG_INLINE_SPIN_LOCK_IRQSAVE
unsigned long __lockfunc _raw_spin_lock_irqsave(raw_spinlock_t *lock)
{
return __raw_spin_lock_irqsave(lock);
}
EXPORT_SYMBOL(_raw_spin_lock_irqsave);
#endif
https://elixir.bootlin.com/linux/v4.0/source/include/linux/spinlock_api_smp.h#L106
static inline unsigned long __raw_spin_lock_irqsave(raw_spinlock_t *lock)
{
unsigned long flags;
local_irq_save(flags);
preempt_disable();
spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
/*
* On lockdep we dont want the hand-coded irq-enable of
* do_raw_spin_lock_flags() code, because lockdep assumes
* that interrupts are not re-enabled during lock-acquire:
*/
#ifdef CONFIG_LOCKDEP
LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
#else
do_raw_spin_lock_flags(lock, &flags);
#endif
return flags;
}
https://elixir.bootlin.com/linux/v4.0/source/include/linux/spinlock.h#L151
static inline void do_raw_spin_lock(raw_spinlock_t *lock) __acquires(lock)
{
__acquire(lock);
arch_spin_lock(&lock->raw_lock);
}
https://elixir.bootlin.com/linux/v4.0/source/arch/arm/include/asm/spinlock.h#L58
static inline void arch_spin_lock(arch_spinlock_t *lock)
{
unsigned long tmp;
u32 newval;
arch_spinlock_t lockval;
prefetchw(&lock->slock);
__asm__ __volatile__(
'1: ldrex %0, [%3]n'
' add %1, %0, %4n'
' strex %2, %1, [%3]n'
' teq %2, #0n'
' bne 1b'
: '=&r' (lockval), '=&r' (newval), '=&r' (tmp)
: 'r' (&lock->slock), 'I' (1 << TICKET_SHIFT)
: 'cc');
while (lockval.tickets.next != lockval.tickets.owner) {
wfe();
lockval.tickets.owner = ACCESS_ONCE(lock->tickets.owner);
}
smp_mb();
}
https://elixir.bootlin.com/linux/v4.0/source/kernel/locking/semaphore.c#L236
static noinline void __sched __down(struct semaphore *sem)
{
__down_common(sem, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}
https://elixir.bootlin.com/linux/v4.0/source/kernel/locking/semaphore.c#L204
/*
因为这个函数是内联的,所以'state'参数将是常量,因此由编译器优化。同样,对于没有超时的情况,“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.task = task;
waiter.up = false;
for (;;) {
if (signal_pending_state(state, task))
goto interrupted;
if (unlikely(timeout <= 0))
goto timed_out;
__set_task_state(task, state);
raw_spin_unlock_irq(&sem->lock);
timeout = schedule_timeout(timeout);
raw_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;
}
上一篇:OK6410A 开发板 (八) 75 linux-5.11 OK6410A linux 内核同步机制 读写锁的实现
下一篇:OK6410A 开发板 (八) 73 linux-5.11 OK6410A linux 内核同步机制 互斥锁的实现
- 〖Linux〗OK6410a蜂鸣器的驱动程序编写全程实录
- 开发环境搭建 (一) OK6410A 开发环境 1官方环境 OK
- 开发环境搭建 (一) OK6410A 开发环境 2 更改环境 OK
- 开发环境搭建 (一) OK6410A 开发环境 3 更改环境 FAIL
- 开发环境搭建 (二) OK6410A 开发环境 其他
- 开发环境搭建 (一) OK6410A 开发环境 4 更改环境 OK
- OK6410A 开发板 (二) 环境熟悉
- OK6410A 开发板 (三) u-boot-1.1.6 boot 解析
- OK6410A 开发板 (四) OK6410A 裸机代码
- OK6410A 开发板 (五) u-boot-2021.01 移植 到 ok6410a