存档

‘Nginx’ 分类的存档

Nginx使用instance标记处理kqueue/epoll中的stale事件

2015年8月28日 评论已被关闭

下面以epoll为例:

每个fd往往会关联一个自定义的结构体来表示逻辑上的连接。比如在nginx中每个ngx_connection_t都抽象成一个TCP连接并且与fd关联。

当我们accept到一个连接的时候,我们会申请这样一个ngx_connection_t,随后将这个fd与ngx_connection_t关联并加入到epoll循环。

代码(添加读事件)

然后我们使用epoll_wait来检查发生的事件

每个epoll_event的data.ptr是由ngx_connection_t*指针与instance相或而来,也就是data.ptr = c | instance;这样做是有前提条件的,那就是c必须是偶数,因为instance是bool类型,data.ptr最末位存储了instance的值。

 

假设当某一次epoll_wait后返回了一组epoll_event。

随后进行了如下操作:如图1所示:

(1)fd=47的文件描述有事件发生。

(2)处理fd=47时,我们关闭了fd=12的连接,回收了ngx_connection_t内存。

(3)接着处理fd=12时,此时data_ptr指向的ngx_connection_t已经被销毁,访问data_ptr将出现致命错误。

20150828160701

解决方法(如图2所示):暂不回收ngx_connection_t内存而是将ngx_connection_t的fd设置为-1,那么处理fd=12时,发现ngx_connection_t中的fd=-1,那么足以证明这个fd在之前已经被释放掉了,从面阻止使用data_ptr继续使用,这就是stale事件。

20150828160702

 

当我们将fd=12的ngx_connection_t回收后将fd设成了-1,防止处理到fd=12时使用了被释放的data_ptr。

试想一下,此时将fd设置成了-1,但在处理fd=12前,我将刚才释放的ngx_connection_t重新分配给了新连接fd=48(调用了accept()),那么在处理fd=12时,其data_ptr仍然不能使用,因这个ngx_connection_t已不属于fd=12而是属于fd=48,也就是说fd=12的ngx_connection_t已被释放并被fd=48使用。

我们使用instance来区分这个ngx_connection_t到底属于谁。因为本身data_ptr中存储了instance值,并且ngx_connection_t中也存储了instance值,在申请ngx_connection_t时,我们要将ngx_connection_t中的instance值置反。当ngx_connection_t的instance与data_ptr不一致时,说明当前fd已销毁。(如图3所示)

20150828160703

 

注意

另外,有一点要说明的是,如果在处理fd=12之前,fd=48也被销毁了,然后该ngx_connection_t又被fd=49复用,那么这种情况仍然会有问题。

这会导致data_ptr中的instance值与ngx_connection_t一致(两次置反)并且fd=49。event_list原本指示的fd=12有事件,但被nginx错误地认为了fd=49有事件发生,目前我还没想到好的解决办法。

分类: C/C++, Linux, Nginx 标签:

nginx的模块上下文

2015年4月26日 评论已被关闭

ngx_modules数组定义:

初始化完成: 阅读全文…

分类: Nginx 标签:

nginx中定时器与事件流程

2015年4月13日 评论已被关闭

1.nginx中的时间更新

Nginx在内部自己缓存时间,那么这些时间值在什么地方更新呢?

1.1 收到信号时更新时间

1.2 timer_resolution值为0

如果用户没有设置timer_resolution值或者设置为0值,那么每次在轮询事件都会设置NGX_UPDATE_TIME标志,表示轮询结束后要更新时间(以kqueue为例):

轮询时:

1.3 timer_resolution值非0

如果用户设置timer_resolution为非零值,nginx会在定时器触发时更新时间。

在nginx中系统定时器的具体实现有两种,一种是使用setitimer(),另外一种具体事件中模型实现的。

1.3.1使用setitimer()

在事件初始化后使用setitimer(timer_resolution),那么系统会每隔timer_resolution(单位为毫秒)发送SIGALARM信号,信号处理函数:

后续的的轮询会被打断并在结束后会去判断ngx_event_timer_alarm值,如果为1的话会更新时间(以kqueue为例):

1.3.2使用特定的事件模型

