单片机
返回首页

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;

}

进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • 永不缺相启动运行的电动机控制电路

  • MT3608构成3.7V转12V的升压电路图

  • 比较常见的功率整流器和滤波电路

  • 一个简单的红外耳机电路

  • 基于CA3193的热电偶放大器电路

  • 基于TDA1554的立体声放大器电路

    相关电子头条文章