1. 程式人生 > >Nginx原始碼閱讀(IPC)

Nginx原始碼閱讀(IPC)

共享記憶體

/* src/os/unix/ngx_shmem.h */

typedef struct {
    u_char      *addr; // 地址
    size_t       size; // 長度
    ngx_str_t    name; // 名稱
    ngx_log_t   *log;
    ngx_uint_t   exists;   /* unsigned  exists:1;  */
} ngx_shm_t;
/* src/os/unix/ngx_shmem.c */

ngx_int_t
ngx_shm_alloc(ngx_shm_t *shm)
{
    // 匿名記憶體對映
shm->addr = (u_char *) mmap(NULL, shm->size, PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0); if (shm->addr == MAP_FAILED) { ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, "mmap(MAP_ANON|MAP_SHARED, %uz) failed"
, shm->size); return NGX_ERROR; } return NGX_OK; } void ngx_shm_free(ngx_shm_t *shm) { // 刪除對映關係 if (munmap((void *) shm->addr, shm->size) == -1) { ngx_log_error(NGX_LOG_ALERT, shm->log, ngx_errno, "munmap(%p, %uz) failed", shm->addr, shm->
size); } }

原子操作

不支援原子庫下的原子操作

/* src/os/unix/ngx_atomic.h */

typedef uint32_t                    ngx_atomic_uint_t;
typedef volatile ngx_atomic_uint_t  ngx_atomic_t;

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)
{
    if (*lock == old) {
        *lock = set;
        return 1;
    }

    return 0;
}


static ngx_inline ngx_atomic_int_t
ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add)
{
    ngx_atomic_int_t  old;

    old = *value;
    *value += add;

    return old;
}

x86架構下的原子操作

/* src/os/unix/ngx_gcc_atomic_x86.h */

#if (NGX_SMP)
#define NGX_SMP_LOCK  "lock;"
#else
#define NGX_SMP_LOCK
#endif


/*
 * "cmpxchgl  r, [m]":
 *
 *     if (eax == [m]) {
 *         zf = 1;
 *         [m] = r;
 *     } else {
 *         zf = 0;
 *         eax = [m];
 *     }
 *
 *
 * The "r" means the general register.
 * The "=a" and "a" are the %eax register.
 * Although we can return result in any register, we use "a" because it is
 * used in cmpxchgl anyway.  The result is actually in %al but not in %eax,
 * however, as the code is inlined gcc can test %al as well as %eax,
 * and icc adds "movzbl %al, %eax" by itself.
 *
 * The "cc" means that flags were changed.
 */

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


/*
 * "xaddl  r, [m]":
 *
 *     temp = [m];
 *     [m] += r;
 *     r = temp;
 *
 *
 * The "+r" means the general register.
 * The "cc" means that flags were changed.
 */


#if !(( __GNUC__ == 2 && __GNUC_MINOR__ <= 7 ) || ( __INTEL_COMPILER >= 800 ))

/*
 * icc 8.1 and 9.0 compile broken code with -march=pentium4 option:
 * ngx_atomic_fetch_add() always return the input "add" value,
 * so we use the gcc 2.7 version.
 *
 * icc 8.1 and 9.0 with -march=pentiumpro option or icc 7.1 compile
 * correct code.
 */

static ngx_inline ngx_atomic_int_t
ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add)
{
    __asm__ volatile (

         NGX_SMP_LOCK
    "    xaddl  %0, %1;   "

    : "+r" (add) : "m" (*value) : "cc", "memory");

    return add;
}


#else

/*
 * gcc 2.7 does not support "+r", so we have to use the fixed
 * %eax ("=a" and "a") and this adds two superfluous instructions in the end
 * of code, something like this: "mov %eax, %edx / mov %edx, %eax".
 */

static ngx_inline ngx_atomic_int_t
ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add)
{
    ngx_atomic_uint_t  old;

    __asm__ volatile (

         NGX_SMP_LOCK
    "    xaddl  %2, %1;   "

    : "=a" (old) : "m" (*value), "a" (add) : "cc", "memory");

    return old;
}

#endif

自旋鎖

/* src/core/ngx_spinlock.c */

void
ngx_spinlock(ngx_atomic_t *lock, ngx_atomic_int_t value, ngx_uint_t spin)
{
    ngx_uint_t  i, n;

    for ( ;; ) {

        // lock為0表示鎖是釋放的,lock不為0表示鎖是被某個程序持有的
        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;
                }
            }
        }

        /* #if (NGX_HAVE_SCHED_YIELD)
           // sched_yield的定義:http://www.man7.org/linux/man-pages/man2/sched_yield.2.html
           #define ngx_sched_yield()  sched_yield()
           #else
           #define ngx_sched_yield()  usleep(1)
           #endif */
        ngx_sched_yield(); // 讓出CPU
    }
}

相關推薦

Nginx原始碼閱讀IPC

