Bus Locking

Intel 64和IA-32处理器提供了LOCK#信号,在某些关键的访存操作时会自动地激活assert这个信号,用于封锁系统总线或类似的链接。当这个输出信号被激活时,就会阻塞来自于其他的处理器或总线代理的总线控制请求。在其他情况下,如果软件业务逻辑需要封锁总线,可以在相应的指令前放置一个LOCK指令前缀。

对于Intel386,Intel486,和Pentium处理器,显示地指定LOCK前缀,会使处理器激活LOCK#信号。硬件设计人员有责任在设计硬件时,提供LOCK#信号的接收机制,用来控制处理器间的访存操作。

对于P6及其后代处理器,如果访存操作命中处理器的内部缓存,在LOCK#信号通常不会被激活;而且,“加锁操作”只会发生在处理器的内部缓存中。

Automatic Locking

在以下操作中,处理器自动遵循“加锁的”的语义(即执行原子操作):

  • 当执行XCHG指令时,有操作数引用存储器数据。
  • 当设置TSS描述符中的B(busy)标志位时 – 当切换任务时,处理器会测试并设置(test and set)TSS描述符的TYPE域的B标志位。为了确保两个处理器不会同时切换到同一个任务,处理器在处理B标志位时,会遵循“加锁的”语义。
  • 当更新段描述符时 – 当载入一个段描述符时,如果段描述符的A(accessed)标志位没有被设置,则处理器会将其置1。在这个操作中,处理器也遵循加锁语义,这样段描述符在被更新时,就不会被其他的处理器修改。为了让这个过程更加高效,用于更新描述符的操作系统程序应该遵守如下的步骤:
    • 使用加锁的操作修改段描述符的访问权限字节,指示描述符不存在,在描述符的TYPE域设定一个值,指示描述符正在被更新。
    • 更新段描述符的域(这个操作可能需要多次访存操作;因此,不能使用加锁的操作)
    • 使用加锁的操作修改段描述符的访问权限字节,指示描述符有效而且可用。

注:参看下图,以数据段描述符为例。

  • 不管段描述符的访问标志位是否被设置,Intel386处理器总是会更新这个标志位。但是在Intel486,Pentium,P6 family,Pentium 4,Intel Xeon处理器上,会先测试这个标志位,只有当没有设置时,才会将其置1。
  • 当更新页目录和页表条目时,处理器使用加锁的操作来设置页目录和页表条目的访问标志位A与脏标志位D。

  • 中断确认 – 在中断请求发出后,中断控制器可能使用数据总线给处理器发送中断向量。处理器使用加锁语义,确保在中断向量传输时,没有其他的数据会出现在数据总线上。

Software Controlled Bus Locking

要显式地指示加锁语义,软件可以使用LOCK指令前缀。不是所有的指令都可以加LOCK前缀。下列的指令在操作存储器操作数时,可以使用LOCK前缀。当在其他指令前或者下述的指令前但是没有向内存写入数据(即目标操作数是寄存器)时,使用LOCK前缀会导致处理器产生无效操作码异常(#UD)。

  • 比特位测试与修改指令(BTS,BTR,和BTC)
  • 交换指令(XADD,CMPXCHG,和CMPXCHG8B)
  • 对XCHG指令,处理器自动假设LOCK前缀
  • 单操作数算术与逻辑指令:INC,DEC,NOT,和NEG
  • 双操作数算术与逻辑指令:ADD,ADC,SUB,SBB,AND,OR和XOR

对于加锁的指令,处理器提供的保证是目标操作数的内存区域一定是原子性操作;但是系统可能将这个区域解释为更大的范围(注:例如,一个缓存行)。

软降应该使用相同的地址与操作数长度来访问信号量(在多个处理器之间传递信号的共享内存空间)。例如,如果一个处理器使用单字长度访问信号量,其他的处理器就不应该使用字节长度访问信号量。

注意:不要使用WC类型的内存实现信号量。对用来实现信号量的缓存行,不要使用非时效存储操作。

总线封锁操作的完整性不会受到内存区域的对齐方式影响。LOCK语义会一直持续到这个个操作数更新完成。但是,非常推荐将LOCK的操作数放置于它们的自然对齐的地址上,主要是出于性能方面的考虑:

  • 单字节访问可以是任何位置
  • 两字节访问在16位边界上
  • 双字访问在32位边界上
  • 四字访问在64位边界上

相对于其他的访存操作与其他的外部可见事件,加锁的操作时原子性的。只有取指与页表访问可以跨越加锁的指令。因此,加锁的指令可以用于同步一个处理器的数据写入与另一个处理器的数据读取。

对于P6 family处理器,加锁的操作会串行化所有未完成的读存与写存操作(即等待所有的访存指令完成)。这个规则对于Pentium 4与Intel Xeon处理器也适用,只有一个例外:引用弱排序内存类型(例如WC类型的内存)的读操作不会被串行化。

加锁的指令不应该被用来保证写入的数据能被当作指令进行取指。

注意:当前版本的Pentium 4,Intel Xeon,P6 family,Pentium和Intel 486处理器允许写入的数据被当作指令读取。但是,Intel推荐想要使用自修改代码的开发者使用另一种同步机制达到这个目的。参看下节。

Handling Self- and Cross-Modifying Code

TODO

Effects of a Lock Operation on Internal Processor Caches

对于Intel486和Pentium处理器,在执行LOCK操作时,LOCK#信号总是被激活,即使被加锁操作的内存区域已经位于在处理器的缓存中。

对于P6和更新的处理器,如果加锁的指令要操作的数据已经位于处理器的缓存中且完全包含在一个缓存行中,同时数据所在的内存区域属于回写式WB内存,处理器可能不会在总线上激活LOCK#信号。相应的,处理器会修改缓存中的数据,同时使用缓存一致性机制来确保加锁操作的原子性。这个操作叫做缓存封锁(cache locking)。缓存一致性协议自动的阻止两个或多个处理器同时修改它们缓存的相同地址区域里的数据。

Intel 64/x86_64/IA-32/x86处理器 - 锁原子操作(2) - 总线封锁/缓存封锁相关推荐

  1. Intel 64/x86_64/IA-32/x86处理器 - 锁原子操作(1) - 处理器保证的原子操作

    Locked Atomic Operations 32位的IA-32处理器支持对系统内存中的位置执行"加锁的原子操作".这些操作通常用于管理共享的数据结构(例如信号量,段描述符,系 ...

  2. Intel 64/x86_64/IA-32/x86处理器段寄存器 - 32位段寄存器/64位段寄存器

    Segment Registers 本节主要讲述Intel处理器中的段寄存器,用于支持处理器的段式存储器管理机制.16位的8086/Intel286处理器有4个段寄存器CS/DS/SS/ES.32位的 ...

  3. Intel 64/x86_64/IA-32/x86处理器基本执行环境 (1) - 32位执行环境概述

    Basic Execution Environment Overview IA-32处理器提供了一套完整的资源,在处理器上运行的程序/任务可以执行指令,存储代码,数据以及状态信息.这些资源(如下简要的 ...

  4. Intel 64/x86_64/IA-32/x86处理器 - SIMD指令集 - SSE扩展(1) - 概述/历史/新数据类型/XMM寄存器组

    SSE Instructions SSE Overview & History Intel SSE技术的全称是Streaming SIMD Extension,中文译作流式单指令多数据指令扩展 ...

  5. Intel 64/x86_64/x86/IA-32处理器操作模式/运行模式

    Processor Operation Mode IA-32架构支持3种操作模式,和一种类操作模式(quasi-operating mode): 实地址模式/实模式(real-address mode ...

  6. Intel 64/x86_64/IA-32/x86处理器 - SIMD指令集 - SSE扩展(7) - 混洗指令 解组合指令

    SSE Shuffle and Unpack Instructions SSE的混洗指令与解组合指令混洗shuffle或交错interleave单精度浮点操作数,并将结果保存到目标操作数. 指令 描述 ...

  7. Intel 64/x86_64/IA-32/x86处理器 - SIMD指令集 - MMX技术(1) - 概述 传输指令

    MMX™ Instructions IA-32架构引入了4个指令集扩展,使得IA-32处理器可以执行单指令多数据SIMD操作.这些扩展包括MMX技术,SSE扩展,SSE2扩展,SSE3扩展. MMX指 ...

  8. Intel 64/x86_64/IA-32/x86处理器 - 通用指令(1) - 数据传输指令

    General-Purpose Instructions 通用指令执行基本的数据搬移,算术/逻辑计算,程序流控制,字符串操作等.这些指令被频繁地用于运行在IA-32与Intel 64架构的系统软件与应 ...

  9. Intel 64/x86_64/IA-32/x86处理器指令集 - CPUID (1) - 概述

    CPUID指令 Introduction of CPUID instruction 根据Wikipedia,CPUID指令是x86处理器体系结构的补充指令,使得软件可以枚举当前运行的处理器的详细特性, ...

最新文章

  1. R语言dir函数获取目录中文件或者文件夹名称实战
  2. python物联网通信_物联网通信RESTDemo示例程序(Python版本)
  3. Let‘s Play Curling 二分,lower_bound(2020.12.南京)
  4. pyqt5获取文本框里输入的值_实战PyQt5: 060-输入对话框QInputDialog
  5. wait、notify、notifyAll和Condition
  6. LeetCode Longest Increasing Subsequence
  7. 解决NetworkOnMainThreadException
  8. JS实现页面字体繁简转换
  9. SAP 生产订单创建修改日期
  10. 李彦宏高中全国计算机比赛,中国互联网“男神”李彦宏学生时代的那些事
  11. from __future__ imports must occur at the beginning of the file问题的解决
  12. 网络信息检索(五)查询处理:查询方式+查询操作
  13. 微服务化小团队:让 GitLab、Jenkins 与 Sonar 碰撞出火花
  14. 2020年Java就业前景和就业方向分析!
  15. 宅家神器—epub阅读器
  16. 第五章:数学运算-fractions:有理数-创建Fraction实例
  17. Springmvc开发流程(入门)
  18. 学校人脸识别门禁系统的意义
  19. C++ Primer Plus第六版第六章编程练习 第4题, 加入Benevolent Order of Programmer后,在BOP大会上
  20. hp计算机如何进入启动界面,BIOS使用之HP BIOS篇-惠普电脑怎么进入bios

热门文章

  1. leetcode24题:两两交换链表的节点
  2. SQL Server 创建表
  3. 如何使用IntelliJ IDEA搭建spark开发环境(上)
  4. UnhandledPromiseRejectionWarning报错send()的处理
  5. java 创建线程_java多线程|创建线程的各种方式
  6. linux下最好的ftp服务器,用Linux系统构建高效FTP服务器
  7. android 透明主题 crash,Android 8.0 的填坑(透明的activity崩溃)
  8. php mysql encode_PHP json_encode mysql结果
  9. android 手机铃声设置铃声设置,Android 修改系统来电铃声
  10. videojs重播_vue2.0 vue-video-player 直播hls 回放mp4