手机网站建设事项,装修效果图制作,临海市建设局网站,长沙网红美食打卡地[内核同步]自旋锁spin_lock、spin_lock_irq 和 spin_lock_irqsave 分析漫画|Linux 并发、竞态、互斥锁、自旋锁、信号量都是什么鬼#xff1f;Linux内核自旋锁之前写的自旋锁的文章#xff0c;现在再加一篇#xff0c;可能单纯的一两次说明不能把问题说清楚。所以再写一篇文… [内核同步]自旋锁spin_lock、spin_lock_irq 和 spin_lock_irqsave 分析漫画|Linux 并发、竞态、互斥锁、自旋锁、信号量都是什么鬼Linux内核自旋锁之前写的自旋锁的文章现在再加一篇可能单纯的一两次说明不能把问题说清楚。所以再写一篇文章也希望更多的人参与讨论这样会让问题更加清晰明了。自旋锁的特点是在等待锁的过程中不会休眠会不断的占用CPU轮询锁的状态一旦发现锁被释放就会马上获取锁。 基于这样的特点自旋锁spinlock适用于保护执行时间非常短的临界区。自旋锁有两个特点进入临界区后不能调用可能引起系统休眠的函数。临界区的代码不能被中断函数重入调用。如果进入临界区后睡眠会引起这样的问题如下图如果临界区的代码在执行的时候中断重入调用如下图上面两种情况下都出现一个问题就是在临界区运行时还没有来得及释放锁当前进程被动释放了CPU的使用权然后下次「可能是中断处理函数可能是CPU调度的其他进程」再进来的时候情况就会比较复杂因为之前的程序一直没有释放导致锁一直获取失败失败后又一直在等待而且永远等不到锁的释放就会导致死锁了。优先级反转问题系统运行对时间要求非常严格如果因为某些问题导致系统时间延迟有误差可能会导致比较严重的问题这种情况在实时系统中会更严重。我描述下优先级反转的问题。A和C共享一个资源但是在运行过程中在某一个时刻C占有资源的时候被高于它优先级的进程B抢占了这时候B就处于一个有利位置一直会有CPU运行如果有其他进程优先级高于C的也会能拿到CPU运行。这就出现了一个奇怪的现象低优先级的进程抢占了高优先级的进程如果A是特斯拉的刹车进程的话我相信故障就此发生。如何解决优先级翻转的问题呢提升C的优先级让C的优先级高于B就不会存在持有锁的情况下被抢占。但是C的优先级提升到多少合适呢假设共享资源R有5个任务会申请它我们需要做的是持有R资源的任务的优先级是这5个任务中最高的这就叫优先级提升。spinlock相关代码基于4.4内核typedef struct {volatile unsigned int slock;
} arch_spinlock_t;#define __ARCH_SPIN_LOCK_UNLOCKED__ 0
#define __ARCH_SPIN_LOCK_LOCKED__ 1#define __ARCH_SPIN_LOCK_UNLOCKED { __ARCH_SPIN_LOCK_UNLOCKED__ }
#define __ARCH_SPIN_LOCK_LOCKED { __ARCH_SPIN_LOCK_LOCKED__ }
//...typedef struct raw_spinlock {arch_spinlock_t raw_lock;
#ifdef CONFIG_GENERIC_LOCKBREAKunsigned int break_lock;
#endif
#ifdef CONFIG_DEBUG_SPINLOCKunsigned int magic, owner_cpu;void *owner;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOCstruct lockdep_map dep_map;
#endif
} raw_spinlock_t;//...typedef struct spinlock {union {struct raw_spinlock rlock;#ifdef CONFIG_DEBUG_LOCK_ALLOC
# define LOCK_PADSIZE (offsetof(struct raw_spinlock, dep_map))struct {u8 __padding[LOCK_PADSIZE];struct lockdep_map dep_map;};
#endif};
} spinlock_t;
自旋锁函数调用static __always_inline void spin_lock(spinlock_t *lock)
{raw_spin_lock(lock-rlock);
}
//1
#define raw_spin_lock(lock) _raw_spin_lock(lock)
//2
#ifndef CONFIG_INLINE_SPIN_LOCK
void __lockfunc _raw_spin_lock(raw_spinlock_t *lock)
{__raw_spin_lock(lock);
}
EXPORT_SYMBOL(_raw_spin_lock);
#endif
//3
static inline void __raw_spin_lock(raw_spinlock_t *lock)
{preempt_disable();spin_acquire(lock-dep_map, 0, 0, _RET_IP_);LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
}
//4LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
//5
#define LOCK_CONTENDED(_lock, try, lock) \
do { \if (!try(_lock)) { \lock_contended((_lock)-dep_map, _RET_IP_); \lock(_lock); \} \lock_acquired((_lock)-dep_map, _RET_IP_); \
} while (0)//6
static inline void do_raw_spin_lock(raw_spinlock_t *lock) __acquires(lock)
{__acquire(lock);arch_spin_lock(lock-raw_lock);
}//7static inline void arch_spin_lock(arch_spinlock_t *lock)
{unsigned int val;SCOND_FAIL_RETRY_VAR_DEF;smp_mb();__asm__ __volatile__(0: mov %[delay], 1 \n1: llock %[val], [%[slock]] \n /*LOCK指令前缀会设置处理器的LOCK#信号译注这个信号会使总线锁定阻止其他处理器接管总线访问内存直到使用LOCK前缀的指令执行结束这会使这条指令的执行变为原子操作。在多处理器环境下设置LOCK#信号能保证某个处理器对共享内存的独占使用。*/ breq %[val], %[LOCKED], 0b \n /* spin while LOCKED 判断变量是否为0如果不为0说明自旋锁已经被获取当前获取就会失败 */ scond %[LOCKED], [%[slock]] \n /* acquire */ bz 4f \n /* done */ \nSCOND_FAIL_RETRY_ASM: [val] r (val)SCOND_FAIL_RETRY_VARS: [slock] r ((lock-slock)),[LOCKED] r (__ARCH_SPIN_LOCK_LOCKED__) /*获取锁把变量值加1*/: memory, cc);smp_mb();
}参考https://blog.csdn.net/longwang155069/article/details/52055876推荐阅读专辑|Linux文章汇总专辑|程序人生专辑|C语言我的知识小密圈关注公众号后台回复「1024」获取学习资料网盘链接。欢迎点赞关注转发在看您的每一次鼓励我都将铭记于心~