版本: nginx-1.11.7
源码目录结构
├── auto #自动检测系统环境以及编译相关的脚本
│ ├── cc #关于编译器相关的编译选项的检测脚本
│ ├── lib #nginx编译所需要的一些库的检测脚本
│ │ ├── geoip
│ │ ├── google-perftools
│ │ ├── libatomic
│ │ ├── libgd
│ │ ├── libxslt
│ │ ├── openssl
│ │ ├── pcre
│ │ ├── perl
│ │ └── zlib
│ ├── os #与平台相关的一些系统参数与系统调用相关的检测
│ └── types #与数据类型相关的一些辅助脚本
├── conf #存放默认配置文件,在make install后,会拷贝到安装目录中去
├── contrib #存放一些实用工具,如geo配置生成工具(geo2nginx.pl)
│ ├── unicode2nginx
│ └── vim
│ ├── ftdetect
│ ├── ftplugin
│ ├── indent
│ └── syntax
├── docs #一些文档
│ ├── dtd
│ ├── html #存放默认的网页文件,在make install后,会拷贝到安装目录中去
│ ├── man #nginx的man手册
│ ├── text
│ ├── xml
│ │ └── nginx
│ ├── xsls
│ └── xslt
├── misc
└── src #存放nginx的源代码
├── core #nginx的核心源代码,包括常用数据结构的定义,以及nginx初始化运行的核心代码如main函数
├── event#对系统事件处理机制的封装,以及定时器的实现相关代码
│ └── modules #不同事件处理方式的模块化,如select、poll、epoll、kqueue等
├── http #nginx作为http服务器相关的代码
│ ├── modules #包含http的各种功能模块
│ │ └── perl
│ └── v2
├── mail #nginx作为邮件代理服务器相关的代码
├── misc #一些辅助代码,测试c++头的兼容性,以及对google_perftools的支持
├── os #主要是对各种不同体系统结构所提供的系统函数的封装,对外提供统一的系统调用接口
│ ├── unix
│ └── win32
└── stream #stream 模块用于一般的 TCP 代理和负载均衡
源码直接的互相引用比较多,先看独立性比较强的代码
src/core/ngx_config.h
/*
* Copyright (C) Igor Sysoev
* Copyright (C) Nginx, Inc.
*/
#ifndef _NGX_CONFIG_H_INCLUDED_
#define _NGX_CONFIG_H_INCLUDED_
#include
#if defined __DragonFly__ && !defined __FreeBSD__
#define __FreeBSD__ 4
#define __FreeBSD_version 480101
#endif
#if (NGX_FREEBSD)
#include
#elif (NGX_LINUX)
#include
#elif (NGX_SOLARIS)
#include
#elif (NGX_DARWIN)
#include
#elif (NGX_WIN32)
#include
#else /* POSIX */
#include
#endif
#ifndef NGX_HAVE_SO_SNDLOWAT
#define NGX_HAVE_SO_SNDLOWAT 1
#endif
#if !(NGX_WIN32)
#define ngx_signal_helper(n) SIG##n
#define ngx_signal_value(n) ngx_signal_helper(n)
#define ngx_random random
/* TODO: #ifndef */
#define NGX_SHUTDOWN_SIGNAL QUIT
#define NGX_TERMINATE_SIGNAL TERM
#define NGX_NOACCEPT_SIGNAL WINCH
#define NGX_RECONFIGURE_SIGNAL HUP
#if (NGX_LINUXTHREADS)
#define NGX_REOPEN_SIGNAL INFO
#define NGX_CHANGEBIN_SIGNAL XCPU
#else
#define NGX_REOPEN_SIGNAL USR1
#define NGX_CHANGEBIN_SIGNAL USR2
#endif
#define ngx_cdecl
#define ngx_libc_cdecl
#endif
typedef intptr_t ngx_int_t;
typedef uintptr_t ngx_uint_t;
typedef intptr_t ngx_flag_t;
#define NGX_INT32_LEN (sizeof("-2147483648") - 1)
#define NGX_INT64_LEN (sizeof("-9223372036854775808") - 1)
#if (NGX_PTR_SIZE == 4)
#define NGX_INT_T_LEN NGX_INT32_LEN
#define NGX_MAX_INT_T_VALUE 2147483647
#else
#define NGX_INT_T_LEN NGX_INT64_LEN
#define NGX_MAX_INT_T_VALUE 9223372036854775807
#endif
#ifndef NGX_ALIGNMENT
#define NGX_ALIGNMENT sizeof(unsigned long) /* platform word */
#endif
#define ngx_align(d, a) (((d) + (a - 1)) & ~(a - 1))
#define ngx_align_ptr(p, a) \
(u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))
#define ngx_abort abort
/* TODO: platform specific: array[NGX_INVALID_ARRAY_INDEX] must cause SIGSEGV */
#define NGX_INVALID_ARRAY_INDEX 0x80000000
/* TODO: auto_conf: ngx_inline inline __inline __inline__ */
#ifndef ngx_inline
#define ngx_inline inline
#endif
#ifndef INADDR_NONE /* Solaris */
#define INADDR_NONE ((unsigned int) -1)
#endif
#ifdef MAXHOSTNAMELEN
#define NGX_MAXHOSTNAMELEN MAXHOSTNAMELEN
#else
#define NGX_MAXHOSTNAMELEN 256
#endif
#define NGX_MAX_UINT32_VALUE (uint32_t) 0xffffffff
#define NGX_MAX_INT32_VALUE (uint32_t) 0x7fffffff
#if (NGX_COMPAT)
#define NGX_COMPAT_BEGIN(slots) uint64_t spare[slots];
#define NGX_COMPAT_END
#else
#define NGX_COMPAT_BEGIN(slots)
#define NGX_COMPAT_END
#endif
#endif /* _NGX_CONFIG_H_INCLUDED_ */
首先针对不同的操作系统引用了对应的头文件,这些文件在src/os/unix 和src/os/win32目录下,并定义了一些宏,比较简单,重点在下面这两个宏:
#define ngx_align(d, a) (((d) + (a - 1)) & ~(a - 1))
#define ngx_align_ptr(p, a) \
(u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))
这两个宏,查了一些资料,使用来做内存池的内存对齐用的,用来提高效率。整理了一下。要弄懂这两个宏定义,首先要理解C语言的字节对齐,字节对齐的主要目的是提高CPU的访问效率。在GCC中默认是4字节对齐的。
理解表达式 ~(a - 1)注意,其中a为2的幂,设右数第n位为非零位,则a-1为右数的n-1位均为1, 则有~(a-1)为最后的n-1位全为0
例如:d = 5 ,a= 4
d二进制 0101
a二进制 0100
((d)+(a-1)) 二进制 1000
~(a-1) 二进制 1100
整个宏结果:1000 = 8
又:d = 3 ,a= 4
d二进制 0011
a二进制 0100
((d)+(a-1)) 二进制 0110
~(a-1) 二进制 1100
整个宏结果:0100 = 4
实际上是以a为对齐基准,向上取2的幂,这种计算地址或者长度对齐,取整的宏还是很有用的。cpu访问对齐的数据较快,不对齐的的int之类的,有可能区要多次内存访问才能取到值。
因为计算机使用数据不是一个字节一个字节取用的,而是一块一块取。
下图简单的说明一些数据对齐为什么会对效率产生影响:
#include
#include
#include
/*内存对齐*/
#define ngx_align(d, a) (((d) + (a - 1)) & ~(a - 1))
#define ngx_align_ptr(p, a) \
(u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))
struct AlignTest
{
char a;
int b;
char c;
};
int main(int argc,char * argv[])
{
struct AlignTest alg1 = {'a',1234,'c'};
printf("%d %d\n",sizeof(struct AlignTest),sizeof(int)+sizeof(char)*2); //结构体大小和实际三项数据的大小,结构体的实际为12, 而不是6
printf("%x %x %x %x\n",&alg1,&(alg1.a),&(alg1.b),&(alg1.c));
printf("%d\n",ngx_align(73, 8));
printf("%x %x %x\n",ngx_align_ptr(&(alg1.a), 4),ngx_align_ptr(&(alg1.a)+1, 4),&(alg1.b));/*数据成员a的地址,
a的地址加1后四字节对齐的地址,可以在下面的运行结果看到和b的地址是相同的。*/
printf("%x \n",&(alg1.a)+1);
return 0;
}
可以看到第一行输出结构体的大小和所包含的3个数据项大小的并不一致。要手动控制对齐方式可以使用__attribute__((aligned(n))或是 #pragm pack(n), 其中的数字n的位置可以制定按照几字节对齐。
ngx_align,这个宏使用来计算存储d字节的数据,如果按照a字节对其,需要多少字节来存储对齐的数据,其中a为2的指数幂。而ngx_align_ptr,长得跟ngx_align相似,作用也相似,不同的是ngx_align_ptr是针对指针地址进行对齐操作。假如说p所指的位置能够按照a字节对齐,则就是p所指的位置了,如果p所指的位置不能按照a字节对齐,找到下一个能够按照a字节对齐的位置。
更多内存对齐的至少,猿们不懂自行学习。