nginx aio机制详解
来源:互联网 发布:java void 方法 编辑:程序博客网 时间:2024/05/16 14:04
linux 2.6以上内核提供以下几个系统调用来支持aio:
1、 SYS_io_setup:建立aio 的context
2、 SYS_io_submit: 提交I/O操作请求
3、 SYS_io_getevents:获取已完成的I/O事件
4、 SYS_io_cancel:取消I/O操作请求
5、 SYS_io_destroy:毁销aio的context
nginx中将aio和epoll事件模型(假设nginx使用epoll事件模型)组合起来使用,当请求的I/O操作完成时调用epoll相关函数通知应用程序来读取。组合的关键点在于使用了eventfd对象,那什么是eventfd呢?有关eventfd的详解资料参考http://linux.die.net/man/2/eventfd。
nginx在woker工作进程启动后初始化epoll事件模型时初始化aio(ngx_epoll_aio_init函数负责aio的初始化)。实现原理如下:在aio初始化时调用eventfd系统调用创建一个eventfd对象,eventfd系统调用返回一个与eventfd对象关联的文件描述符,设置该描述符为非阻塞并添加到epoll中,当该描述符可读时epoll_wait函数返回调用read函数读取当前完成的I/O操作个数,我们通过调用SYS_io_getevents系统调用就可以获取已完成的I/o事件。但eventfd描述符什么时候可读呢?这需要在提交I/O事件时将eventfd与aio关联起来(实现代码在ngx_file_aio_read函数中),提交I/O事件后如果I/O事件已完成就将当前完成的事件个数写入到eventfd描述符相关的计数器中并标识eventfd可读。下面来看看nginx中与aio相关的源代码:
ngx_epoll_aio_init函数:
static voidngx_epoll_aio_init(ngx_cycle_t *cycle, ngx_epoll_conf_t *epcf){ int n; struct epoll_event ee; /***调用eventfd系统调用新建一个eventfd对象,第二个参数中的0表示eventfd的计数器初始值为0, 系统调用成功返回的是与eventfd对象关联的描述符***/ ngx_eventfd = syscall(SYS_eventfd, 0); if (ngx_eventfd == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "eventfd() failed"); ngx_file_aio = 0; return; } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "eventfd: %d", ngx_eventfd); n = 1; //设置描述符为非阻塞 if (ioctl(ngx_eventfd, FIONBIO, &n) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "ioctl(eventfd, FIONBIO) failed"); goto failed; } //调用SYS_io_setup系统调用建立aio context if (io_setup(epcf->aio_requests, &ngx_aio_ctx) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "io_setup() failed"); goto failed; } //ngx_epoll_eventfd_handler函数当ngx_eventfd描述符可读时被调用 ngx_eventfd_event.data = &ngx_eventfd_conn; ngx_eventfd_event.handler = ngx_epoll_eventfd_handler; ngx_eventfd_event.log = cycle->log; ngx_eventfd_event.active = 1; ngx_eventfd_conn.fd = ngx_eventfd; ngx_eventfd_conn.read = &ngx_eventfd_event; ngx_eventfd_conn.log = cycle->log; ee.events = EPOLLIN|EPOLLET; ee.data.ptr = &ngx_eventfd_conn; //将ngx_eventfd加入到epoll中 if (epoll_ctl(ep, EPOLL_CTL_ADD, ngx_eventfd, &ee) != -1) { return; } ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "epoll_ctl(EPOLL_CTL_ADD, eventfd) failed"); //epoll_ctl失败时需毁销aio的context if (io_destroy(ngx_aio_ctx) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "io_destroy() failed"); }failed: if (close(ngx_eventfd) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "eventfd close() failed"); } ngx_eventfd = -1; ngx_aio_ctx = 0; ngx_file_aio = 0;}
ngx_epoll_eventfd_handler函数:
static voidngx_epoll_eventfd_handler(ngx_event_t *ev){ int n, events; long i; uint64_t ready; ngx_err_t err; ngx_event_t *e; ngx_event_aio_t *aio; struct io_event event[64]; struct timespec ts; ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "eventfd handler"); //调用read函数读取已完成的I/O的个数 n = read(ngx_eventfd, &ready, 8); . . . ts.tv_sec = 0; ts.tv_nsec = 0; /***循环调用io_getevents函数获取所有已完成的I/O操作***/ while (ready) { events = io_getevents(ngx_aio_ctx, 1, 64, event, &ts); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0, "io_getevents: %l", events); if (events > 0) { . . . continue; } if (events == 0) { return; } /* events == -1 */ ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "io_getevents() failed"); return; }}
ngx_file_aio_read函数:
ssize_tngx_file_aio_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset, ngx_pool_t *pool){ ngx_err_t err; struct iocb *piocb[1]; ngx_event_t *ev; ngx_event_aio_t *aio; . . . ngx_memzero(&aio->aiocb, sizeof(struct iocb)); /***设置iocb结构,注意aio->aiocb.aio_flags与aio->aiocb.aio_resfd这两个成员***/ aio->aiocb.aio_data = (uint64_t) (uintptr_t) ev; aio->aiocb.aio_lio_opcode = IOCB_CMD_PREAD; aio->aiocb.aio_fildes = file->fd; aio->aiocb.aio_buf = (uint64_t) (uintptr_t) buf; aio->aiocb.aio_nbytes = size; aio->aiocb.aio_offset = offset; /***当IOCB_FLAG_RESFD标识被设置时就使用aio->aiocb.aio_resfd变量中的描述符中通知用户态I/O事件已完成***/ aio->aiocb.aio_flags = IOCB_FLAG_RESFD; aio->aiocb.aio_resfd = ngx_eventfd; ev->handler = ngx_file_aio_event_handler; piocb[0] = &aio->aiocb; //提交I/O事件 if (io_submit(ngx_aio_ctx, 1, piocb) == 1) { ev->active = 1; ev->ready = 0; ev->complete = 0; return NGX_AGAIN; } err = ngx_errno; if (err == NGX_EAGAIN) { return ngx_read_file(file, buf, size, offset); } ngx_log_error(NGX_LOG_CRIT, file->log, err, "io_submit(\"%V\") failed", &file->name); if (err == NGX_ENOSYS) { ngx_file_aio = 0; return ngx_read_file(file, buf, size, offset); } return NGX_ERROR;}
io_setup函数:
static intio_setup(u_int nr_reqs, aio_context_t *ctx){ return syscall(SYS_io_setup, nr_reqs, ctx);}
io_destroy函数:
static intio_destroy(aio_context_t ctx){ return syscall(SYS_io_destroy, ctx);}
io_getevents函数:
static intio_getevents(aio_context_t ctx, long min_nr, long nr, struct io_event *events, struct timespec *tmo){ return syscall(SYS_io_getevents, ctx, min_nr, nr, events, tmo);}
io_submit函数:
static intio_submit(aio_context_t ctx, long n, struct iocb **paiocb){ return syscall(SYS_io_submit, ctx, n, paiocb);}
- nginx aio机制详解
- nginx机制详解
- Linux AIO机制
- Linux AIO机制
- Linux AIO机制
- 【转】Linux AIO机制
- MySQL数据库InnoDB存储引擎 异步IO(AIO)实现机制详解
- Java BIO NIO AIO 详解
- NIO和AIO对比详解
- nginx 0.8.x中linux aio实现
- nginx 0.8.x中linux aio实现
- 一、BIO、NIO、AIO通信机制理解
- AIO
- aio
- AIO
- AIO
- AIO
- java io bio nio aio 详解
- 使用perl创建Excel表格统计数据
- redis hashTable实现细节(1)
- Flex里的fx、mx和s命名空间
- 斗地主算法逻辑中的天之道
- CentOS中安装gcc编译器
- nginx aio机制详解
- 通过端口 1433 连接到主机 127.0.0.1 的 TCP/IP 连接失败。错误:“connect timed out。"
- MySpace架构演进
- c#调用c++的ocx控件传递数组
- 消息中间件的比较-转载
- 博客菜鸟
- OnScrollListener回调分析
- java中如何对JFrame进行设置背景颜色和背景图片
- SQL语句中IN的用法