OK6410A 开发板 (八) 72 linux-5.11 OK6410A linux 内核同步机制 自旋锁的实现

发布者:创意狂想最新更新时间:2022-08-19 来源: csdn关键字:OK6410A  开发板  11  linux  自旋锁 手机看文章 扫描二维码
随时随地手机看文章

解决的问题是什么

所有竞态原因


大概意思

原子操作写的时候 可以同时发生 ,但不会同时成功,只有一个成功(成功的同时置位占用标识)

失败的那个,如果再去获取

先去读占用标识 (肯定是已经被占用,程序上就不再获取了,而是一直读占用标识)


实现

API spin_lock 的定义

//https://elixir.bootlin.com/linux/v4.0/source/include/linux/spinlock.h#L310

static inline void spin_lock(spinlock_t *lock)

{

raw_spin_lock(&lock->rlock);

}

//https://elixir.bootlin.com/linux/v4.0/source/include/linux/spinlock.h#L188

#define raw_spin_lock(lock) _raw_spin_lock(lock)



#ifndef CONFIG_INLINE_SPIN_LOCK

void __lockfunc _raw_spin_lock(raw_spinlock_t *lock)

{

__raw_spin_lock(lock);

}

EXPORT_SYMBOL(_raw_spin_lock);

#endif

https://elixir.bootlin.com/linux/v4.0/source/include/linux/spinlock_api_smp.h#L141

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);

}



https://elixir.bootlin.com/linux/v4.0/source/include/linux/lockdep.h#L430

#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)



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();

}


API spin_lock_init 的定义

https://elixir.bootlin.com/linux/v4.0/source/include/linux/spinlock.h#L304


#define spin_lock_init(_lock)

do {

spinlock_check(_lock);

raw_spin_lock_init(&(_lock)->rlock);

} while (0)


https://elixir.bootlin.com/linux/v4.0/source/include/linux/spinlock.h#L103


# define raw_spin_lock_init(lock)

do { *(lock) = __RAW_SPIN_LOCK_UNLOCKED(lock); } while (0)


https://elixir.bootlin.com/linux/v4.0/source/include/linux/spinlock_types.h#L59


#define __RAW_SPIN_LOCK_UNLOCKED(lockname)

(raw_spinlock_t) __RAW_SPIN_LOCK_INITIALIZER(lockname)


https://elixir.bootlin.com/linux/v4.0/source/include/linux/spinlock_types.h#L53

#define __RAW_SPIN_LOCK_INITIALIZER(lockname)

{

.raw_lock = __ARCH_SPIN_LOCK_UNLOCKED

}


https://elixir.bootlin.com/linux/v4.0/source/arch/arm/include/asm/spinlock_types.h#L25

#define __ARCH_SPIN_LOCK_UNLOCKED { { 0 } }

// 注意这里 { { 0 } } 展开为

{

.tickets = {

.owner = 0

}

}


spinlock_t 的定义

https://elixir.bootlin.com/linux/v4.0/source/include/linux/spinlock_types.h#L76


typedef struct spinlock {

union {

struct raw_spinlock rlock;

};

} spinlock_t;


https://elixir.bootlin.com/linux/v4.0/source/include/linux/spinlock_types.h#L32


typedef struct raw_spinlock {

arch_spinlock_t raw_lock;

} raw_spinlock_t;


https://elixir.bootlin.com/linux/v4.0/source/arch/arm/include/asm/spinlock_types.h#L23


typedef struct {

union {

u32 slock;

struct __raw_tickets {

u16 owner;

u16 next;

} tickets;

};

} arch_spinlock_t;


如何索引

spinlock_t *spin_lock_val ;

spin_lock_val->rlock.raw_lock.tickets.owner

spin_lock_val->rlock.raw_lock.tickets.next

spin_lock_val->rlock.raw_lock.slock


arch_spinlock_t *raw_spinlock_val;

arch_spinlock_val->tickets.owner

arch_spinlock_val->tickets.next

arch_spinlock_val->slock


arm 架构 原子指令

LDREX

用来读取内存中的值,并标记对该段内存的独占访问:

LDREX Rx, [Ry]


读取寄存器Ry指向的4字节内存值,将其保存到Rx寄存器中

同时

发现指向内存区域已经被标记为独占访问,则不会改变 "独占访问标记位"

发现指向内存区域没有被标记为独占访问,则 将 指向内存区域 标记为独占访问



STREX

在更新内存数值时,会检查该段内存是否已经被标记为独占访问,并以此来决定是否更新内存中的值:


STREX Rd, Rx, [Ry]


