Linux Kernel CMPXCHG函数分析
原文地址:http://blog.csdn.net/penngrove/article/details/44175387
最近看到Linux Kernel cmpxchg的代码,对实现很不理解。上网查了内嵌汇编以及Intel开发文档,才慢慢理解了,记录下来以享和我一样困惑的开发者。其实cmpxchg实现的原子操作原理早已被熟知:
cmpxchg(void* ptr, int old, int new),如果ptr和old的值一样,则把new写到ptr内存,否则返回ptr的值,整个操作是原子的。在Intel平台下,会用lock cmpxchg来实现,这里的lock个人理解是锁住内存总线,这样如果有另一个线程想访问ptr的内存,就会被block住。
好了,让我们来看Linux Kernel中的cmpxchg(网上找来的,我自己机器上没找到对应的头文件,据说在include/asm-i386/cmpxchg.h)实现:
01./* TODO: You should use modern GCC atomic instruction builtins instead of this. */
02.#include <stdint.h>
03.#define cmpxchg( ptr, _old, _new ) { \
04. volatile uint32_t *__ptr = (volatile uint32_t *)(ptr); \
05. uint32_t __ret; \
06. asm volatile( "lock; cmpxchgl %2,%1" \
07. : "=a" (__ret), "+m" (*__ptr) \
08. : "r" (_new), "0" (_old) \
09. : "memory"); \
10. ); \
11. __ret; \
12.}
/* TODO: You should use modern GCC atomic instruction builtins instead of this. */
#include <stdint.h>
#define cmpxchg( ptr, _old, _new ) { \
volatile uint32_t *__ptr = (volatile uint32_t *)(ptr); \
uint32_t __ret; \
asm volatile( "lock; cmpxchgl %2,%1" \
: "=a" (__ret), "+m" (*__ptr) \
: "r" (_new), "0" (_old) \
: "memory"); \
); \
__ret; \
}
主要要看懂内嵌汇编,c的内嵌汇编格式是
01.asm ( assembler template
02. : output operands (optional)
03. : input operands (optional)
04. : clobbered registers list (optional)
05. );
asm ( assembler template
: output operands (optional)
: input operands (optional)
: clobbered registers list (optional)
);
output operands和inpupt operands指定参数,它们从左到右依次排列,用','分割,编号从0开始。以cmpxchg汇编为例,(__ret)对应0,(*__ptr)对应1,(_new)对应2,(_old)对应3,如果在汇编中用到"%2",那么就是指代_new,"%1"指代(*__ptr)。
"=a"是说要把结果写到__ret中,而且要使用eax寄存器,所以最后写结果的时候是的操作是mov eax, ret (eax==>__ret)。"r" (_new)是要把_new的值读到一个通用寄存器中使用。
在cmpxchg中,注意"0"(_old),这个是困惑我的地方,它像告诉你(_old)和第0号操作数使用相同的寄存器或者内存,即(_old)的存储在和0号操作数一样的地方。在cmpxchg中,就是说_old和__ret使用一样的寄存器,而__ret使用的寄存器是eax,所以_old也用eax。
明白了这些,再来看cmpxchgl,在Intel开发文档上说:
0F B1/r CMPXCHG r/m32, r32 MR Valid Valid* Compare EAX with r/m32. If equal, ZF is set
and r32 is loaded into r/m32. Else, clear ZF
and load r/m32 into EAX.
翻译一下:
比较eax和目的操作数(第一个操作数)的值,如果相同,ZF标志被设置,同时源操作数(第二个操作)的值被写到目的操作数,否则,清ZF标志,并且把目的操作数的值写回eax。
好了,把上面这句话套在cmpxchg上就是:
比较_old和(*__ptr)的值,如果相同,ZF标志被设置,同时_new的值被写到(*__ptr),否则,清ZF标志,并且把(*__ptr)的值写回_old。
很明显,符合我们对cmpxchg的理解。
另:Intel开发手册上说lock就是让CPU排他地使用内存。
Linux Kernel CMPXCHG函数分析的更多相关文章
- Linux kernel workqueue机制分析
Linux kernel workqueue机制分析 在内核编程中,workqueue机制是最常用的异步处理方式.本文主要基于linux kernel 3.10.108的workqueue文档分析其基 ...
- Linux Kernel‘ieee80211_radiotap_iterator_init()’函数拒绝服务漏洞
漏洞名称: Linux Kernel‘ieee80211_radiotap_iterator_init()’函数拒绝服务漏洞 CNNVD编号: CNNVD-201312-041 发布时间: 2013- ...
- Linux kernel ‘qeth_snmp_command’函数缓冲区溢出漏洞
漏洞名称: Linux kernel ‘qeth_snmp_command’函数缓冲区溢出漏洞 CNNVD编号: CNNVD-201311-423 发布时间: 2013-11-29 更新时间: 201 ...
- Linux kernel ‘aac_send_raw_srb’函数输入验证漏洞
漏洞名称: Linux kernel ‘aac_send_raw_srb’函数输入验证漏洞 CNNVD编号: CNNVD-201311-422 发布时间: 2013-11-29 更新时间: 2013- ...
- Linux kernel ‘lbs_debugfs_write’函数数字错误漏洞
漏洞名称: Linux kernel ‘lbs_debugfs_write’函数数字错误漏洞 CNNVD编号: CNNVD-201311-421 发布时间: 2013-11-29 更新时间: 2013 ...
- Linux kernel ‘xfs_attrlist_by_handle()’函数缓冲区溢出漏洞
漏洞名称: Linux kernel ‘xfs_attrlist_by_handle()’函数缓冲区溢出漏洞 CNNVD编号: CNNVD-201311-392 发布时间: 2013-11-29 更新 ...
- Linux kernel ‘uio_mmap_physical’函数缓冲区溢出漏洞
漏洞名称: Linux kernel ‘uio_mmap_physical’函数缓冲区溢出漏洞 CNNVD编号: CNNVD-201311-154 发布时间: 2013-11-13 更新时间: 201 ...
- Linux Kernel ‘write_tag_3_packet()’函数本地基于堆的缓冲区溢出漏洞
漏洞名称: Linux Kernel ‘write_tag_3_packet()’函数本地基于堆的缓冲区溢出漏洞 CNNVD编号: CNNVD-201311-067 发布时间: 2013-11-07 ...
- Linux Kernel ‘exitcode_proc_write()’函数本地缓冲区溢出漏洞
漏洞名称: Linux Kernel ‘exitcode_proc_write()’函数本地缓冲区溢出漏洞 CNNVD编号: CNNVD-201311-061 发布时间: 2013-11-07 更新时 ...
随机推荐
- 【转载】MySQL索引原理及慢查询优化
原文链接:美团点评技术团队:http://tech.meituan.com/mysql-index.html MySQL凭借着出色的性能.低廉的成本.丰富的资源,已经成为绝大多数互联网公司的首选关系型 ...
- BZOJ: 1084: [SCOI2005]最大子矩阵
NICE 的DP 题,明白了题解真是不错. Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1228 Solved: 622[Submit][Stat ...
- 一道PK赛题
Problem Description I think that you might have played the traditional Chinese ring game: The Chines ...
- console中一些不常用的实用方法
console.group('分组1'); console.table( [ {key1: 1,key2: 2,key3: 3}, {key1: 1,key2: 2,key3: 3}, {key1: ...
- SWF Web播放器
<HTML> <HEAD> <!-- saved from url=(0013)about:internet --> <TITLE> Untitled. ...
- POJ 2021
#include <iostream> #include <string> #include <algorithm> #define MAXN 105 using ...
- HDU 1385 Minimum Transport Cost (Dijstra 最短路)
Minimum Transport Cost http://acm.hdu.edu.cn/showproblem.php?pid=1385 Problem Description These are ...
- linux查看硬件信息及驱动设备相关整理
查看声卡设备:cat /proc/asound/cards 查看USB设备:cat /proc/bus/usb/devices 常用命令整理如下:用硬件检测程序kuduz探测新硬件:service k ...
- Visual Studio 项目中添加include, lib, dll库文件(*.h,*.lib,*.dll)
应用程序使用外部库时需要进行加载,两种库的加载本质上都是一样:提供功能和功能的定义.vs2005 c++ 项目设置外部库方法如下: 1. 添加编译所需要(依赖)的 lib 文件 在“项目-&g ...
- ZOJ 1610 Count the Colors (线段树区间更新)
题目链接 题意 : 一根木棍,长8000,然后分别在不同的区间涂上不同的颜色,问你最后能够看到多少颜色,然后每个颜色有多少段,颜色大小从头到尾输出. 思路 :线段树区间更新一下,然后标记一下,最后从头 ...