首页 > 其他分享 >19 同步与互斥(五)自旋锁

19 同步与互斥(五)自旋锁

时间:2023-04-29 17:24:10浏览次数:34  
标签:__ raw 19 lock 互斥 自旋 spin spinlock

1 简介

自旋锁:通俗的说就是自己在原地打转,一直等待资源可用。不会休眠

对临界资源的访问时,因为自旋锁的存在,某段临界资源被占用后。其他事件将无法访问,即进行所谓的自旋,“原地打转”

注意:

  • 在自旋锁的临界区不能使用可能引起进程调度的函数(因为抢占已经被禁止了)。

    示例:

    copy_to_user、copy_from_user、kmalloc、msleep等

    可能会导致内核崩溃

  • spin_lock_irqsave只能控制当前CPU的中断,并不能控制多核的所有中断屏蔽,因此当中断与进程并发时,可能出现竟态。4

    所以对于SMP,在中断服务函数中还应使用spin_lock去屏蔽进程抢占

2 自旋锁的结构和API

2.1 自旋锁的结构

spinlock_t lock;		// 定义一个自旋锁

整个spinlock_t -> raw_spinlock -> arch_spinlock_t

在实现自旋的功能时arch_spinlock_t中owner、next是实现SMP的关键

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;
typedef struct raw_spinlock {
	arch_spinlock_t raw_lock;
#ifdef CONFIG_GENERIC_LOCKBREAK
	unsigned int break_lock;
#endif
#ifdef CONFIG_DEBUG_SPINLOCK
	unsigned int magic, owner_cpu;
	void *owner;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
	struct lockdep_map dep_map;
#endif
} raw_spinlock_t;
typedef struct {
	union {							// 注意这里使用的union
		u32 slock;
		struct __raw_tickets {
#ifdef __ARMEB__
			u16 next;
			u16 owner;
#else
			u16 owner;
			u16 next;
#endif
		} tickets;
	};
} arch_spinlock_t;

2.2 自旋的API

  • spin_lock_init(_lock)

    初始化自旋锁为unlock状态

  • void spin_lock(spin_lockt *lock)

    加锁

  • int spin_trylock(spinlock_t *lock)

    尝试加锁。成功返回1;失败返回0

  • void spin_unlock(spinlock_t *lock)

    解锁

  • int spin_is_locked(spinlock_t *lock)

    返回自旋锁的状态

自旋锁可以在原有的基础上添加后缀表示在执行相关的操作时还会做额外的事情

  • _bh

    加锁时会禁止中断下半部(softirq),解锁时使能中断下半部

  • _irq

    加锁时禁止中断,解锁时使能中断

  • _irqsave/_irqrestore

    加锁时禁止中断并记录此时状态,解锁时恢复中断为所记录的状态

3 自旋锁的实现机制

自旋的实现借助了ldrex,strex和ARM处理器内存屏障命令dmb、dsb、wfe、sev

3.1 单核

spin_lock -> raw_spin_lock -> _raw_spin_lock -> __LOCK - > ___LOCK ->

#define __LOCK(lock) \
  do { preempt_disable(); ___LOCK(lock); } while (0)
# define __acquire(x) (void)0

从上述调用可看出spin_lock只是去禁用了抢占,同理spin_lock_irq,在禁止抢占的同时禁止irq

3.2 SMP

3.2.1 spin_lock

spin_lock -> raw_spin_lock -> _raw_spin_lock -> __raw_spin_lock -> do_raw_spin_lock -> arch_spin_lock

static inline void __raw_spin_lock(raw_spinlock_t *lock)
{
	// 禁止强张
	preempt_disable();
	// debug
	spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
	LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
}

在__raw_spin_lock中禁用抢占


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"									@ lockval = &lock->slock 取出传入的自旋锁的next,owner
"	add	%1, %0, %4\n"									@ newval = lockval + (1 << TICKET_SHIFT) 即next++; 
"	strex	%2, %1, [%3]\n"								@ (&lock->slock) = newval; 整个过程可能会被优先级更高的事件抢占,导致失败。从而需要再次排号next++
"	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) {				// owner的号码与next不一致时,在下面去等待
		wfe();															// 暂时中断挂起执行,CPU低功耗运行
		lockval.tickets.owner = ACCESS_ONCE(lock->tickets.owner);		// 更新owner
	}

	// owner与next一致了,执行下面命令获得自旋锁
	smp_mb();
}

3.2.2 spin_unlock

static inline void arch_spin_unlock(arch_spinlock_t *lock)
{
	smp_mb();
	lock->tickets.owner++;
	dsb_sev(); // 执行sev指令,唤醒wfe等待的处理器
}

标签:__,raw,19,lock,互斥,自旋,spin,spinlock
From: https://www.cnblogs.com/burnk/p/17364263.html

相关文章

  • Gtk-Message: 09:56:19.551: Failed to load module "canberra-gtk-module"
    解决办法cmakemake....[100%]Builttargetopencv_exampleadmin@ub:~/opencv/samples/cpp/example_cmake/build$./opencv_exampleBuiltwithOpenCV4.6.0CaptureisopenedGtk-Message:09:56:19.551:Failedtoloadmodule"canberra-gtk-module"sudoap......
  • [TJOI2019]甲苯先生的滚榜
    [TJOI2019]甲苯先生的滚榜又双叒叕来水博客了几乎就是一个板子,虽然有两个关键字,但是实际上可以压成一个。k=a*mo-b其中a为过题数,b为罚时,mo=2e6,因为b<1.5e6。所以我们可以用这样一个二元组来表示。虽然说相同的二元组可以对应不同的人,但实际上是谁不重要,重要的是有哪些数。然......
  • Fuzzing101-Exercise1 fuzz xpdf CVE-2019-13288
    author:cxingdate:2023年4月28日0x00前期准备第一个exercise是复现xpdf的CVE-2019-13288,在正式进入fuzz之前我们需要了解xpdf和CVE-2019-13288。找到xpdf的官网,上面有一句简短的介绍。XpdfisafreePDFviewerandtoolkit,includingatextextractor,imagecon......
  • Python用RNN神经网络:LSTM、GRU、回归和ARIMA对COVID19新冠疫情人数时间序列预测|附代
    全文下载链接: http://tecdat.cn/?p=27042最近我们被客户要求撰写关于新冠疫情的研究报告,包括一些图形和统计输出。在本文中,该数据根据世界各国提供的新病例数据提供。获取时间序列数据df=pd.read_csv("C://global.csv")探索数据此表中的数据以累积的形式呈现,为了找出每天......
  • 我们常说的 CAS 自旋锁是什么
    CAS(Compareandswap),即比较并交换,也是实现我们平时所说的自旋锁或乐观锁的核心操作。它的实现很简单,就是用一个旧的预期的值和内存值进行比较,如果两个值相等,就用新的值替换内存值,并返回true。否则,返回false。保证原子操作任何技术的出现都是为了解决某些特定的问题,CAS要解决的......
  • Unity 2019.1 中文更新日志速览版
    洪流学堂微信公众号。洪流学堂,学Unity快人几步Unity2019.1已经正式发布,快来看看一些核心新功能吧!完整版的中文更新日志可在洪流学堂微信公众号回复2019.1获取。今年Unity的第一个技术版本——Unity2019.1已经发布。它包括许多新的可用于生产的功能,例如BurstCompiler,Lightweight......
  • 研究NIST FIPS 199 - 安全分类的标准
    NISTFIPS199-安全分类的标准FIPS199是在2004年2月发布的,这是一份古老的文件,但在实施信息安全时应首先遵循,无论你准备遵守哪种安全标准。常见的安全标准有:CIS、ISO27001、NIST网络安全框架等。目的根据风险程度提供适当的控制水平;推荐信息系统类别的准则;对所有类别都应做......
  • 第18,19,20章
    第18章PKI之梦18.1PKI的简短回顾PKI:公钥基础设施(PublicKeyInfrastruecture),通过它可以知道哪个公钥属于谁。CA:证书机构(CertificateAuthority),有一对公私密钥对(例如RSA密钥对),其中公钥是公开的。由于该公钥保持长期不变,一般假定所有人都知道CA的公钥。Howto加入PKI?用户生......
  • c++打卡练习(19)
    1.问题描述相传国际象棋是古印度舍罕王的宰相达依尔发明的。舍罕王十分喜爱象棋,决定让宰相自己选择何种赏赐。这位聪明的宰相指着8x8共64格的象棋棋盘说:陛下,请您赏给我一些麦子吧。就在棋盘的第1格中放1粒,第2格放2粒,第3格放4粒,以后每一格都比前一格增加一倍,依此放完棋盘上64格,我......
  • 4.19今日总结
    使用QtDesigner建立垂直菜单结构的折叠侧边栏的步骤如下:(1)以上文uiDemo8.ui为基础,在图形窗口的左侧创建垂直菜单结构的折叠侧边栏,在图形窗口的中间和右侧创建一个堆叠布局器stackedWidget。堆叠布局的页面布局和设计详见上文,本文不作赘述。(2)在QtDesigner左侧工具栏“Conta......