PHP-FPM启动后,master进程会陷入event_loop(0)
中来管理维持worker进程,而fork出的worker进程会回到主函数开始循环接收、处理请求。一次请求能够总结为 请求接收、请求处理、请求结束 三个阶段,下面就详细来说一下。html
运行环境:Mac 10.14.2 + PHP 7.3.7git
accept()
会有惊群问题,在调用accept()
以前会对listen_socket加锁。惊群问题在Linux2.6版本中获得解决,内核在收到一个客户端链接时只会唤醒等待队列上的第一个进程。accept(listen_socket, (struct sockaddr *)&sa, &len)
从全链接队列中接受一个链接,若是队列中暂时没有则会一直阻塞着,这里的listen_socket
是在fcgi_listen()
中建立监听的。判断client_socket是否被容许:知足以下请求之一便可github
poll()
来监听client_socket上的可读事件,这里的while条件是while (ret < 0 && errno == EINTR);
EINTR错误是当阻塞中的poll()
被捕获到的信号中断所产生的错误,因此能够从新执行poll
系统调用。read()
数据并解析,消息传递大体以下。关于PHP如何实现FastCGI协议能够看下这篇文章。在上一阶段读取到请求数据后,worker进程接着会初始化输出相关的堆栈、初始化编译阶段用到的compiler_globals(CG宏)、执行阶段用到的executor_globals(EG宏)、执行每一个扩展的PHP_RINIT_FUNCTION函数 等等。segmentfault
讲到请求处理阶段就不得不提ZendVM,你们都知道PHP是解释型语言,ZendVM就是PHP的解释器,负责PHP的解析、执行。计算机理解不了PHP代码,可是ZendVM能够,对PHP而言,ZendVM就像是真正的“计算机“,这台“计算机“能够识别的指令就是本身事先定义好的opcode。在运行时,PHP会被编译为一系列opcode指令,ZendVM会逐个调用opcode对应的机器指令,最终完成PHP代码的运行。socket
register_shutdown_function()
注册的关闭函数通过以上的清理操做,worker进程就准备好接收处理下一个请求了。函数