执行这条指令的时候发现已经被标记为独占访问了

1.将寄存器Rx中的值更新到寄存器Ry指向的内存,并将寄存器Rd设置成0

2.将独占访问标记位清除



执行这条指令的时候发现没有设置独占标记

1.不会更新内存,不会将寄存器Rd的值设置成1

2.不会改变 "独占访问标记位"


--

arch_spin_trylock 时

会先 load , 

如果load 结果为0  , 就 store 1

store 成功(Rd为0) , 就返回成功(0)

store 失败(Rd为1) , 就返回失败(非0)

如果load 结果为1  , 就返回失败(非0)


场景分析


第一种情况AB12

A.LDREX

A.STREX

B.LDREX

B.STREX

第二种情况A1B2

A.LDREX

B.LDREX

A.STREX

B.STREX

第三种情况A12B

A.LDREX

B.LDREX

B.STREX

A.STREX


其他情况

A.LDREX & B.LDREX (不管A和B在什么时候发生,都会正常执行)


A.STREX & B.STREX (同时发生,只有一个会将Rd弄成0,另一个为1)


arm   是根据    该内存        是否 标记独占 , strex 来做 不同的事情

riscv 是根据    该内存中的值  是否 为0      , amoswap 来做不同的事情 


AMOSWAP  amoswap.{w/d}.{aqrl} rd, rs2, (rs1) 原子交换指令,

   会判断 rs1 是否为0

      如果为0 , 则 rd = *rs1, *rs1 = rs2 // 即rd 为0 , 同时 *rs1 = rs2

      做成功了 , rd 为 0

      做失败了 , rd 为 1

      如果为1 , 则 , rd = 1 , *rs1 = rs2



arch_spin_trylock 时

会做 amoswap , 

如果rs1 结果为0  , 就 尝试 swap  // 1. rd <- *rs1  2. *rs1 <-rs2

swap 成功(rd为0) , 就返回成功(0)

swap 失败(rd为1) , 就返回失败(非0)

如果rs1 结果为1  , 就返回失败(非0)

关键字:OK6410A  开发板  11  linux  自旋锁 引用地址:OK6410A 开发板 (八) 72 linux-5.11 OK6410A linux 内核同步机制 自旋锁的实现

上一篇:OK6410A 开发板 (八) 73 linux-5.11 OK6410A linux 内核同步机制 互斥锁的实现
下一篇:OK6410A 开发板 (八) 71 linux-5.11 OK6410A linux 内核同步机制 禁软中断的实现

推荐阅读最新更新时间:2024-10-13 18:00