对于特定的事件模型,在这里只包括kqueue和eventport。它们内部实现了一个定时器,我们在事件初始化时安装定时器,例如(以kqueue为例):

同时设置还会置上NGX_USE_TIMER_EVENT标志,并且定时器触发时没有回调函数,我们要在事件轮询后判断是否是定时器事件,如果是则要更新时间(以kqueue为例):

 

总结:nginx自身缓存时间。 阅读全文…

分类: Linux, Nginx 标签:

Nginx源码分析(一)

2012年3月12日 没有评论

1.错误定义

分析源码从最简单的地方入手,首先来看nginx的错误码定义,代码在ngx_errno.h,ngx_errno.h文件中。一共就两个函数。

  1. u_char *ngx_strerror(ngx_err_t err, u_char *errstr, size_t size);
  2. ngx_uint_t ngx_strerror_init(void);

系统启动时会初始化全局变量ngx_sys_errlist,这是一个全局ngx_str_t数组,数组大小为NGX_SYS_NERR,每个元素都一个结构体为:

  1. typedef struct {
  2.     size_t      len;//data成员的大小
  3.     u_char     *data;//一个字符串
  4. } ngx_str_t;

初始化:ngx_uint_t ngx_strerror_init
所以初始化的函数是填充每一个元素,该元素的数组下标即为错误码,元素len成员是指元素data字符串的大小,data是该错误码(数组下标)的文字描述,通过函数strerror(err)来取得错误码的信息串。
获取错误码对应的信息串:ngx_strerror
在ngx_sys_errlist找到err对应位置的错误信息,如果错误码不在数组下标范围则返回未知错误,同时检查传入的长度,太小于将会截断错误信息串。

分类: Linux, Nginx 标签:

在windwos下的编译Nginx

2012年2月28日 没有评论

在windows下编译nginx可以利用VC编译来调试nginx,当我们很熟悉了操作系统上层的实现之后转向分析nginx代码也方便一些。
在windows下编译nginx跟在Linux下的步骤差不多。利用svn工具下载源码,第三方网站下载的tar文件中没有win32的配置文件;由于configure文件是sh脚本,所以只能用第三方仿真软件,我这里用的是MinGW Shell;配置完成后就是编译,只要调用VC的编译工具cl.exe编译就行了。

下载工具
需要的工具有:
1.TortoiseSVN:http://downloads.sourceforge.net/project/tortoisesvn/1.7.5/Application/TortoiseSVN-1.7.5.22551-win32-svn-1.7.3.msi
2.MinGW32:http://10.10.4.6/download/7377061/8602355/3/exe/230/40/1322227850470_40/mingw-get-inst-20111118.exe
3.VC2010 express:http://download.microsoft.com/download/e/5/e/e5e362e1-6a2a-4ce3-bbac-659c9740ab04/vc_web.exe
上面的工具下载安装完成即可。

下载源码
源码地址在:svn://svn.nginx.org/nginx/trunk 使用svn将源码检出到本地任意目录,比如f:\nginx\trunk
目录结构如下:
f—nginx—trunk—(auto conf contrib docs misc src)

配置代码环境
打开cmd命令行提示:

2.设置VC的环境变量:在命令提示符中键入命令(根据VC的安装目录不同而不同,x86为参数)

设置MinGW:在命令提示符键入命令(根据MinGW32安装目录不同而不同):

检查环境:
弹出MinGW窗口,关闭其它的cmd窗口。在MinGW32的窗口输入:

有如下显示:
用于 80×86 的 Microsoft (R) 32 位 C/C++ 优化编译器 16.00.30319.01 版
版权所有(C) Microsoft Corporation。保留所有权利。
用法: cl [ 选项… ] 文件名… [ /link 链接选项… ]
说明编译环境配置成功
编译
cd进入主目录,即truck目录

配置:

注解:
–prefix=. 表示安装目录在本目录下
–with-cc-opt=”-D FD_SETSIZE=4096″ 预定义宏FD_SETSIZE大小4096
–without-http_rewrite_module 不加载rewite模块
–without-http_gzip_module 不加载gzip模块
–with-cc=cl 编译器为cl
编译:

在obj/目录下为生成的中间文件和nginx.exe文件。

分类: Nginx 标签: