Nginx源码学习-从零开始(1)

Nginx源码结构

版本: 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之类的,有可能区要多次内存访问才能取到值。
因为计算机使用数据不是一个字节一个字节取用的,而是一块一块取。
下图简单的说明一些数据对齐为什么会对效率产生影响:

Nginx源码学习-从零开始(1)_第1张图片
下面是测试代码:

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

Nginx源码学习-从零开始(1)_第2张图片

可以看到第一行输出结构体的大小和所包含的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字节对齐的位置。
更多内存对齐的至少,猿们不懂自行学习。

你可能感兴趣的:(Nginx)