Nginx源代码分析之I/O模型细节(七)

原创 2015年07月10日 20:16:36

这里谈谈源码的具体实现


作为统一框架,每个模型都有统一的处理接口包括,这里定义在

typedef struct {
    ngx_int_t  (*add)(ngx_event_t *ev, int event, u_int flags);
    ngx_int_t  (*del)(ngx_event_t *ev, int event, u_int flags);


    ngx_int_t  (*enable)(ngx_event_t *ev, int event, u_int flags);
    ngx_int_t  (*disable)(ngx_event_t *ev, int event, u_int flags);


    ngx_int_t  (*add_conn)(ngx_connection_t *c);
    ngx_int_t  (*del_conn)(ngx_connection_t *c, u_int flags);


    ngx_int_t  (*process_changes)(ngx_cycle_t *cycle, ngx_uint_t nowait);
    ngx_int_t  (*process_events)(ngx_cycle_t *cycle, ngx_msec_t timer,
                   ngx_uint_t flags);


    ngx_int_t  (*init)(ngx_cycle_t *cycle, ngx_msec_t timer);
    void       (*done)(ngx_cycle_t *cycle);
} ngx_event_actions_t;


可以看到,主要有add,del,process_events,init,done,等主要方法。有点类似OOB的多态,定义了统一的抽象接口。


于是每个模型都有自己的具体实现:


比如iocp模型下,分别实现了ngx_iocp_add_event,ngx_iocp_process_events,ngx_iocp_init

epoll模型下,则实现了ngx_epoll_add_event,ngx_epoll_del_event,ngx_epoll_process_events,ngx_epoll_init

select则与epoll类似。



我们知道,ngx_single_process_cycle是I/O处理的线程,其中,process_events 方法是在这个线程中被调用。

    for ( ;; ) {
        ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle");


        ngx_process_events_and_timers(cycle);


        if (ngx_terminate || ngx_quit) {


            for (i = 0; ngx_modules[i]; i++) {
                if (ngx_modules[i]->exit_process) {
                    ngx_modules[i]->exit_process(cycle);
                }
            }


            ngx_master_process_exit(cycle);
        }


        if (ngx_reconfigure) {
            ngx_reconfigure = 0;
            ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring");


            cycle = ngx_init_cycle(cycle);
            if (cycle == NULL) {
                cycle = (ngx_cycle_t *) ngx_cycle;
                continue;
            }


            ngx_cycle = cycle;
        }


        if (ngx_reopen) {
            ngx_reopen = 0;
            ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs");
            ngx_reopen_files(cycle, (ngx_uid_t) -1);
        }


实际上是在ngx_process_events_and_timers函数中调用处理方法,ngx_process_events_and_timers函数涉及到多个重要问题。比如accept的互斥管理的问题,超时的管理问题,不同I/O模型的ngx_process_events的处理,ngx_posted_accept_events和ngx_posted_events队列的处理。

这里只谈谈ngx_process_events。 ngx_process_events主要用于异步模型中当时未完成,但延迟完成的情况。


对于每个模型来说,无非是通过各模型的API,读取I/O的状态,来判断是否有I/O数据到达并就绪。每个模型的代码细节就不谈了,谈谈代码上的一些关键点以及一切差别。


关于timer,每个模型各有特点,但都会设置这个参数。比如GetQueuedCompletionStatus的最后一个参数用来设置timer。


就绪I/O的处理方法各有不同,对于select,会检查work_write_fd_set和work_read_fd_set的每个一句柄,然后将可读可写的socket对应的ev放入accept队列或者普通队列中。

代码如下:

    for (i = 0; i < nevents; i++) {
        ev = event_index[i];
        c = ev->data;
        found = 0;


        if (ev->write) {
            if (FD_ISSET(c->fd, &work_write_fd_set)) {
                found = 1;
                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                               "select write %d", c->fd);
            }


        } else {
            if (FD_ISSET(c->fd, &work_read_fd_set)) {
                found = 1;
                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                               "select read %d", c->fd);
            }
        }


        if (found) {
            ev->ready = 1;


            queue = ev->accept ? &ngx_posted_accept_events
                               : &ngx_posted_events;


            ngx_post_event(ev, queue);


            nready++;
        }
    }


