if (ioctl(ngx_processes[s].channel[0], FIOASYNC, &on) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "ioctl(FIOASYNC) failed while spawning "%s"", name); ngx_close_channel(ngx_processes[s].channel, cycle->log); return NGX_INVALID_PID; } if (fcntl(ngx_processes[s].channel[0], F_SETOWN, ngx_pid) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "fcntl(F_SETOWN) failed while spawning "%s"", name); ngx_close_channel(ngx_processes[s].channel, cycle->log); return NGX_INVALID_PID; }
分析:
- 设置channel[0]的信号驱动异步I/O标志 ,FIOASYNC:该状态标志决定是否收取针对socket的异步I/O信号(SIGIO)
- 其与O_ASYNC文件状态标志等效,可通过fcntl的F_SETFL命令设置or清除
- F_SETOWN:用于指定接收SIGIO和SIGURG信号的socket属主(进程ID或进程组ID) 这里意思是指定Master进程接收SIGIO和SIGURG信号 ,
- SIGIO信号必须是在socket设置为信号驱动异步I/O才能产生,即上一步操作 SIGURG信号是在新的带外数据到达socket时产生的
FIOASYNC
toggles the O_ASYNC
flag (which is usually set in open(2)
or fcntl(2)
) for a file descriptor, which will ask the kernel to send SIGIO
or SIGPOLL
to the process when the file descriptor is ready for IO.
O_ASYNC
is not used often:
- it is extremely difficult to properly handle IO in signal handlers; they are best left as tiny as possible
- because signals interrupt the control flow of the program, they 'cost more' to run than standard system calls, such as
select(2)
orpoll(2)
- signals provide less information than other calls: they only report one fd ready vs many fds that might be ready.
The O_NONBLOCK
doesn't provide any notification to the user process that a fd is ready for read(2)
or write(2)
-- instead, it changes the behavior of read(2)
and write(2)
and similar calls to return immediately if the file descriptor isn't ready for reading or writing. O_NONBLOCK
is typically used in conjunction with select(2)
or poll(2)
or similar calls to guarantee that the main loop of a client or server won't block on one specific peer, and thus starve all its peers.
ioctl和FIOASYNC等价于fcntl和O_ASYNC。
ioctl和FIONBIO等价于fcntl和O_NONBLOCK。
FIOASYNC设置O_ASYNC标记,该标记决定fd可以IO时进程是否会收到SIGIO和SIGPOLL信号。
FIONBIO设置O_NONBLOCK标记,该标记会改变read,write和同类函数的行为,使得在fd还不能IO时立即返回而不是hang住。
后者经常跟select,poll等函数一起使用,使得主程序不会因为个别socket而影响其他。
一般来说使用select和poll结合非阻塞的文件指针可以对应大部分情况,但是某些时候 需要使用异步的文件指针。比如:如果一个函数处理数据,但是处理时间很长,在其处理的时候 我们需要运行这个函数的进程及时响应网络事件或者内核信号,这时就需要将其置为异步
对于socket来说,如果需要设置异步的话需要三个步骤
- 必须注册一个响应SIGIO的信号回调函数
- 通过fcntl设置F_SETOWN,使得socket属于某个进程
- 通过fcntl设置O——ASYNC将该socket设置为异步