nginx事件模块 -- 第五篇 epoll add

微信公众号:郑尔多斯
关注可了解更多的Nginx知识。任何问题或建议,请公众号留言;
关注公众号,有趣有内涵的文章第一时间送达!

内容回顾

上一篇文章我们介绍了Nginxepoll初始化过程。从这一篇文章开始我们继续介绍ngx_epoll_module的源码,包括添加事件,删除事件,触发事件等。

ngx_epoll_module_ctx源码

 1static ngx_event_module_t  ngx_epoll_module_ctx = { 2    &epoll_name, 3    ngx_epoll_create_conf,               /* create configuration */ 4    ngx_epoll_init_conf,                 /* init configuration */ 5 6    { 7        ngx_epoll_add_event,             /* add an event */ 8        ngx_epoll_del_event,             /* delete an event */ 9        ngx_epoll_add_event,             /* enable an event */10        ngx_epoll_del_event,             /* disable an event */11        ngx_epoll_add_connection,        /* add an connection */12        ngx_epoll_del_connection,        /* delete an connection */13#if (NGX_HAVE_EVENTFD)14        ngx_epoll_notify,                /* trigger a notify */15#else16        NULL,                            /* trigger a notify */17#endif18        ngx_epoll_process_events,        /* process the events */19        ngx_epoll_init,                  /* init the events */20        ngx_epoll_done,                  /* done the events */21    }22};

添加新事件

从上面的源码中我们可以知道,epoll添加事件的方法为ngx_epoll_add_event,源码如下:

 1static ngx_int_t 2ngx_epoll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) 3{ 4    int                  op; 5    uint32_t             events, prev; 6    ngx_event_t         *e; 7    ngx_connection_t    *c; 8    struct epoll_event   ee; 910    c = ev->data;1112    events = (uint32_t) event;1314    if (event == NGX_READ_EVENT) {15        e = c->write;16        prev = EPOLLOUT;17#if (NGX_READ_EVENT != EPOLLIN|EPOLLRDHUP)18        events = EPOLLIN|EPOLLRDHUP;19#endif2021    } else {22        e = c->read;23        prev = EPOLLIN|EPOLLRDHUP;24#if (NGX_WRITE_EVENT != EPOLLOUT)25        events = EPOLLOUT;26#endif27    }2829    if (e->active) {30        op = EPOLL_CTL_MOD;31        events |= prev;3233    } else {34        op = EPOLL_CTL_ADD;35    }3637#if (NGX_HAVE_EPOLLEXCLUSIVE && NGX_HAVE_EPOLLRDHUP)38    if (flags & NGX_EXCLUSIVE_EVENT) {39        events &= ~EPOLLRDHUP;40    }41#endif4243    ee.events = events | (uint32_t) flags;44    ee.data.ptr = (void *) ((uintptr_t) c | ev->instance);4546    if (epoll_ctl(ep, op, c->fd, &ee) == -1) {47        return NGX_ERROR;48    }4950    ev->active = 1;51    return NGX_OK;52}

该函数的三个参数功能如下:

ev:我们要添加的事件
event: 事件的类型,读事件或者写事件,我们这里分析read event,对于write event来说道理相同
flags: 添加事件的参数

我们这里只分析read event:
这里有一个问题,为什么添加read event的时候要判断c->write呢?

1 if (event == NGX_READ_EVENT) {2        e = c->write;3        prev = EPOLLOUT;4#if (NGX_READ_EVENT != EPOLLIN|EPOLLRDHUP)5        events = EPOLLIN|EPOLLRDHUP;6#endif7}

其实结合后面的代码就很清楚了,我们看一下后面的代码:

1if (e->active) {2        op = EPOLL_CTL_MOD;3        events |= prev;4} else {5        op = EPOLL_CTL_ADD;6}

因为往epoll中增加事件的时候,有两种方式,分别为 addmodify。当我们将某个fd添加read event的时候,如果该fdwrite event已经被添加到了epoll中,那么我们就不能继续add了,只能modify,所以这里要先判断一下write event的状态。
我们查看 man epoll手册,在Question and answers部分有下面一个Question,如下:

Q1 What happens if you register the same file descriptor on an epoll instance twice?
A1 You will probably get EEXIST. However, it is possible to add a duplicate (dup(2), dup2(2), fcntl(2) F_DUPFD) descriptor to t

这里有一点要注意,那就是我们添加的eventdata字段,我们先看一下epoll函数中event的结构:

 1 typedef union epoll_data { 2     void        *ptr; 3     int          fd; 4     uint32_t     u32; 5     uint64_t     u64; 6} epoll_data_t; 7 8struct epoll_event { 9    uint32_t     events;      /* Epoll events */10    epoll_data_t data;        /* User data variable */11};

ngx_epoll_add_event()函数中有下面一句话:

1ee.data.ptr = (void *) ((uintptr_t) c | ev->instance);

这里会把 event->data->ptr指向当前事件对应的connection。这是一个很重要的特性。这样的话,当我们epoll_wait()获取到某个事件之后,就可以拿到这个事件对应的connection,然后进行各种操作。

这就是ngx_epoll_add_event()的处理流程,这里遗留了一个问题:
read event 或者 write eventdata字段是什么时候指向了connection呢?
其实是在 ngx_get_connection()方法中。我们随后会分析这个函数。



喜欢本文的朋友们,欢迎长按下图关注订阅号郑尔多斯,更多精彩内容第一时间送达

郑尔多斯

原文地址:https://www.cnblogs.com/zhengerduosi/p/10178530.html

时间: 2024-08-29 12:20:58

nginx事件模块 -- 第五篇 epoll add的相关文章

Nginx 事件模块

概述 Nginx 是以事件的触发来驱动的,事件驱动模型主要包括事件收集.事件发送.事件处理(即事件管理)三部分.在Nginx 的工作进程中主要关注的事件是 IO 网络事件 和 定时器事件.在生成的 objs 目录文件中,其中ngx_modules.c 文件的内容是 Nginx 各种模块的执行顺序,我们可以从该文件的内容中看到事件模块的执行顺序为以下所示:注意:由于是在 Linux 系统下,所以支持具体的 epoll 事件模块,接下来的文章结构按照以下顺序来写. extern ngx_module

【Nginx】Nginx事件模块

一.事件处理框架概述 事件处理框架所要解决的问题是如何收集.管理.分发事件.事件处理框架需要在不同的操作系统内核中选择一种事件驱动机制支持网络事件的处理. 步骤: 1.Nginx定义了一个核心模块ngx_events_module,该模块定义了事件类型的模块,为所有的事件模块解析events{}中的配置项,同时管理这些事件模块存储配置项的结构体 2.Nginx定义了一个非常重要的事件模块ngx_event_core_module,这个模块会决定使用哪种事件驱动机制,以及如何管理事件 3.Ngin

nginx事件模块 -- 第一篇

微信公众号:郑尔多斯关注可了解更多的Nginx知识.任何问题或建议,请公众号留言;关注公众号,有趣有内涵的文章第一时间送达! 事件机制 下面是我们对nginx事件相关的配置,如下: 1events {2    worker_connections  1024;3    use epoll;4} 我们明确的使用了epoll机制,在nginx中,和事件相关的模块一共有三个,分别为ngx_events_module,ngx_event_core_module,ngx_epoll_module.本篇文章

nginx事件模块 -- 第二篇

微信公众号:郑尔多斯关注可了解更多的Nginx知识.任何问题或建议,请公众号留言;关注公众号,有趣有内涵的文章第一时间送达! 事件机制 上一篇文件我们简单的介绍了ngx_event_block()函数的功能,这个函数用于解析events指令,引入事件机制.其实真正的工作是在ngx_event_core_module中完成的,这个模块可以解析use,work_connections等指令,这些指令用于控制nginx事件机制的一些参数.上一篇文章中我们也提到过执行ngx_event_block()函

nginx事件模块指令

accept_mutex Syntax: accept_mutex [ on | off ] Default: on nginx 使用连接互斥锁进行顺序的accept()系统调用. accept_mutex_delay Syntax: accept_mutex_delay Nms; Default: 500ms 如果一个进程没有互斥锁,它将延迟至少多长时间.默认情况下,延迟是500ms . debug_connection Syntax: debug_connection [ip | CIDR]

Nginx学习日记第五篇 -- upstream及fastcgi

一.Nginx upstream Ngx_http_upstream_module模块可实现七层负载均衡,定义的服务器组可被proxy_pass.fastcgi_pass.uwsgi_pass.scgi_pass和memcached_pass所引用. 1.实验场景 Nginx upstream IP:192.168.0.110 apache node1 IP:192.168.0.40 apache node2 IP:192.168.0.30  2.Nginx upstream配置(结合proxy

nginx学习笔记五(nginx的事件模块定义)

在linux后台服务器开发领域里面,epoll的大名是早有所闻.<深入理解nginx>一书在第9章-事件模块中就详细说明了epoll相关的系统调用是怎么嵌入到nginx的框架中. 下面说明nginx框架下与事件处理相关的一些模块. 一.ngx_events_module ngx_events_module是核心模块中的一种.之前一直不是很明白核心模块的意思,现在想来,事件模块的核心模块应该是第一个启动的与事件相关的模块.这个模块并不会去处理实际的事件业务,而是会去做一些基本的初始化操作.ngx

nginx源码分析--事件模块 &amp; 琐碎

通过HUP信息使得NGINX实现重新读取配置文件,使用USR2信号使得NGINX实现平滑升级. 在nginx中有模块这么一说,对外所有的模块都是ngx_module_t类型,这个结构体作为所有模块的通用接口,它只定义了init_master.init_module.init_process.init_thread.exit_thread.exit_process.exit_master这7个回调方法,(其实init_master.init_thread.exit_thread这3个方法目前都没有

nginx之旅(第五篇):URL重写介绍、URL重写场景、URL重写语法

nginx之旅(第五篇):URL重写 一.URL重写介绍 URL重写是指将一个URL请求重新写成网站可以处理的另一个URL的过程.这样说可能不是很好理解,举个例子来说明一下,在开发中可能经常遇到这样的需求,比如通过浏览器请求的http://localhost:8080/getUser?id=1,但是需要通过SEO优化等等原因,需要把请求的地址重写为http://localhost:8080/getUser/1这样的URL,从而符合需求或者更好的被网站阅读. 当遇到这种请求的时候,就需要使用到Ur