Ubuntu 下 nginx-1.24.0 源码分析 - ngx_atomic_cmp_set 函数
目录
修正
执行
./configure命令时,输出:
checking for OS
+ Linux 6.8.0-52-generic x86_64
checking for C compiler ... found
+ using GNU C compiler
+ gcc version: 11.4.0 (Ubuntu 11.4.0-1ubuntu1~22.04)
所以当前环境是 x86_64
于是在 src\os\unix\ngx_atomic.h 中
#include "ngx_gcc_atomic_x86.h"被包含
src/os/unix/ngx_gcc_atomic_x86.h 中:
static ngx_inline ngx_atomic_uint_t ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old,ngx_atomic_uint_t set) {u_char res;__asm__ volatile (NGX_SMP_LOCK" cmpxchgl %3, %1; "" sete %0; ": "=a" (res) : "m" (*lock), "a" (old), "r" (set) : "cc", "memory");return res; }函数功能:
原子地比较
*lock的值是否等于old:若相等:将
*lock设置为set,并返回1(成功)若不相等:不修改
*lock,返回0(失败)
内联汇编实现
NGX_SMP_LOCK宏定义,在多核(SMP)系统中扩展为
lock前缀,确保指令的原子性;单核系统中可能为空
cmpxchgl %3, %1x86 的原子比较并交换指令:
- 比较
%1(即*lock)与eax寄存器(隐含使用,值为old)- 若相等,将
%3(即set)写入*lock;否则,将*lock的值加载到eax
sete %0根据
cmpxchgl结果(ZF 标志位)设置res为0或1输入输出约束
输出
"=a" (res):结果res通过eax寄存器返回输入
"m" (*lock), "a" (old), "r" (set):
*lock作为内存操作数
old存入eax(隐含用于cmpxchgl的比较)
set存入通用寄存器
"cc", "memory":告知编译器条件寄存器和内存可能被修改
内联汇编语法
操作数占位符
%0, %1, %2, %3:按操作数出现顺序编号:
%0→"=a" (res)(输出)%1→"m" (*lock)(输入)%2→"a" (old)(输入)%3→"r" (set)(输入)操作数约束(Constraints)
输出操作数
"=a" (res)
=:表示只写(输出)。a:使用eax寄存器。res:C变量,接收结果(0或1)
"m" (*lock)
m:内存操作数,直接操作*lock的内存地址
"a" (old)
a:将old的值存入eax寄存器(cmpxchgl隐式使用eax进行比较)。
"r" (set)
r:将set的值存入任意通用寄存器(如ebx、ecx等)。Clobber列表
"cc":表示指令修改了标志寄存器(如 ZF、CF)。"memory":表示指令可能修改内存,强制编译器刷新内存缓存。cmpxchgl 源操作数, 目标操作数
比较
目标操作数(即*lock)与eax的值(old)。若相等:
将
源操作数(即set)写入目标操作数(*lock)。设置 ZF(Zero Flag)为 1。
若不相等:
将
目标操作数(*lock)的值加载到eax。设置 ZF 为 0。
sete %0
sete:若 ZF=1(即比较成功),将目标(%0,即res)设为 1,否则设为 0。- 由于
%0约束为"=a",结果通过eax写入res。
执行流程
将
old加载到eax。原子比较
*lock与eax:相等 → 将
set写入*lock,ZF=1。不等 → 将
*lock值加载到eax,ZF=0。根据 ZF 设置
res(1 或 0)。返回
res。
意图
实现原子操作
通过cmpxchgl指令和lock前缀,确保在多核环境下的原子性,避免竞态条件。跨平台兼容性
使用
NGX_SMP_LOCK宏适配不同平台(如单核无需lock前缀)
NGX_SMP_LOCK在 src\os\unix\ngx_gcc_atomic_x86.h
#if (NGX_SMP) #define NGX_SMP_LOCK "lock;" #else #define NGX_SMP_LOCK #endif
objs/ngx_auto_config.h 中
#ifndef NGX_SMP #define NGX_SMP 1 #endif
所以
NGX_SMP_LOCK 是 "lock;"
- 无
lock:cmpxchgl本身是原子的,但仅限单核环境。- 有
lock:确保多核环境下的原子性,完整执行“比较-交换”操作。
修正
以上部分 可能是错误的
在 src\os\unix\ngx_atomic.h 中:
#define ngx_trylock(lock) (*(lock) == 0 && ngx_atomic_cmp_set(lock, 0, 1))这样定义了 ngx_trylock
但对于 ngx_atomic_cmp_set 的定义可能判断错了
在 我的Ubuntu 环境中
objs/ngx_auto_config.h:9:#define NGX_HAVE_GCC_ATOMIC 1
也就是在 objs/ngx_auto_config.h 中
定义了
#ifndef NGX_HAVE_GCC_ATOMIC #define NGX_HAVE_GCC_ATOMIC 1 #endif在 ngx_atomic.h 中
#if (NGX_HAVE_LIBATOMIC) 省略 #elif (NGX_HAVE_GCC_ATOMIC) 省略 #define ngx_atomic_cmp_set(lock, old, set) \__sync_bool_compare_and_swap(lock, old, set)#elif (NGX_HAVE_GCC_ATOMIC) 条件成立
所以 ngx_atomic_cmp_set 的定义应该是:
#define ngx_atomic_cmp_set(lock, old, set) \__sync_bool_compare_and_swap(lock, old, set)在Ubuntu的x86_64架构下,
NGX_HAVE_GCC_ATOMIC会被定义ngx_atomic_cmp_set 在支持GCC原子内置函数的情况下,这个函数应该会被定义为上述情况
__sync_bool_compare_and_swap是 GCC 提供的一个内置原子操作函数,用于实现多线程环境下的无锁同步。其作用是在原子操作中比较并交换(Compare-and-Swap, CAS)一个值,常用于实现线程安全的操作。
函数原型
bool __sync_bool_compare_and_swap(type *ptr, type oldval, type newval);
- 参数:
ptr:指向需要操作的内存地址的指针。oldval:期望的旧值。newval:要设置的新值。- 返回值:
- 如果
*ptr的当前值等于oldval,则将*ptr设置为newval,并返回true。- 否则不修改内存,返回
false。底层原理
该函数依赖硬件级别的原子指令(如 x86 的
CMPXCHG指令)实现,确保多线程环境下操作的原子性函数由 GCC 编译器直接提供,无需像标准库函数(如
printf)那样通过#include引入头文件。直接在代码中调用即可
gcc -E
鉴于有时预编译指令较多且嵌套,难以判断具体使用的哪一个定义
于是改用
gcc -E 的方法
- 作用:运行 GCC 的 预处理阶段,处理以下内容:
- 展开
#include引入的头文件。- 替换
#define定义的宏。- 处理
#ifdef/#if等条件编译指令。- 删除注释。
- 输出:预处理后的纯 C 代码(未编译)。
gcc -E src/core/ngx_times.c \-I src/core \-I src/event \-I src/event/modules \-I src/os/unix \-I objs \> ngx_times_preprocessed.c-I 添加头文件搜索路径
> ngx_times_preprocessed.c
- 作用:将预处理结果重定向到文件
ngx_times_preprocessed.c- 文件内容:展开后的完整代码
找到原本 ngx_times.c中void ngx_time_update(void) {u_char *p0, *p1, *p2, *p3, *p4;ngx_tm_t tm, gmt;time_t sec;ngx_uint_t msec;ngx_time_t *tp;struct timeval tv;if (!ngx_trylock(&ngx_time_lock)) {return;}ngx_time_update 函数中,struct timeval tv; 后,ngx_trylock 调用的地方
在
ngx_times_preprocessed.c 中的位置if (!(*(&ngx_time_lock) == 0 && __sync_bool_compare_and_swap(&ngx_time_lock, 0, 1))) {return;}这里是展开后的样子
所以 确认是 调用了
__sync_bool_compare_and_swap
相关文章:
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_atomic_cmp_set 函数
目录 修正 执行 ./configure 命令时,输出: checking for OS Linux 6.8.0-52-generic x86_64 checking for C compiler ... found using GNU C compiler gcc version: 11.4.0 (Ubuntu 11.4.0-1ubuntu1~22.04) 所以当前环境是 x86_64 于是在 src…...
CNN-BiLSTM卷积神经网络双向长短期记忆神经网络多变量多步预测,光伏功率预测
代码地址:CNN-BiLSTM卷积神经网络双向长短期记忆神经网络多变量多步预测,光伏功率预测 CNN-BiLSTM卷积神经网络双向长短期记忆神经网络多变量多步预测 一、引言 1.1、研究背景和意义 光伏功率预测在现代电力系统中占有至关重要的地位。随着可再生能源…...
【YOLO系列】YOLOv5 NMS源码理解、更换为DIoU-NMS
代码来源:GitHub - ultralytics/yolov5: YOLOv5 🚀 in PyTorch > ONNX > CoreML > TFLite 使用的代码是YOLOv5 6.1版本 参考笔记:YOLOv5改进系列(八) 更换NMS非极大抑制DIoU-NMS、CIoU-NMS、EIoU-NMS、GIoU-NMS 、SIoU-NMS、Soft-…...
Android RenderEffect对Bitmap高斯模糊(毛玻璃),Kotlin(1)
Android RenderEffect对Bitmap高斯模糊(毛玻璃),Kotlin(1) import android.graphics.Bitmap import android.graphics.BitmapFactory import android.graphics.HardwareRenderer import android.graphics.PixelFormat import android.graphic…...
【linux学习指南】线程同步与互斥
文章目录 📝线程互斥🌠 库函数strncpy🌉进程线程间的互斥相关背景概念🌉互斥量mutex 🌠线程同步🌉条件变量🌉同步概念与竞态条件🌉 条件变量函数 🚩总结 📝线…...
JavaScript函数与方法详解
目录 一、函数的定义 1. 函数声明 2. 函数表达式 3. 箭头函数 二、函数的调用 1. 调用方式 2. 参数数量的灵活性 三、arguments 对象 1. 基本概念 2. 属性 3. 应用场景 4. 转换为真数组 5. 总结 四、Rest参数 1. 基本概念 2. 特点 3. 应用场景 4. 总结 五、变…...
【论文笔记】ZeroGS:扩展Spann3R+GS+pose估计
spann3r是利用dust3r做了增量式的点云重建,这里zeroGS在前者的基础上,进行了增量式的GS重建以及进行了pose的联合优化,这是一篇dust3r与GS结合的具有启发意义的工作。 abstract NeRF和3DGS是重建和渲染逼真图像的流行技术。然而,…...
AtCoder - arc058_d Iroha Loves Strings解答与注意事项
链接:Iroha Loves Strings - AtCoder arc058_d - Virtual Judge 利用bitset这一数据结构,定义bitset类型的变量dp[i]表示第i到n个字符串能拼成的字符串长度都有哪些,比如00100101,表示能拼成的长度有0,2,5,࿰…...
企业使用统一终端管理(UEM)工具提高端点安全性
什么是统一终端管理(UEM) 统一终端管理(UEM)是一种从单个控制台管理和保护企业中所有端点的方法,包括智能手机、平板电脑、笔记本电脑、台式机和 IoT设备。UEM 解决方案为 IT 管理员提供了一个集中式平台,用于跨所有作系统和设备类型部署、配置、管理和…...
Leetcode 算法题 9 回文数
起因, 目的: 数学法。 % 求余数, 拆开组合,组合拆开。 这个题,翻来覆去,拆开组合, 组合拆开。构建的过程。 题目来源,9 回文数: https://leetcode.cn/problems/palindrome-number…...
设计模式Python版 命令模式(上)
文章目录 前言一、命令模式二、命令模式示例 前言 GOF设计模式分三大类: 创建型模式:关注对象的创建过程,包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式和建造者模式。结构型模式:关注类和对象之间的组合&…...
C语言之循环结构:直到型循环
C语言 循环结构 直到型循环的实现 特点:先执行,后判断,不管条件是否满足,至少执行一次。典型代表:do…while,goto(已淘汰,不推荐使用) do…while 语法: d…...
细说STM32F407单片机RTC的备份寄存器原理及使用方法
目录 一、备份寄存器的功能 二、示例功能 三、项目设置 1、晶振、DEBUG、CodeGenerator、USART6 2、RTC 3、NVIC 4、GPIO 及KEYLED 四、软件设计 1、main.h 2、main.c 3、rtc.c 4、keyled.c、keyled.h 五、运行调试 本实例旨在介绍备份寄存器的作用。本实例继续使…...
MATLAB计算反映热需求和能源消耗的度数日指标(HDD+CDD)(全代码)
目录 度数日(Degree Days, DD)概述计算公式MATLAB计算代码调用函数1:计算单站点的 CDD参考度数日(Degree Days, DD)概述 度数日(Degree Days, DD)是用于衡量建筑、城市和地区的热需求和能源消耗模式的指标。它分为两部分: 加热度日(Heating Degree Days, HDD):当室…...
J6 X8B/X3C切换HDR各帧图像
1、OV手册上的切换命令 寄存器为Ox5074 各帧切换: 2、地平线control tool实现切换命令 默认HDR模式出图: HCG出图: LCG出图 SPD出图 VS出图...
09-轮转数组
给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。 方法一:使用额外数组 function rotate(nums: number[], k: number): void {const n nums.length;k k % n; // 处理 k 大于数组长度的情况const newNums new A…...
用vue3写一个好看的wiki前端页面
以下是一个使用 Vue 3 Element Plus 实现的 Wiki 风格前端页面示例,包含现代设计、响应式布局和常用功能: <template><div class"wiki-container"><!-- 头部导航 --><el-header class"wiki-header"><d…...
瑞芯微烧写工具
文章目录 前言一、安装驱动二、安装烧写工具1.直接解压压缩包2. 如何使用 三、MASKROM 裸机必备四、LOADER 烧写,前提是搞过第三步没问题五、Update.img包的烧录六、linux下烧写总结 前言 提示:这里可以添加本文要记录的大概内容: 项目需要…...
说下JVM中一次完整的GC流程?
大家好,我是锋哥。今天分享关于【说下JVM中一次完整的GC流程?】面试题。希望对大家有帮助; 说下JVM中一次完整的GC流程? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 JVM中的一次完整的垃圾回收(GC)流程可以概括为…...
Open FPV VTX开源之OSD使用分类
Open FPV VTX开源之OSD使用分类 1. 源由2. 硬件2.1 【天空端】SigmaStar2.2 【天空端】Raspberry Pi2.3 【地面端】 3. 软件3.1 天空端软件3.2 地面端软件 4. 分类4.1 嵌入式OSD分类A1-嵌入式OSD:SigmaStar Android分类A2-嵌入式OSD:SigmaStar Hi3536分…...
基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...
零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...
脑机新手指南(七):OpenBCI_GUI:从环境搭建到数据可视化(上)
一、OpenBCI_GUI 项目概述 (一)项目背景与目标 OpenBCI 是一个开源的脑电信号采集硬件平台,其配套的 OpenBCI_GUI 则是专为该硬件设计的图形化界面工具。对于研究人员、开发者和学生而言,首次接触 OpenBCI 设备时,往…...
Unity VR/MR开发-VR开发与传统3D开发的差异
视频讲解链接:【XR马斯维】VR/MR开发与传统3D开发的差异【UnityVR/MR开发教程--入门】_哔哩哔哩_bilibili...
LUA+Reids实现库存秒杀预扣减 记录流水 以及自己的思考
目录 lua脚本 记录流水 记录流水的作用 流水什么时候删除 我们在做库存扣减的时候,显示基于Lua脚本和Redis实现的预扣减 这样可以在秒杀扣减的时候保证操作的原子性和高效性 lua脚本 // ... 已有代码 ...Overridepublic InventoryResponse decrease(Inventor…...
