onesignal php,PHP FPM源代码反刍品味之五:信号signal处理

unix 的信号signal常用于进程管理.

比如管理员或者操作系统通过向master进程实现重启和关闭服务.

master进程通过向worker进程发信号管理worker进程.

通常会在进程自定义信号处理函数,处理相关的逻辑.

自定义信号处理函数,从使用者的角度看,很简单,有点像快捷键的定制.

FPM 信号处理有以下几个特点:

master进程,不是直接处理信号,而是通过socketpair创建一个管道,把信号转换一个字符,写到管道里,master进程事件处理无限循环,读取到这个字符时,调用对应的函数.

socketpair,通常管道不同进程通信,而这里确是在同一个进程内部通信,左手交右手,感觉多此一举.

这样做的好处是: 避免信号处理函数与事件处理逻辑同时运行的情况.

注意worker 进程没有用到这个socketpair管道.

worker 进程的信号处理常见的方式,直接绑定处理函数.

处理过程: sig_soft_quit -> fpm_php_soft_quit -> fcgi_set_in_shutdown

fcgi_set_in_shutdown 函数很简单 就是设置in_shutdown这个全局的worker进程开关

worker进程无限循环时,每次都会检查这个开关, in_shutdown=1 时,跳出循环,优雅退出.

源码注释说明:

//fpm_signals.c

#include "fpm_config.h"

...

//整数数组,存放socketpair创建的管道两端文件句柄

static int sp[2];

...

//worker进程信号处理函数

static void sig_soft_quit(int signo) /* {{{ */

{

int saved_errno = errno;

/* closing fastcgi listening socket will force fcgi_accept() exit immediately */

close(0);

if (0 > socket(AF_UNIX, SOCK_STREAM, 0)) {

zlog(ZLOG_WARNING, "failed to create a new socket");

}

fpm_php_soft_quit();

errno = saved_errno;

}

//master进程信号处理函数

static void sig_handler(int signo) /* {{{ */

{

//C99 的数组初始化语法

//信号整数和字符的对应关系.

static const char sig_chars[NSIG + 1] = {

[SIGTERM] = 'T',

[SIGINT] = 'I',

[SIGUSR1] = '1',

[SIGUSR2] = '2',

[SIGQUIT] = 'Q',

[SIGCHLD] = 'C'

};

char s;

int saved_errno;

if (fpm_globals.parent_pid != getpid()) {

return;

}

saved_errno = errno;

s = sig_chars[signo];

//信号对应的字符写到管道

write(sp[1], &s, sizeof(s));

errno = saved_errno;

}

int fpm_signals_init_main() /* {{{ */

{

struct sigaction act;

//创建socketpair管道,管道两端的文件句柄fd 放在数组sp里

if (0 > socketpair(AF_UNIX, SOCK_STREAM, 0, sp)) {

zlog(ZLOG_SYSERROR, "failed to init signals: socketpair()");

return -1;

}

if (0 > fd_set_blocked(sp[0], 0) || 0 > fd_set_blocked(sp[1], 0)) {

zlog(ZLOG_SYSERROR, "failed to init signals: fd_set_blocked()");

return -1;

}

if (0 > fcntl(sp[0], F_SETFD, FD_CLOEXEC) || 0 > fcntl(sp[1], F_SETFD, FD_CLOEXEC)) {

zlog(ZLOG_SYSERROR, "falied to init signals: fcntl(F_SETFD, FD_CLOEXEC)");

return -1;

}

memset(&act, 0, sizeof(act));

act.sa_handler = sig_handler; //所有信号使用同一个处理函数

sigfillset(&act.sa_mask);

if (0 > sigaction(SIGTERM, &act, 0) ||

0 > sigaction(SIGINT, &act, 0) ||

0 > sigaction(SIGUSR1, &act, 0) ||

0 > sigaction(SIGUSR2, &act, 0) ||

0 > sigaction(SIGCHLD, &act, 0) ||

0 > sigaction(SIGQUIT, &act, 0)) {

zlog(ZLOG_SYSERROR, "failed to init signals: sigaction()");

return -1;

}

return 0;

}

int fpm_signals_init_child()

{

struct sigaction act, act_dfl;

memset(&act, 0, sizeof(act));

memset(&act_dfl, 0, sizeof(act_dfl));

act.sa_handler = &sig_soft_quit;

act.sa_flags |= SA_RESTART;

act_dfl.sa_handler = SIG_DFL; //系统默认动作

//worker 进程不使用socketpair创建的管道

close(sp[0]);

close(sp[1]);

if (0 > sigaction(SIGTERM, &act_dfl, 0) ||

0 > sigaction(SIGINT, &act_dfl, 0) ||

0 > sigaction(SIGUSR1, &act_dfl, 0) ||

0 > sigaction(SIGUSR2, &act_dfl, 0) ||

0 > sigaction(SIGCHLD, &act_dfl, 0) ||

0 > sigaction(SIGQUIT, &act, 0)) {

zlog(ZLOG_SYSERROR, "failed to init child signals: sigaction()");

return -1;

}

return 0;

}

