OK6410A 开发板 (八) 74 linux-5.11 OK6410A linux 内核同步机制 信号量(count=1)的实现
作者:互联网
- 解决的问题是什么
所有异常原因
- 限制是什么
加锁函数会引起睡眠,所以不能...
实现
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, %4\n"
" strex %2, %1, [%3]\n"
" teq %2, #0\n"
" 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;
}
标签:count,__,lock,OK6410A,raw,linux,sem,spin 来源: https://blog.csdn.net/u011011827/article/details/117818723