发信人: RoachCock (安息吧), 信区: KernelTech
标 题: 终于弄明白了 Linux 内核的 LOCK_PREFIX 的含义
发信站: 水木社区 (Fri Mar 13 02:32:32 2009), 站内
x86 架构的内核实现原子整数的时候,用到了 LOCK_PREFIX 这个宏
static __inline__ void atomic_add(int i, atomic_t *v)
{
__asm__ __volatile__(
LOCK_PREFIX "addl %1,%0"
:"+m" (v->counter)
:"ir" (i));
}
在 CONFIG_SMP 的时候:
#define LOCK_PREFIX /
".section .smp_locks,/"a/"/n" /
" .align 4/n" /
" .long 661f/n" /* address */ /
".previous/n" /
"661:/n/tlock; "
展开后变成这样:
.section .smp_locks,"a"
.align 4
.long 661f
.previous
661:
lock;
本来觉得直接加上 lock 前缀即可,前面一堆干吗用的一直不明白,终于决定要搞懂,
翻开 as 手册,查了个明白,现逐条解释如下:
.section .smp_locks,"a"
下面的代码生成到 .smp_locks 段里,属性为"a", allocatable,参考 as 7.76 .section
name
.align 4
四字节对齐
.long 661f
生成一个整数,值为下面的 661 标号的实际地址,f 表示向前引用,如果 661 标号出现
在前面,要写 661b。
.previous
代码生成恢复到原来的段,也就是 .text
661:
数字标号是局部标号,5.3 Symbol Names
lock;
开始生成指令,lock 前缀
这段代码汇编后,在 .text 段生成一条 lock 指令前缀 0xf0,在 .smp_locks 段生成
四个字节的 lock 前缀的地址,链接的时候,所有的 .smp_locks 段合并起来,形成一个
所有 lock 指令地址的数组,这样统计 .smp_locks 段就能知道代码里有多少个加锁的
指令被生成,猜测是为了调试目的。
----
搜索完成,果然找到了引用处:
linux-2.6.23.12/arch/i386/kernel/module.c
当一个内核模块被加载后调用这个
int module_finalize(const Elf_Ehdr *hdr,
const Elf_Shdr *sechdrs,
struct module *me)
{
const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL,
*para = NULL;
char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
if (!strcmp(".text", secstrings + s->sh_name))
text = s;
if (!strcmp(".altinstructions", secstrings + s->sh_name))
alt = s;
if (!strcmp(".smp_locks", secstrings + s->sh_name))
locks= s;
if (!strcmp(".parainstructions", secstrings + s->sh_name))
para = s;
}
if (alt) {
/* patch .altinstructions */
void *aseg = (void *)alt->sh_addr;
apply_alternatives(aseg, aseg + alt->sh_size);
}
if (locks && text) {
void *lseg = (void *)locks->sh_addr;
void *tseg = (void *)text->sh_addr;
alternatives_smp_module_add(me, me->name,
lseg, lseg + locks->sh_size,
tseg, tseg + text->sh_size);
}
if (para) {
void *pseg = (void *)para->sh_addr;
apply_paravirt(pseg, pseg + para->sh_size);
}
return module_bug_finalize(hdr, sechdrs, me);
}
上面的代码说,如果模块有 .text 和 .smp_locks 段,就调这个来处理,做什么呢?
void alternatives_smp_module_add(struct module *mod, char *name,
void *locks, void *locks_end,
void *text, void *text_end)
{
struct smp_alt_module *smp;
unsigned long flags;
if (noreplace_smp)
return;
if (smp_alt_once) {
if (boot_cpu_has(X86_FEATURE_UP))
alternatives_smp_unlock(locks, locks_end,
text, text_end);
return;
}
。。。
}
上面的代码说,如果是单处理器(UP),就调这个:
static void alternatives_smp_unlock(u8 **start, u8 **end, u8 *text, u8
*text_end)
{
u8 **ptr;
char insn[1];
if (noreplace_smp)
return;
add_nops(insn, 1);
for (ptr = start; ptr < end; ptr++) {
if (*ptr < text)
continue;
if (*ptr > text_end)
continue;
text_poke(*ptr, insn, 1);
};
}
看到这里就能明白,这是内核配置了 smp,但是实际运行到单处理器上时,通过运行期间
打补丁,根据 .smp_locks 里的记录,把 lock 指令前缀替换成 nop 以消除指令加锁的
开销,这个优化真是极致了……,可能考虑很多用户直接使用的是配置支持 SMP 编译好
的内核而特地对 x86/x64 做的这个优化。
看来学点汇编还是有用的。
顺手搜了一下:
http://www.google.cn/search?hl=zh-CN&newwindow=1&q=alternative+kernel+smp&meta=&
aq=f&oq=
又看到这段注释……,本来仔细看一下就明白了,折腾啊。
/*
* Alternative inline assembly for SMP.
*
* The LOCK_PREFIX macro defined here replaces the LOCK and
* LOCK_PREFIX macros used everywhere in the source tree.
*
* SMP alternatives use the same data structures as the other
* alternatives and the X86_FEATURE_UP flag to indicate the case of a
* UP system running a SMP kernel. The existing apply_alternatives()
* works fine for patching a SMP kernel for UP.
*
* The SMP alternative tables can be kept after boot and contain both
* UP and SMP versions of the instructions to allow switching back to
* SMP at runtime, when hotplugging in a new CPU, which is especially
* useful in virtualized environments.
*
* The very common lock prefix is handled as special case in a
* separate table which is a pure address list without replacement ptr
* and size information. That keeps the table sizes small.
*/
相关推荐
【精通内核】Linux 内核写锁实现原理与源码解析
也就是说,当有读锁持有时,如果有读任务,则可以直接获得读锁;然而,如果在持有写锁的情况下,那么读锁肯定获取失败,然后进入等待队列中,写锁被释放后,如果有锁等待,那会唤醒等待任务。有时候我们需要在获取到写锁后,进行降级为读锁,这可以通过 downgrade_write 方法进行锁降级有先原子性的降锁状态从写锁状态置为读锁状态,如果结果小于 0,则表明有任务正在等待被唤醒,此时可以调用 rwsem_downgrade_wake 函数唤醒等待读锁的任务,因为此时写锁已经被释放,可以让等待读锁的任务一起并行执行。
lock prefix
关于同步的原语,无非就那么几种,用于进程间同步的记录锁、信号量(record lock, semaphore), 用于线程间同步的互斥量、读写锁、条件变量(mutex, rwlock, condition variable),在某些特殊的场合下,我们可以自己实现简单的用户态的锁来进行同步,这依赖于lock prefix。根据intel 64 and IA-32 architectures sof
Linux C/C++并发编程实战(10)x86 上的原子操作实现--lock 指令前缀
当指令执行完毕,这个锁定动作也就会消失。在单处理器系统( UniProcessor,简称 UP)中,能够在单条指令中完成的操作都可以认为是原子操作,因为中断只能发生在指令与指令之间。在多处理器系统( Symmetric Multi-Processor,简称 SMP)中情况有所不同,由于系统中有多个处理器在独立的运行,即使在能单条指令中完成的操作也可能受到干扰。(以及所有以 ‘X’ 开头的指令)都能够保证在多处理器系统下的原子操作,它们总会宣告一个 “LOCK#” 信号,而不管有没有 LOCK 前缀。
linux同步之原子操作原理
x86和ARM64平台下内核原子操作的原理
pwm电机调速的原理介绍与代码实现
1、pwm实现调速的原理与介绍 PWM(Pulse Width Modulation)脉冲宽度调制。 1)占空比 pwm占空比就是一个脉冲周期内有效电平在整个周期所占的比例。 通过调节PWM的占空比就能调节IO口上电压的持续性变化,因此也能够控制外设的功率进行持续性变化,也就能控制直流电机的转速快慢。 那么重点就在于如何调节PWM波形的输出。如下图所示 图中的ARR是我们给定时器的一个预装载值,CCRx的上下变化是产生PWM波的关键。我们假设ARR大于CCRx的部分输出为高电平(即t1-t2、t3-t4
如何使用superpowers
"这个 bug 帮我修一下" → 我会自动走 systematic-debugging → TDD → verify 流程。- "帮我添加一个登录功能" → 我会自动走 brainstorming → plan → TDD → verify 流程。只要任务有 1% 的可能性适用某个技能,我就会先调用它再行动。→ TDD(测试驱动开发)→ verification(验证)→ code review(代码审查)提出需求 → brainstorming(头脑风暴)→ writing-plans(编写计划)
X64指令前缀概览
X64指令前缀概览
Verilog语法之十:过程块(initial和always)
我将Verilog的语法进行了总结,写了13篇文章,让小白“快速见识猪如何跑”,每一篇讲解一类语法,结合正确的示例代码和错误的示例代码,有的章节对个别语法进行了归纳总结,帮助初学者加深理解。
从JAVA、JVM以及汇编三个层面去理解volatile关键字
深入理解volatile关键字,了解他在不同层面的实现原理!
【Qt】QByteArray详解
对象共享同一份数据,直到修改时才进行深拷贝,以节省内存和计算资源。:可存储任意二进制数据(如图片、音频、协议数据),不依赖字符编码。与编码(如 UTF-8、Latin-1)之间的桥梁(例如。• 补零规则确保奇数字符串能正确解析,避免数据截断。:内部自动分配和释放内存,无需手动管理。将输入的字符串视为十六进制编码数据,返回实际数据长度(不包括结尾的。的输入必须是有效的十六进制字符(,但针对 Qt 框架做了优化。:处理加密后的二进制结果(如。• 如果输入字符串长度为奇数,• 若输入长度为奇数,自动在。
【C2000系列DSP的Bootloader详解】如何打包源文件为库文件且加密仅授权使用,一步步教你如何实现
如果想要在 TI 的 CCS 开发环境中为 C2000 系列 MCU 生成 lib 库文件,并对这些库文件进行加密保护,确保只有授权方(持有密钥)才能调用和使用,以此保护源代码的知识产权。
操作系统——操作系统锁
操作系统对数据同步的方法有:对最重要的几种锁(原子变量,关中断,信号量,自旋锁)。
【ArcGIS遇上Python】ArcGIS10.8 Python代码批量完美实现MODIS NDVI数据格式转换和投影变换
由于论文的需要,将MODIS NDVI数据进行投影变换和格式转换,具体操作可以参照:《ArcGIS10.8完美实现MODIS NDVI数据格式转换和投影变换》,但是该文章中的做法只能一次性实现一景影像的转换,没法批量,虽然ArcGIS中提供了Batch的方法但是需要挨个添加数据,确定输出路径等等,本文就实现以ArcGIS10.8 Python代码批量完美实现MODIS NDVI数据格式转换和投影变换。先来看投影后的效果: 在实现批量投影转换之前,需要两个投影文件:Sinusoidal.prj和MyAl
Linux 内核 LOCK_PREFIX 的含义
发信人: RoachCock (安息吧), 信区: KernelTech 标 题: 终于弄明白了 Linux 内核的 LOCK_PREFIX 的含义 发信站: 水木社区 (Fri Mar 13 02:32:32 2009), 站内 x86 架构的内核实现原子整数的时候,用到了 LOCK_PREFIX 这个宏 static __inline__ void atomic_add(in
OPTEE:TA命令操作的实现(三)
上文我们创建好了通道,现在就是操作,怎么操作TA呢?REE侧的CA执行创建会话操作成功后,CA就可使用获取到的调用来让TA执行特定的命令。通过ioctl的系统调用发送到OP-TEE的驱动中,保存在共享内存中,并触发安全监控模式调用(smc)切换到Monitor模式(ARMv7)或EL3(ARMv8)中进行安全世界状态的处理。
2025华为od面试手撕代码【求字符串表达式结果】
2025华为od面试手撕代码【求字符串表达式结果】
终于弄明白了Linux内核的LOCK_PREFIX的含义
x86 架构的内核实现原子整数的时候,用到了 LOCK_PREFIX 这个宏 static __inline__ void atomic_add(int i, atomic_t *v) { __asm__ __volatile__( LOCK_PREFIX "addl %1,%0" :"+m" (v->counter)
锂电池充电器电路设计 里面有电路
锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。
LINUX内核之普通自旋锁
LINUX内核之普通自旋锁 @CopyLeft by ICANTH,I Can do ANy THing that I CAN THink!~ Author:WenHui,WuHan University,2012-6-15 PDF版阅读地址:http://www.docin.com/p1-424285718.html 普通自旋锁 自旋锁最常见的使用场景是创建一段临界
lwip-2.0.3
lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。
迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)
迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)
linux内核原子操作的实现
所谓原子操作,就是“不可中断的一个或一系列操作”。硬件级的原子操作:在单处理器系统(UniProcessor)中,能够在单条指令中完成的操作都可以认为是“原子操作”,因为中断只发生在指令边缘。在多处理器结构中(Symmetric Multi-Processor)就不同了,由于系统
精雕软件(JDpaint) 5.5 绿色版
精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版
linux内核同步
同步是linux内核中一种很重要的操作.它为内核提供了一种临界区和SMP系统中的数据保护机制.今天就来分析一下在linux内核是怎么样实现这些操作的.一:原子操作(摘自《understanding the linux kernel 2.4》)原子操作是指在执行过程中不能被打断的操作.它包括以下几种类型:进行一次或者零次对齐内存的访问操作都是原子操作.因为这些指令一般都是单指令.不可
Linux内核中的cmpxchg函数
Linux内核中的cmpxchg函数 http://www.longene.org/forum/viewtopic.php?t=2216 前几天,为了这个函数花了好多时间,由于参考的资料有误,一直都没有看明白,直到google之后,总算搞明白了,因此写出来大家分享一下。 在Linux内核中,提供了比较并交换的函数cmpxchg,代码在include/asm-i386/cmpx
Linux内核原子操作(2)接口与实现
处理器在提供了硬件级别的原子操作保障后,软件可以基于硬件机制实现软件级别的原子操作接口,提供给软件模块使用。
瞧一瞧Linux:Linux的自旋锁和信号量如何实现?
你好,我是程序员贵哥。上节课,我们学习了解决数据同步问题的思路与方法。Linux作为成熟的操作系统内核,当然也有很多数据同步的机制,它也有原子变量、开启和关闭中断、自旋锁、信号量。那今天我们就来探讨一下这些机制在Linux中的实现。看看Linux的实现和前面我们自己的实现有什么区别,以及Linux为什么要这么实现,这么实现背后的机理是什么。
Linux内核同步机制——自旋锁
之前已经给出了原子操作部分内容,现将自旋锁部分内容整理如下,其中代码引用自os网站上源码阅读连接中的2.6.22.6版本,体系结构选用了i386。 信号量部分将在后续给出。 有疑义,欢迎共同探讨!2.自旋锁自旋锁是Linux内核常用的锁机制,它只能被一个执行进程持有。当一个进程去获取已被其他进程占有的自旋锁时,该进程会一直等待,直到锁可用为止。由于自旋锁的这种忙等机制,使得自旋锁不适合长期加锁
linux 内核 锁,深入linux内核架构--内核锁
简介在多线程(进程)并发模型中,多个线程如果同时处理同一块数据的话,会引发竞态问题,以及随之而来的线程安全问题。而锁是解决线程安全的重要手段,其中主要包括原子性操作atomic,自旋锁spin_lock,信号量semaphore,互斥信号量mutex,读写锁rw_lock等等。临界区临界区是指一个访问共用资源(例如:共用设备或是共用存储器)的程序片段,而这些共用资源又无法同时被多个访问的特性。当一...
1057



被折叠的 条评论
为什么被折叠?