int fpm_signals_get_fd()

{

return sp[0];

}

master 进程的信号被写到了管道,管道另一端的处理:

//fpm_events.c

static void fpm_got_signal(struct fpm_event_s *ev, short which, void *arg)

{

char c;

int res, ret;

int fd = ev->fd;

do {

do {

res = read(fd, &c, 1);

} while (res == -1 && errno == EINTR);

if (res <= 0) {

if (res < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {

zlog(ZLOG_SYSERROR, "unable to read from the signal pipe");

}

return;

}

//依据读取到的字符做处理

switch (c) {

...

case 'Q' : /* SIGQUIT */

zlog(ZLOG_DEBUG, "received SIGQUIT");

zlog(ZLOG_NOTICE, "Finishing ...");

fpm_pctl(FPM_PCTL_STATE_FINISHING, FPM_PCTL_ACTION_SET);

break;

case '1' : /* SIGUSR1 */

zlog(ZLOG_DEBUG, "received SIGUSR1");

if (0 == fpm_stdio_open_error_log(1)) {

zlog(ZLOG_NOTICE, "error log file re-opened");

} else {

zlog(ZLOG_ERROR, "unable to re-opened error log file");

}

ret = fpm_log_open(1);

if (ret == 0) {

zlog(ZLOG_NOTICE, "access log file re-opened");

} else if (ret == -1) {

zlog(ZLOG_ERROR, "unable to re-opened access log file");

}

/* else no access log are set */

break;

case '2' : /* SIGUSR2 */

zlog(ZLOG_DEBUG, "received SIGUSR2");

zlog(ZLOG_NOTICE, "Reloading in progress ...");

fpm_pctl(FPM_PCTL_STATE_RELOADING, FPM_PCTL_ACTION_SET);

break;

}

if (fpm_globals.is_child) {

break;

}

} while (1);

return;

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/363971.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【leetcode】657. Robot Return to Origin

Algorithm 【leetcode】657. Robot Return to Origin https://leetcode.com/problems/robot-return-to-origin/ 1&#xff09;problem There is a robot starting at position (0, 0), the origin, on a 2D plane. Given a sequence of its moves, judge if this robot ends up…

HTTP Developer's Handbook Part V: Security 读书笔记

Thus, the SSL handshake takes place once a TCP connection has been established between the Web client and Web server and before the initial HTTP request is sent.转载于:https://www.cnblogs.com/huyi/archive/2010/11/06/1870686.html

Spring 3.2矩阵变量是什么? - 第1部分

Spring 3.2引入了对处理“矩阵变量”的支持&#xff0c;并且可能像大多数开发人员一样&#xff0c;我从未听说过它们。 因此&#xff0c;经过一番研究&#xff0c;我对这个博客的了解是什么&#xff0c;以及您可以如何使用它们。 和往常一样&#xff0c;如果我错了&#xff0c;…

登录界面点击登录后如何延迟提示成功的div的显示时间并跳转

需求&#xff1a; 在登录页面点击sign in跳转到下个页面之前&#xff0c;我需要显示成功的窗口2秒然后自动关闭 那我们来研究下setTimeout: 关于这个setTimeout首先下面的代码实现的是两秒之后再显示SuccLogin窗体。 setTimeout(function () {$(".SuccLogin").sho…

MSN和QQ文件传输速度解析

基本上就是说msn传输文件是使用TCP&#xff0c;而QQ使用UDP&#xff0c;这就是两者传输速率的区别…… 发现很多情况下&#xff0c;msn传输文件比qq要慢&#xff0c;倒不是说msn没有快的时候&#xff0c;但是大部分的时候是真的比QQ慢&#xff0c;连我这种神经比较大条的人都注…

Java 队列清空,如何清空Actor死信队列 - java

我有一个用例&#xff0c;我想清空我的Akka演员的死信队列。我的本地演员与远程演员交谈&#xff0c;并定期向其发送一些数据。我认为这些会排队等待&#xff0c;因为当远程角色可用时&#xff0c;会发生大量事件。是否可以限制此队列的大小&#xff1f;甚至更好地访问它&#…

[minecraft]mcCoder制作有感

mcCoder是一个minecraft-forge-mod制作库&#xff0c;力图让mod制作者可以更简单的制作mod&#xff0c;减少mod制作者的mod制作难度。 在GitHub上关注这个项目&#xff1a; 原理 mcCoder主要使用&#xff0c;JSR 269 Pluggable Annotation Processing API&#xff0c;辅以使用a…

关于导入oracle10g的数据到sqlserver2005里的方案总结

由于项目需求&#xff0c;现需要将oracle的数据全部导入到sqlserver中&#xff0c;一下算是自己的总结小计吧。 sqlserver有自己的导入数据的功能&#xff0c;其中就有提供两种方式从oracle导入数据。 两种方式就不仔细说了&#xff0c;可以google到的。 遇到的问题如下&…

js文件处理File

支持File API的浏览器有IE10 ,Firefox3.5 &#xff0c;Opera10.6 &#xff0c;Safari5 ,Chrome。 1.在表单元素上<input type"fiel" name"file" id"file" />&#xff0c;可以选择一个或多个文件&#xff0c;通过获取文件元素对象的集合fi…

在IntelliJ IDEA中为不同的数据源着色

IntelliJ IDEA中的数据库插件是使用数据库中数据的有用工具。 只要我们有了JDBC驱动程序来连接数据库&#xff0c;就可以配置数据源。 然后&#xff0c;我们可以运行查询&#xff0c;检查表的内容并使用数据库工具窗口更改数据。 具有多个数据源&#xff08;例如开发和测试环境…

.NET Framework 如何:提高性能

以下编程做法可以节省内存和改善设备应用程序的性能。 使用 Windows 窗体和图形节省内存 对提供 BeginUpdate 和 EndUpdate 方法的控件使用这两种方法&#xff0c;提供这两种方法的控件包括 ComboBox、ListBox、ListView、ToolStripComboBox 和 TreeView。 重新定位控件时&…

[蓝桥杯]ALGO-185.算法训练_Trash Removal

题目描述&#xff1a; 代码如下&#xff1a; 1 #include <algorithm>2 #include <cstdio>3 #include <cstdlib>4 #include <cmath>5 #include <cstring>6 #include <iostream>7 #define INF 0x7fffffff8 using namespace std;9 10 typed…

php检测数组类型,javascript中通过哪些方法来检测数组类型?

typeof操作符。对于Function、String、Number、Undefined这几种类型的对象来说&#xff0c;不会有什么问题&#xff0c;但是针对Array的对象就没什么用途了&#xff1a;alert(typeof null); // "object"alert(typeof []); // "object"instanceof当只有一个…

值得记录的(一)

简要记录维护 jQuery 项目相关需求实现的细节&#xff0c;方便日后回顾。样式相关 flex 布局justify-content: flex-start; 和 justify-content: center;flex-wrap: wrap; 换行cursor: pointer; 手型的使用jQuery 左右移动 animate 使用 jQuery 实现左右按钮移动效果 - 类似…

跟踪异常–第4部分– Spring的邮件发件人

如果您阅读过本系列以前的任何博客&#xff0c;您可能会记得我正在开发一个小型但几乎具有工业实力的应用程序&#xff0c;该应用程序在日志文件中搜索异常。 您可能还记得&#xff0c;我现在有一个可以包含一堆结果的类&#xff0c;需要将其发送给感兴趣的任何人。 这将通过实…

从客户端...中检测到有潜在危险的 Request.Form 值

在.net中&#xff0c;Request时出现有HTML、Javascript等字符串时&#xff0c;系统会认为是危险值&#xff0c;运行显示“从客户端……中检测到有潜在危险的Request.Form值”这样的错。解决办法&#xff1a; &#xff08;1&#xff09; 在.aspx文件头中加入这句&#xff1a; …

php ci model条件查询,Laravel关系模型指定条件查询方法

对于关系模型来说&#xff0c;有时候我们需要甄别关联后结果&#xff0c;例如&#xff0c;班级和学生是一对多关联&#xff0c;我现在查询班级&#xff0c;但是想只显示正常状态&#xff0c;即状态为1的学生&#xff0c;因为有的学生从这个班级里面删除了&#xff0c;状态是4&a…

android 之 百度地图

简介 百度地图Android定位SDK为基于移动客户端开发LBS应用提供基础定位能力。 功能介绍 功能介绍&#xff1a; 地图展示&#xff1a;包括2D图、卫星图、3D图地图展示。 地图操作&#xff1a;提供控制平移、缩放、底图旋转、变换视角等地图相关操作的功能。 短串分享&#xff1a…

从javaagent迁移到JVMTI:我们的经验

当您需要从JVM内部收集数据时&#xff0c;您会发现自己很危险地接近Java虚拟机内部进行工作。 幸运的是&#xff0c;有一些方法可以避免被JVM实现细节所困扰。 Java之父没有给您提供过两个漂亮的工具供您使用。 在这篇文章中&#xff0c;我们将说明两种方法之间的差异&#xf…

浅谈HTML5中canvas中的beginPath()和closePath()的重要性

beginPath的作用很简单&#xff0c;就是开始一段新的路径&#xff0c;但在使用canvas绘图的过程中却非常重要 先来看一小段代码&#xff1a; var ctxdocument.getElementById("canvas").getContext("2d");ctx.beginPath();ctx.rect(150,150,100,100);ctx.…