嵌入式linux-arm交叉编译工具链的构建
第一步:首先下载如下源文件 binutils-2.16. tar.gz,gcc-3.4.4.tar.bz2, t-linux.diff, glibc-2.3.5.tar.gz, glibc-linuxthreads-2.3.5.tar.gz, ioperm.c.diff, linux-2.6.11.12tar.gz 并且把所有的源文件放入/home/zmj/usr/arm/src文件夹中,其中zmj是用户名。并把如下脚本,写入一个文件,例如文件名为buildchain.sh,并把该文件放入usr目录下。 第二步: 运行buildchain.sh脚本即可。其中第七步是不需要的,将来自己编译内核的时候还要重新配置,故可以删去。 #!/b
[单片机]
Linux 6.2 内核已正式发布,广泛支持苹果 M1 系列芯片
Linux 创始人 Linus Torvalds 现发布了稳定的 Linux 6.2 内核更新,带来了一些新的驱动程序、新功能等等,并且还有一些硬件支持和安全性改进。 这是 Linux 2023 年的第一个主要内核版本更新。Linux 6.3 合并窗口今日已正式开启,Linus 称其 “已经有 30 多个拉取请求在排队”。 经过两个多月的努力,Linux 内核 6.2 终于引入了 IPv6 堆栈的保护性负载平衡 (PLB),支持英特尔“异步退出通知”机制,新的 x86 FineIBT 控制流完整性机制,以及进一步改进新的 Rust 基础设施。 硬件方面,Linux 6.2 提升了 Intel 锐炫显卡 (DG2 / A
[嵌入式]
基于嵌入式Linux的矩阵键盘驱动程序开发
   O 引 言   随着以计算机技术、通信技术和软件技术为核心的信息技术的发展,嵌入式系统在各个行业中得到了广泛的应用。嵌入式系统已成为当今IT行业的焦点之一。而在嵌入式系统中,键盘是重要的人机交互设备之一。嵌入式Linux是一种开放源码、软实时、多任务的操作系统,是开发嵌入式产品的优秀操作系统平台,是在标准Linux基础上针对嵌入式系统进行优化和裁剪后形成的,因此具有Linux的基本性质。在此提出的矩阵键盘驱动程序的设计方案是以嵌入式Linux和TIOMAP5912处理器为软硬件平台的,在设计的嵌入式语音识别应用平台中,通过测试,表明其具有良好的稳定性和实时性。    l 硬件原理   OMAP5912处理器是由T
[嵌入式]
计数型和移存型的具有自启动功能的01011序列信号发生器
序列信号为01011,序列信号长度为5 一、计数型序列信号发生器 由于序列信号长度为5,所以要考虑选用一个模5计数器,则应选取计数循环为011,100,101,110,111。 仿真实验电路图如下: 时钟信号频率设置为1Hz,周期为1秒,可以自行根据需要调节,便于对运行结果进行观察。在数据选择器的输出端连接一个提示灯,可以对运行的输出结果进行明显的反映。 时钟信号波形图: 输出结果波形图: 提示灯就如输出结果波形一样,灭一秒亮一秒,灭一秒亮两秒,即输出为01011。 二、移存型序列信号发生器 序列信号长度为5,首先考虑使用三位移存寄存器,序列信号分组情况为:010,101,011,110,101,不能满足要
[测试测量]
计数型和移存型的具有自启动功能的010<font color='red'>11</font>序列信号发生器
vivo首批适配Android 11预览版机型 即日可升级
6月12日上午消息,智能手机品牌vivo正式宣布旗下两款5G手机NEX 3S和iQOO 3成为首批适配Android 11 Developer Preview版的机型。   美国当地时间6月11日,谷歌在Android 11 Beta Launch Show上正式发布全新一代Android 11 Beta版。随后一些手机厂商陆续宣布首发适配的机型。vivo表示为了开发者能第一时间针对vivo手机进行Android 11 Developer Preview版的升级适配,vivo数月前就和谷歌启动密切合作。 vivo首批适配Android 11 Developer Preview版   即日起,开发者可以前往vivo开发者网站v
[手机便携]
ARMv7:Linux Kernel引导
1.如果内核镜像是压缩的,需要解压缩,引导的第一步是从解压缩开始:archarmbootcompressedhead.S 2.解压缩之后,内核镜像已经存在于ARM中了,下面开始运行,内核开始运行是从/arch/arm/kernel/head.S开始的,入口代码为: 1 2 3 4 5 6 7 8 .arm __HEAD ENTRY(stext) THUMB( adr r9, BSYM(1f) ) @ Kernel is always entered in ARM. THUMB( bx r9 ) @ If this is a Thumb-2 kernel, THUMB( .
[单片机]
米尔电子2023年度大事记丨2023砥砺奋进,2024扬帆远航
有人说,2023年是经济下行的一年 有人说,2023年是充满挑战的一年 也有人说,2023年是充满希望的一年 于米尔来说 2023年是砥砺奋进的一年 这一年 我们用汗水书写辉煌 我们用奋斗书写芳华 跟随小编来盘点2023年米尔大事记 展望全新的2024  新品发布,助力开发 2023年米尔电子激昂前进,开发了很多新的平台方案,共计推出了核心板开发板10款,成为覆盖全面,品质优良的嵌入式CPU模组供应商。  外资平台,集齐四大半导体原厂的主流MPU,成为外资工业处理器核心板最全供应商: 米尔是目前国内唯一一家能全面提供主流外资半导体厂商入门级及中高端MPU的芯片厂家,可以给客户提供一站式的选型
[嵌入式]
米尔电子2023年度大事记丨2023砥砺奋进,2024扬帆远航
韦东山嵌入式Linux_3期之USB摄像头监控_手机App增加录像功能(二)
一、模块划分 i) (主体模块)视频采集播放 ii) 显示模式切换 iii) 拍照 iv) 录像 v) fps显示 vi) 录像的浏览和删除 回到顶部(go to top) 二、各模块的实现 2.1(主体模块)视频采集播放 2.1.1 参考资料: 1)主体框架(解码、读帧)参考雷霄骅的:100行代码实现最简单的基于FFMPEG+SDL的视频播放器(SDL1.x) 主体框架的流程,可参考雷霄骅的上述博文,这里不再赘述 2)帧的显示,参考:Android 使用 FFmpeg (二)——视屏流播放简单实现 帧显示的流程,大致如下: 2.2 显示模式切换 实现思路:利用av_filter
[单片机]
韦东山嵌入式<font color='red'>Linux</font>_3期之USB摄像头监控_手机App增加录像功能(二)
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved