Nginx 是多进程模式的,一个 master 与多个 workers,一般工作在多核 CPU 上,所以自旋锁就是必须用到的。Nginx 中的自旋锁的定义,位于 ngx_spinlock.c 中,如下:

void
ngx_spinlock(ngx_atomic_t *lock, ngx_atomic_int_t value, ngx_uint_t spin)
{ #if (NGX_HAVE_ATOMIC_OPS) ngx_uint_t i, n; for ( ;; ) { // lock 即为锁,是一个整数
// ngx_atomic_cmp_set 是平台相关的,一般都涉及内联汇编
if (*lock == 0 && ngx_atomic_cmp_set(lock, 0, value)) {
return;
} // 多核
if (ngx_ncpu > 1) { // 等待与重试策略,见下面的描述
for (n = 1; n < spin; n <<= 1) { for (i = 0; i < n; i++) {
ngx_cpu_pause();
} if (*lock == 0 && ngx_atomic_cmp_set(lock, 0, value)) {
return;
}
}
} ngx_sched_yield();
} #else #if (NGX_THREADS) #error ngx_spinlock() or ngx_atomic_cmp_set() are not defined ! #endif #endif }

其中用 lock 这个整形变量表示锁,在笔者的机器(Darwin 12.0)上,是如下定义的:

typedef volatile ngx_atomic_uint_t  ngx_atomic_t;

再 回到上面 spinlock 的源码分析中,如果 ngx_ncpu(表示 CPU 的核心数)超过 1 个,即多核 CPU,则要等待/重试。举个例子,如果 spin 为 80,则第一次等待 1 个 ngx_cpu_pause() 操作,然后再次查看锁是否可用。接下来每轮分别等待 2个、4 个、8 个、16 个、32 个、64 个 ngx_cpu_pause() 操作后再试。这中间过程中如果出现锁被释放从而可以使用的情况,则循环会被中止,spinlock 函数会返回值。如果重试仍没有成功,则执行 ngx_sched_yield,然后再重复上面的操作。

另外其中的 ngx_atomic_cmp_set 函数也很有探讨价值。在 Darwin 12.0 上面是如下的宏定义:

#define ngx_atomic_cmp_set(lock, old, new)                                    \
OSAtomicCompareAndSwap64Barrier(old, new, (int64_t *) lock)

在我一位朋友的 Linux 环境(具体忘记了,但是 x86),如下。其中的内联汇编可以参考本博客内的 GCC 内联汇编的两篇博文。其中的 SMP 为总线锁。

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

这里输出为 res,保存在 eax 寄存器中。输入为 *lock(内存中)、old(eax中)、set(r 表示通用寄存器)。这样 %0 就是 res,%1 就是 *lock,%2 就是 old,%3 就是 set。

如 果 *lock 和 old 相等,则异或(cmpxchgl)为 0,则 ZF 为 1,sete 将 res(%0)的值设置为 1 并返回它。如果 *lock 和 old 不相等,则异火值非零,所以 ZF 非零,则 sete 不会执行动作,即 res 值为 0,即调用 ngx_atomic_cmp_set 失败。

cmpxchgl 会影响 ZF(Zero Flag)标志位。

Nginx 源码完全注释(11)ngx_spinlock的更多相关文章

  1. Nginx源码完全注释(6)core/murmurhash

    下面是摘自 Google Code 的 Murmurhash 开源项目主页上的 Murmurhash2,Nginx 就是采用的这个. uint32_t MurmurHash2 ( const void ...

  2. Nginx 源码完全注释(10)ngx_radix_tree

    ngx_radix_tree.h // 未被使用的节点 #define NGX_RADIX_NO_VALUE (uintptr_t) -1 typedef struct ngx_radix_node_ ...

  3. Nginx源码完全注释(5)core/ngx_cpuinfo.c

    /* * Copyright (C) Igor Sysoev * Copyright (C) Nginx, Inc. */ #include <ngx_config.h> #include ...

  4. Nginx源码完全注释(9)nginx.c: ngx_get_options

    本文分析 ngxin.c 中的 ngx_get_options 函数,其影响: nginx.c 中的: static ngx_uint_t ngx_show_help; static ngx_uint ...

  5. Nginx源码完全注释(8)ngx_errno.c

    errno.h中的strerror(int errno)可以确定指定的errno的错误的提示信息.在 Nginx 中,将所有错误提示信息预先存储在一个数组里,而预先确定这个数组的大小,是在自动化脚本中 ...

  6. Nginx源码完全注释(2)ngx_array.h / ngx_array.c

    数组头文件 ngx_array.h #include <ngx_config.h> #include <ngx_core.h> struct ngx_array_s { voi ...

  7. nginx源码完全注释(1)ngx_alloc.h / ngx_alloc.c

    首先看 ngx_alloc.h 文件,主要声明或宏定义了 ngx_alloc,ngx_calloc,ngx_memalign,ngx_free. /* * Copyright (C) Igor Sys ...

  8. Nginx源码完全注释(7)ngx_palloc.h/ngx_palloc.c

    ngx_palloc.h /* * NGX_MAX_ALLOC_FROM_POOL should be (ngx_pagesize - 1), i.e. 4095 on x86. * On Windo ...

  9. Nginx源码完全注释(4)ngx_queue.h / ngx_queue.c

    队列头文件ngx_queue.h #include <ngx_config.h> #include <ngx_core.h> #ifndef _NGX_QUEUE_H_INCL ...

随机推荐

  1. IDEA使用介绍

    https://blog.csdn.net/qq_27093465/article/details/77449117

  2. 如何查看你的 FastAdmin 服务器是否开启了 gzip br 压缩

    如何查看你的 FastAdmin 服务器是否开启了 gzip 压缩 gzip br 压缩的好处不用多说了. 但是怎么方便的知道网站到底有没有开启或使用了 gzip 呢,其实只要在浏览器就可以看到. 按 ...

  3. 【转】Linux 静态库与共享库的使用

    原文网址:http://blog.csdn.net/heyabo/article/details/11688517 申明: 正如题如示,本篇讲的是Linux下是静态库与共享库,而Window下的动态链 ...

  4. Docker安装ShowDoc

    ShowDoc就是一个非常适合IT团队的在线文档分享工具,它可以加快团队之间沟通的效率. 一.下载showDoc资源 打开 https://github.com/star7th/showdoc 复制其 ...

  5. 安装Zookeeper(单机版)

    一.解压和重命名 tar -zxvf zookeeper-3.4.8.tar.gz -C /usr/ cd /usr mv zookeeper-3.4.8 zookeeper 二.设置配置文件 cd ...

  6. 常见企业IT支撑【3、SVN代码版本控制系统】

    代码版本控制系统有人喜欢用SVN,有人喜欢用GIT     1.环境   os:centos7 apache:2.4.6 python:2.7  --自带 submin2:2.2.1   2.安装ap ...

  7. FPGA时序优化简单窍门

    尽量用硬核,比如硬件乘法器,这个应该都知道. 结构上的pipeline,简言之就是“拆",最极端的情形是拆到源和目的Reg间只有基本的组合逻辑门,比如说~a & b之类...:当然F ...

  8. (转)Inno Setup入门(十二)——Pascal脚本(1)

    本文转载自:http://blog.csdn.net/yushanddddfenghailin/article/details/17250917 事件函数(1) Inno Setup支持以下函数和过程 ...

  9. common-lang3-version.jar 提供java.lang的扩展功能

    Apache Commons Lang 3.6 API

  10. 【POJ】3616 Milking Time(dp)

    Milking Time Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 10898   Accepted: 4591 Des ...