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、