共享記憶體 /* src/os/unix/ngx_shmem.h */ typedef struct { u_char *addr; // 地址 size_t size; // 長度 ngx_str_t

Nginx原始碼閱讀ngx_http_process_request_line

ngx_http_process_request_line() static void ngx_http_process_request_line(ngx_event_t *rev) {     ssize_t              n;     ngx_int_t  

Nginx原始碼閱讀模組

每個nginx模組,都是一個ngx_module_t型別的變數。根據ngx_module_t的type,所有nginx模組可以分為5種類型: type ctx指向的資料結構 commands指向的資料結構 具體模組 NGX_CO

Nginx原始碼閱讀main

main()執行流程 main()程式碼解析 /* src/core/nginx.c */ int ngx_cdecl // #define ngx_cdecl,一個空的define,跨平臺支援 main(int argc, char *con

【筆記】ThreadPoolExecutor原始碼閱讀

執行緒數量的維護 執行緒池的大小有兩個重要的引數,一個是corePoolSize(核心執行緒池大小),另一個是maximumPoolSize(最大執行緒大小)。執行緒池主要根據這兩個引數對執行緒池中執行緒的數量進行維護。 需要注意的是,執行緒池建立之初是沒有任何可用執行緒的。只有在有任務到達後,才開始建立

## Zookeeper原始碼閱讀 Watcher

前言 好久沒有更新部落格了,最近這段時間過得很壓抑,終於開始踏上為換工作準備的正軌了,工作又真的很忙而且很瑣碎,讓自己有點煩惱,希望能早點結束這種狀態。 繼上次分析了ZK的ACL相關程式碼後,ZK裡非常重要的另一個特性就是Watcher機制了。其實在我看來,就ZK的使用而言,Watche機制是最核心的特性

Zookeeper原始碼閱讀 Server端Watcher

前言 前面一篇主要介紹了Watcher介面相關的介面和實體類,但是主要是zk客戶端相關的程式碼,如前一篇開頭所說,client需要把watcher註冊到server端,這一篇分析下server端的watcher。 主要分析Watchmanager類。 Watchmanager 這是WatchMan

Zookeeper原始碼閱讀 ACL基礎

前言 之前看程式碼的時候也同步看了看一些關於zk原始碼的部落格,有一兩篇講到了ZK裡ACL的基礎的結構,我自己這邊也看了看相關的程式碼,在這裡分享一下! ACL和ID ACL和ID都是有Jute生成的實體類,分別代表了ZK裡ACL和不同ACL模式下的具體實體。 ACL: public class A

Redis原始碼閱讀叢集-故障遷移(下)

Redis原始碼閱讀(六)叢集-故障遷移(下)   最近私人的事情比較多,沒有抽出時間來整理部落格。書接上文,上一篇裡總結了Redis故障遷移的幾個關鍵點,以及Redis中故障檢測的實現。本篇主要介紹叢集檢測到某主節點下線後,是如何選舉新的主節點的。注意到Redis叢集是無中心的,那麼使用分散式一

nginx原始碼分析5——監聽socket初始化

在nginx原始碼分析(4)中,看到了nginx的事件模型,但其中沒有介紹監聽socket的初始化。而對於web server來說,需要通過監聽socket來監聽客戶端的連線等。本篇將會具體介紹這方面的內容。還記得在前文介紹ngx_cycle_t結構時,它具有一個listening屬性,是一個數組,

XSStrike原始碼閱讀2——四種模式

1.bruteforcer模式 功能介紹 根據使用者提供的payloads檔案去暴力測試每一個引數,以此來確定是否存在xss漏洞(說起來也就是一個兩層迴圈)。 具體實現 XSStrike3.0 bruteforcer.py原始碼如下: import copy from

Spark原始碼閱讀

強烈推薦 https://blog.csdn.net/weixin_41705780/article/details/79273666 總體架構 Spark工程下的模組 spark core, spark 核心 spark streaming, spark流計算(基

Koa原始碼閱讀從搭建Web伺服器說起

先複習一下使用原生 Node.js 搭建一個 Web 伺服器。 var http = require('http'); var server = http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'te

Koa原始碼閱讀上下文ctx

上篇提到,this.callback() 返回一個回撥函式,其實是以閉包的形式返回了一個區域性函式變數 handleRequest,供 Server 呼叫來處理 HTTP 請求。 callback() { const fn = compose(this.middleware); const han

Redis原始碼閱讀叢集-請求分配

    叢集搭建好之後,使用者傳送的命令請求可以被分配到不同的節點去處理。那Redis對命令請求分配的依據是什麼?如果節點數量有變動,命令又是如何重新分配的,重分配的過程是否會阻塞對外提供的服務?接下來會從這兩個問題入手,分析Redis3.0的原始碼實現。 1. 分配依據—

java原始碼閱讀

#include <stdio.h> #define JRT_ENTRY(result_type , header) \ JRT_NO(result_type , header) #define JRT_NO(result_type , header

課時17 第三課Spark內部原理剖析與原始碼閱讀

為何spark shuffle比mapreduce shuffle慢? 主要是spark shuffle的shuffle read階段還不夠優秀,它是基於hashmap實現的,shuffle read會把shuffel write階段已經排序資料給重新轉成亂序的,轉成亂序之後又做了排序,導致非常低效,sp

spring原始碼閱讀1- ioc依賴注入之bean載入

還是先看下DefaultListableBeanFactory的類結構圖  我們從User user = (User) beanFactory.getBean("user");入手進入bean的載入管理流程。 這裡還是堅持走主線的流程,去掉無關的枝葉,儘量讓業務變得簡

spring原始碼閱讀2-aop之jdk動態代理深入解析

續spring原始碼閱讀(2)-aop之j動態代理 我們從需求作為動態代理髮展的切入吧 現在有5個已經投產了的run100m的實現,我們新的需求需要監控不同實現的執行效能,如果我們針對這五個實現分別去新增效能監控的程式碼,如此就造成兩個問題: 一個是已經穩定的程式碼需要

spring原始碼閱讀2-aop之原始碼解析篇

經過一個aop術語介紹和動態代理的深入講解,我們終於可以來看aop的原始碼了,下面跟著博主一點點剖析spring aop原始碼的實現吧 我們知道spring使用中我們只要做好相關的配置,spring自動幫我們做好了代理的相關工作。 我們從三個方面入手吧 1、配置 2、