然后接着调用ngx_event_process_posted(cycle, &ngx_posted_accept_events);以及ngx_event_process_posted(cycle, &ngx_posted_events);来处理已完成队列。

而iocp则不会使用这2个数据结构,在ngx_process_events_and_timers中,也就是ngx_iocp_process_events函数,iocp会直接调用ev->handler(ev);完成回调处理。

对于epoll模型,如果存在NGX_POST_EVENTS标志,会跟select一样把就绪I/O放入2个对之列中,如果不存在,则直接调用rev->handler(rev);

为什么有这样的差别,以后在详细论述。


Nginx源代码分析之I/O细节(十一)

至于每个平台和模型里面具体I/O的细节,我们简单分析一下,先看看发送的具体实现,我们先以iocp模型来进行具体分析。 在Upstream部分,最后提到真正的发送函数是一个send_chain指针,对...
  • namelcx
  • namelcx
  • 2015年07月31日 22:12
  • 539

解释nginx的epoll的网络I/O模型为什么快的原因

epoll是多路复用IO(I/O Multiplexing)中的一种方式,但是仅用于linux2.6以上内核,在开始讨论这个问题之前,先来解释一下为什么需要多路复用IO. 以一个生活中的例子来解释....
  • xb_0916
  • xb_0916
  • 2013年08月06日 17:14
  • 926

Nginx源代码分析之accept细节(十九)

现在单独说说accept中与一些具体I/O模型相关的细节。         其实前面已经提过这个问题,这一系列I/O模型中最大差别是iocp,我们前面也说了,linux的几个模型,不管是select,...
  • namelcx
  • namelcx
  • 2016年09月09日 17:37
  • 830

nginx源代码分析 - 启动(六) 关于worker进程绑定CPU的细节

关于worker进程绑定CPU的细节 配置: worker_processes  2; worker_cpu_affinity 01 10; linux,NGX_HAVE_SCHED_SE...

WinSock五种I/O模型的性能分析

原文地址:http://club.topsage.com/thread-735498-1-1.html 五种I/O模型的性能分析 重叠I/O模型的另外几个优点在于,微软针对重叠I/O模型提...

Java I/O流模型概念分析整理

Java中的流,可以从不同的角度进行分类。 按照数:输入流和输出流。按照处理数据单位不同可以分为:字节流和字符流。按照实现功能不同可以分为:节点流和处理流。 输出流: ...

memcached I/O模型源码分析

memcached是基于多路复用实现事件驱动的服务器,在事件处理方面,应用了master+works的线程模型。 master线程负责监听端口,当有新的连接,master线程负责接收连接,...

千百万以上海量连接的select、poll和epoll等网络I/O模型的性能测试与分析提纲

千百万以上海量连接的select、poll和epoll等网络I/O模型的性能测试与分析。The C10M Problem...
  • tlthm
  • tlthm
  • 2016年07月03日 23:53
  • 337

WinSock五种I/O模型的性能分析

五种I/O模型的性能分析重叠I/O模型的另外几个优点在于,微软针对重叠I/O模型提供了一些特有的扩展函数。当使用重叠I/O模型时,可以选择使用不同的完成通知方式。采用事件对象通知的重叠I/O模型是不可...
  • smalldu
  • smalldu
  • 2011年01月23日 22:33
  • 256

Linux--I/O模型分析

socket的 内核会用更高效的方式去做,而用户空间的代码每一次系统调用都要包含一次用户空间到内核空间的转换,以及内核再转换回来,这样就很浪费机器周期。而且内核中的poll接口实现会根据操作文...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Nginx源代码分析之I/O模型细节(七)
举报原因:
原因补充:

(最多只允许输入30个字)