MYSQL中对信号的处理(SIGTERM,SIGQUIT,SIGHUP等)
发表于:2025-02-02 作者:千家信息网编辑
千家信息网最后更新 2025年02月02日,原创,因为LINUX系统编程水平有限某些用词不当请指出一、信号处理以及多线程先信号处理基础知识在LINUX中信号是一种由内核处理的一种软中断机制,他满足简单、不能携带大量信息、并且要满足一定条件才会发
千家信息网最后更新 2025年02月02日MYSQL中对信号的处理(SIGTERM,SIGQUIT,SIGHUP等)原创,因为LINUX系统编程水平有限某些用词不当请指出
一、信号处理以及多线程先信号处理基础知识
在LINUX中信号是一种由内核处理的一种软中断机制,他满足简单、不能携带大量信息、并且要满足一定条件才会发送等特征。
信号会经历产生-->阻塞信号集-->未决信号集-->信号递达-->信号处理方式
首先信号的产生可以有多种方式比如我们经常用的kill命名,下面将一些kill 中常用信号列举一下并且给出默认处理方式
(摘取自邢文鹏LINUX讲义)
Ctrl+c 2)SIGINT
Ctrl+\ 3)SIGQUIT
Ctrl+z 4)SIGTSTP
当然还有很多其他触发方式比如硬件异常,raise函数,abort函数,alarm函数等等。
其次是阻塞信号集,阻塞信号集能够对想除(9/19号信号以外)的信号进行屏蔽,如果屏蔽后信号自然不会到达递达状态,也就谈不上
处理了。我们通过sigprocmask函数进行阻塞信号集的设置,但之前必须要设置sigset_t 集合,通过sigaddset sigdelset sigemptyset
sigfillset等函数设置。
未决信号集是不能被操作的,只能被获取通过sigpending函数获取,但是他和阻塞信号集一起可以控制信号的递达
信号递达后就需要处理信号,默认的行为上面都列举了,但是信号(9/19号信号以外)是可以被捕获改变其处理方式的,我们可以自定义函数
作为某个信号的处理方式,这可以通过signal函数和sigaction函数进行捕获和处理,sigaction函数相对复杂需要有一个struct sigaction的
结构体变量,其中包含了sa_handler\sa_mask\sa_flags\sa_siaction 成员,这里不做解释可以自行查看LINUX man page
上面是单进程下的信号处理方式,在多线程下,线程之间公用处理方式,但是可以有不同的信号屏蔽集,在多线程下一般采用设置统一的信号
屏蔽字和信号处理方式使用pthread_mask函数继承到各个线程,同时使用sigwait/sigwaitinfo等函数设置一个单独的信号处理线程来进行统一
处理,MYSQL就是这样处理的。
二、MYSQL中的信号处理
首先我们可以发现MYSQL中有一个单独的signal处理线程
| 36 | 1927 | sql/signal_handler | NULL | BACKGROUND | NULL | NULL |
这个线程对整个MYSQLD进程的信号进行统一的处理,特别是涉及到SIGTERM,SIGQUIT,SIGHUP等信号的处理。
下面从源码触发我们来分析一下
1、信号初始化
void my_init_signals()函数
下面我们将一些关于信号处理的源码放出来进行解释
信号,通过一个专门的线程来处理这几个信号。同时很多信号也重新捕获改变了其
处理方式,详见上面解释。
2、信号处理线程
start_signal_handler-->signal_hand 来建立信号处理线程。
我们重点关注signal_hand这个回调函数,下面是一些源码和解释
这里我们看到很多我们关心的东西:
kill/kill -15/kill -SIGTERM做什么:
他们都是一样的都是SIGTERM信号MYSQL关闭所有活跃的连接同时干净的关闭innodb,我通过gdb确实看到了innodb关闭函数的调用,
这很容易我只要断点打到innobase_shutdown_for_mysql(),同时kill mysqldpid即可
和上面一样,这在源码中清楚的看到了
kill -1/kill -SIGHUP做什么:
源码解释中说了做
reload_acl_and_cache(NULL,(REFRESH_LOG | REFRESH_TABLES | REFRESH_FAST |
REFRESH_GRANT | REFRESH_THREADS | REFRESH_HOSTS),
NULL, ?_used); // Flush logs
函数调用关于参数2
@param options What should be reset/reloaded (tables, privileges, slave...)
我们可以看到这样的解释,那么
REFRESH_LOG | REFRESH_TABLES | REFRESH_FAST |REFRESH_GRANT | REFRESH_THREADS | REFRESH_HOSTS
代表什么,明显他们是位图方式,他们代表的东西在源码中有解释如下:
当然大家千万不要直接kill -9这个信号不能被屏蔽也不能被捕获,而是强制终止进程这个时候innodb不可能调用
innobase_shutdown_for_mysql来干净的关闭MYSQLD。
作者微信:
一、信号处理以及多线程先信号处理基础知识
在LINUX中信号是一种由内核处理的一种软中断机制,他满足简单、不能携带大量信息、并且要满足一定条件才会发送等特征。
信号会经历产生-->阻塞信号集-->未决信号集-->信号递达-->信号处理方式
首先信号的产生可以有多种方式比如我们经常用的kill命名,下面将一些kill 中常用信号列举一下并且给出默认处理方式
(摘取自邢文鹏LINUX讲义)
点击(此处)折叠或打开
- 1) SIGHUP:当用户退出shell时,由该shell启动的所有进程将收到这个信号,默认动作为终止进程
- 2)SIGINT:当用户按下了<Ctrl+C>组合键时,用户终端向正在运行中的由该终端启动的程序发出此信号。默认动
- 作为终止里程。
- 3)SIGQUIT:当用户按下<ctrl+\>组合键时产生该信号,用户终端向正在运行中的由该终端启动的程序发出些信
- 号。默认动作为终止进程。
- 4)SIGILL:CPU检测到某进程执行了非法指令。默认动作为终止进程并产生core文件
- 5)SIGTRAP:该信号由断点指令或其他 trap指令产生。默认动作为终止里程 并产生core文件。
- 6 ) SIGABRT:调用abort函数时产生该信号。默认动作为终止进程并产生core文件。
- 7)SIGBUS:非法访问内存地址,包括内存对齐出错,默认动作为终止进程并产生core文件。
- 8)SIGFPE:在发生致命的运算错误时发出。不仅包括浮点运算错误,还包括溢出及除数为0等所有的算法错误。默
- 认动作为终止进程并产生core文件。
- 9)SIGKILL:无条件终止进程。本信号不能被忽略,处理和阻塞。默认动作为终止进程。它向系统管理员提供了可
- 以杀死任何进程的方法。
- 10)SIGUSE1:用户定义 的信号。即程序员可以在程序中定义并使用该信号。默认动作为终止进程。
- 11)SIGSEGV:指示进程进行了无效内存访问。默认动作为终止进程并产生core文件。
- 12)SIGUSR2:这是另外一个用户自定义信号 ,程序员可以在程序中定义 并使用该信号。默认动作为终止进程。1
- 13)SIGPIPE:Broken pipe向一个没有读端的管道写数据。默认动作为终止进程。
- 14) SIGALRM:定时器超时,超时的时间 由系统调用alarm设置。默认动作为终止进程。
- 15)SIGTERM:程序结束信号,与SIGKILL不同的是,该信号可以被阻塞和终止。通常用来要示程序正常退出。执行
- shell命令Kill时,缺省产生这个信号。默认动作为终止进程。
- 16)SIGCHLD:子进程结束时,父进程会收到这个信号。默认动作为忽略这个信号。
- 17)SIGCONT:停止进程的执行。信号不能被忽略,处理和阻塞。默认动作为终止进程。
- 18)SIGTTIN:后台进程读终端控制台。默认动作为暂停进程。
- 19)SIGTSTP:停止进程的运行。按下<ctrl+z>组合键时发出这个信号。默认动作为暂停进程。
- 21)SIGTTOU:该信号类似于SIGTTIN,在后台进程要向终端输出数据时发生。默认动作为暂停进程。
- 22)SIGURG:套接字上有紧急数据时,向当前正在运行的进程发出些信号,报告有紧急数据到达。如网络带外数据
- 到达,默认动作为忽略该信号。
- 23)SIGXFSZ:进程执行时间超过了分配给该进程的CPU时间 ,系统产生该信号并发送给该进程。默认动作为终止
- 进程。
- 24)SIGXFSZ:超过文件的最大长度设置。默认动作为终止进程。
- 25)SIGVTALRM:虚拟时钟超时时产生该信号。类似于SIGALRM,但是该信号只计算该进程占用CPU的使用时间。默
- 认动作为终止进程。
- 26)SGIPROF:类似于SIGVTALRM,它不公包括该进程占用CPU时间还包括执行系统调用时间。默认动作为终止进
- 程。
- 27)SIGWINCH:窗口变化大小时发出。默认动作为忽略该信号。
- 28)SIGIO:此信号向进程指示发出了一个异步IO事件。默认动作为忽略。
- 29)SIGPWR:关机。默认动作为终止进程。
- 30)SIGSYS:无效的系统调用。默认动作为终止进程并产生core文件。
- 31)SIGRTMIN~(64)SIGRTMAX:LINUX的实时信号,它们没有固定的含义(可以由用户自定义)。所有的实时信
- 号的默认动作都为终止进程
Ctrl+c 2)SIGINT
Ctrl+\ 3)SIGQUIT
Ctrl+z 4)SIGTSTP
当然还有很多其他触发方式比如硬件异常,raise函数,abort函数,alarm函数等等。
其次是阻塞信号集,阻塞信号集能够对想除(9/19号信号以外)的信号进行屏蔽,如果屏蔽后信号自然不会到达递达状态,也就谈不上
处理了。我们通过sigprocmask函数进行阻塞信号集的设置,但之前必须要设置sigset_t 集合,通过sigaddset sigdelset sigemptyset
sigfillset等函数设置。
未决信号集是不能被操作的,只能被获取通过sigpending函数获取,但是他和阻塞信号集一起可以控制信号的递达
信号递达后就需要处理信号,默认的行为上面都列举了,但是信号(9/19号信号以外)是可以被捕获改变其处理方式的,我们可以自定义函数
作为某个信号的处理方式,这可以通过signal函数和sigaction函数进行捕获和处理,sigaction函数相对复杂需要有一个struct sigaction的
结构体变量,其中包含了sa_handler\sa_mask\sa_flags\sa_siaction 成员,这里不做解释可以自行查看LINUX man page
上面是单进程下的信号处理方式,在多线程下,线程之间公用处理方式,但是可以有不同的信号屏蔽集,在多线程下一般采用设置统一的信号
屏蔽字和信号处理方式使用pthread_mask函数继承到各个线程,同时使用sigwait/sigwaitinfo等函数设置一个单独的信号处理线程来进行统一
处理,MYSQL就是这样处理的。
二、MYSQL中的信号处理
首先我们可以发现MYSQL中有一个单独的signal处理线程
| 36 | 1927 | sql/signal_handler | NULL | BACKGROUND | NULL | NULL |
这个线程对整个MYSQLD进程的信号进行统一的处理,特别是涉及到SIGTERM,SIGQUIT,SIGHUP等信号的处理。
下面从源码触发我们来分析一下
1、信号初始化
void my_init_signals()函数
下面我们将一些关于信号处理的源码放出来进行解释
点击(此处)折叠或打开
- /*
- SA_RESETHAND resets handler action to default when entering handler.
- SA_NODEFER allows receiving the same signal during handler.
- E.g. SIGABRT during our signal handler will dump core (default action).
- */
- //这里将一些列如段错误、浮点数例外、总线错误、CPU非法指令等信号的默认处理
- //方式进行修改,修改为handle_fatal_signal函数调用,这个函数应该是打印一些
- //出错时候的状态信息等,我没有仔细看这个回调函数
- sa.sa_flags= SA_RESETHAND | SA_NODEFER;
- sa.sa_handler= handle_fatal_signal;
- // Treat all these as fatal and handle them.
- (void) sigaction(SIGSEGV, &sa, NULL);
- (void) sigaction(SIGABRT, &sa, NULL);
- (void) sigaction(SIGBUS, &sa, NULL);
- (void) sigaction(SIGILL, &sa, NULL);
- (void) sigaction(SIGFPE, &sa, NULL);
- }
- // Ignore SIGPIPE and SIGALRM
- //这里忽略掉管道错误和定时器信号
- sa.sa_flags= 0;
- sa.sa_handler= SIG_IGN;
- (void) sigaction(SIGPIPE, &sa, NULL);
- (void) sigaction(SIGALRM, &sa, NULL);
- //自定义信号,从注释来看是终止socket通信的
- //回调函数为empty_signal_handler
- // SIGUSR1 is used to interrupt the socket listener.
- sa.sa_handler= empty_signal_handler;
- (void) sigaction(SIGUSR1, &sa, NULL);
- //这里估计是什么特殊处理因为SIGTERM、SIGHUP已经在后面设置了
- //阻塞,应该和平台有关
- // Fix signals if ignored by parents (can happen on Mac OS X).
- sa.sa_handler= SIG_DFL;
- (void) sigaction(SIGTERM, &sa, NULL);
- (void) sigaction(SIGHUP, &sa, NULL);
- //下面开始设置我们的阻塞信号集通过pthread_sigmask生效
- //要阻塞SIGQUIT、SIGHUP、SIGTERM、SIGTSTP等信号
- //都是一些常用的可以终止进程的信号
- sigset_t set;
- (void) sigemptyset(&set);
- /*
- Block SIGQUIT, SIGHUP and SIGTERM.
- The signal handler thread does sigwait() on these.
- */
- (void) sigaddset(&set, SIGQUIT);
- (void) sigaddset(&set, SIGHUP);
- (void) sigaddset(&set, SIGTERM);
- (void) sigaddset(&set, SIGTSTP);
- /*
- Block SIGINT unless debugging to prevent Ctrl+C from causing
- unclean shutdown of the server.
- */
- if (!(test_flags & TEST_SIGINT))
- (void) sigaddset(&set, SIGINT);
- pthread_sigmask(SIG_SETMASK, &set, NULL);
信号,通过一个专门的线程来处理这几个信号。同时很多信号也重新捕获改变了其
处理方式,详见上面解释。
2、信号处理线程
start_signal_handler-->signal_hand 来建立信号处理线程。
我们重点关注signal_hand这个回调函数,下面是一些源码和解释
点击(此处)折叠或打开
- extern "C" void *signal_hand(void *arg MY_ATTRIBUTE((unused)))
- {
- my_thread_init();
- //这里设置sigset_t信号集合,并将SIGTERM/SIGQUIT/SIGHUP设置
- sigset_t set;
- (void) sigemptyset(&set);
- (void) sigaddset(&set, SIGTERM);
- (void) sigaddset(&set, SIGQUIT);
- (void) sigaddset(&set, SIGHUP);
- .....MUTEX相关不考虑
- for (;;)
- {
- int sig;
- while (sigwait(&set, &sig) == EINTR) //调用sigwait堵塞捕获信号
- {}
- if (cleanup_done)
- {
- my_thread_end();
- my_thread_exit(0); // Safety
- return NULL; // Avoid compiler warnings
- }
- switch (sig) { //下面的判断非常重要如果是SIGTERM和SIGQUIT会
- //pthread_kill终止所有活动的会话线程每个线程将收到
- //SIGUSR1信号然后调用empty_signal_handler回调函数进行
- //处理然后close_connections然后my_thread_end关闭,
- //这里是否调用innodb关闭操作,可以通过GDB打断点
- //到innobase_shutdown_for_mysql函数上,我做了
- //测试确实调用了后面会给出,也就是说kill SIGTERM和
- //SIGQUIT是安全的,因为他们调用innodb关闭函数正常
- //的关闭了innodb
- case SIGTERM:
- case SIGQUIT:
- // Switch to the file log message processing.
- query_logger.set_handlers((log_output_options != LOG_NONE) ?
- LOG_FILE : LOG_NONE);
- DBUG_PRINT("info", ("Got signal: %d abort_loop: %d", sig, abort_loop));
- if (!abort_loop)
- {
- abort_loop= true; // Mark abort for threads.
- /*
- Kill the socket listener.
- The main thread will then set socket_listener_active= false,
- and wait for us to finish all the cleanup below.
- */
- mysql_mutex_lock(&LOCK_socket_listener_active);
- while (socket_listener_active)
- {
- DBUG_PRINT("info",("Killing socket listener"));
- if (pthread_kill(main_thread_id, SIGUSR1))
- {
- DBUG_ASSERT(false);
- break;
- }
- mysql_cond_wait(&COND_socket_listener_active,
- &LOCK_socket_listener_active);
- }
- mysql_mutex_unlock(&LOCK_socket_listener_active);
- close_connections();
- }
- my_thread_end();
- my_thread_exit(0);
- return NULL; // Avoid compiler warnings
- break;
- case SIGHUP: //这里也是大家很关心的关于SIGHUP到底了做了什么
- //我们可以看到他调用reload_acl_and_cache来刷新
- //一个东西,具体后面给出,并没有其他什么操作
- //这个SIGHUP信号的行为完全被改变了
- if (!abort_loop)
- {
- int not_used;
- mysql_print_status(); // Print some debug info
- reload_acl_and_cache(NULL,
- (REFRESH_LOG | REFRESH_TABLES | REFRESH_FAST |
- REFRESH_GRANT | REFRESH_THREADS | REFRESH_HOSTS),
- NULL, ¬_used); // Flush logs
- // Reenable query logs after the options were reloaded.
- query_logger.set_handlers(log_output_options);
- }
- break;
- default:
- break; /* purecov: tested */
- }
- }
- return NULL; /* purecov: deadcode */
- }
这里我们看到很多我们关心的东西:
kill/kill -15/kill -SIGTERM做什么:
他们都是一样的都是SIGTERM信号MYSQL关闭所有活跃的连接同时干净的关闭innodb,我通过gdb确实看到了innodb关闭函数的调用,
这很容易我只要断点打到innobase_shutdown_for_mysql(),同时kill mysqldpid即可
点击(此处)折叠或打开
- (gdb) bt
- #0 innobase_shutdown_for_mysql () at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/srv/srv0start.cc:2785
- #1 0x00000000019a0f9c in innobase_end (hton=0x2e9a450, type=HA_PANIC_CLOSE) at /root/mysql5.7.14/percona-server-5.7.14-7/storage/innobase/handler/ha_innodb.cc:4360
- #2 0x0000000000f62215 in ha_finalize_handlerton (plugin=0x2fe31a0) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/handler.cc:813
- #3 0x00000000015d3179 in plugin_deinitialize (plugin=0x2fe31a0, ref_check=true) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_plugin.cc:995
- #4 0x00000000015d3562 in reap_plugins () at /root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_plugin.cc:1077
- #5 0x00000000015d54c7 in plugin_shutdown () at /root/mysql5.7.14/percona-server-5.7.14-7/sql/sql_plugin.cc:1845
- #6 0x0000000000ebf5eb in clean_up (print_message=true) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/mysqld.cc:1336
- #7 0x0000000000ec6c7e in mysqld_main (argc=56, argv=0x2e98768) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/mysqld.cc:5358
- #8 0x0000000000ebd404 in main (argc=9, argv=0x7fffffffe418) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/main.cc:25
和上面一样,这在源码中清楚的看到了
kill -1/kill -SIGHUP做什么:
源码解释中说了做
reload_acl_and_cache(NULL,(REFRESH_LOG | REFRESH_TABLES | REFRESH_FAST |
REFRESH_GRANT | REFRESH_THREADS | REFRESH_HOSTS),
NULL, ?_used); // Flush logs
函数调用关于参数2
@param options What should be reset/reloaded (tables, privileges, slave...)
我们可以看到这样的解释,那么
REFRESH_LOG | REFRESH_TABLES | REFRESH_FAST |REFRESH_GRANT | REFRESH_THREADS | REFRESH_HOSTS
代表什么,明显他们是位图方式,他们代表的东西在源码中有解释如下:
点击(此处)折叠或打开
- #define REFRESH_GRANT 1 /* Refresh grant tables */
- #define REFRESH_LOG 2 /* Start on new log file */
- #define REFRESH_TABLES 4 /* close all tables */
- #define REFRESH_HOSTS 8 /* Flush host cache */
- #define REFRESH_STATUS 16 /* Flush status variables */
- #define REFRESH_THREADS 32 /* Flush thread cache */
- #define REFRESH_SLAVE 64 /* Reset master info and restart slave
- thread */
- #define REFRESH_MASTER 128 /* Remove all bin logs in the index
- and truncate the index */
- #define REFRESH_ERROR_LOG 256 /* Rotate only the erorr log */
- #define REFRESH_ENGINE_LOG 512 /* Flush all storage engine logs */
- #define REFRESH_BINARY_LOG 1024 /* Flush the binary log */
- #define REFRESH_RELAY_LOG 2048 /* Flush the relay log */
- #define REFRESH_GENERAL_LOG 4096 /* Flush the general log */
- #define REFRESH_SLOW_LOG 8192 /* Flush the slow query log */
当然大家千万不要直接kill -9这个信号不能被屏蔽也不能被捕获,而是强制终止进程这个时候innodb不可能调用
innobase_shutdown_for_mysql来干净的关闭MYSQLD。
作者微信:
信号
进程
处理
动作
函数
线程
方式
阻塞
信号处理
文件
用户
程序
解释
时间
系统
终端
错误
数据
源码
同时
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
液晶电视软件开发
徐州融联网络技术有限公司
合肥服务器导轨回收
上海联合互联网科技
with改时间服务器错误
网络安全是为了保障
美军网络安全防护图片
杭州童尚网络技术有限公司
西安网安网络技术有限公司
软件开发的可转换模型
v8通讯服务器管理器被关
大学数据库如何实现
jdbc配数据库连接池
数据库参看参考文献
linux服务器主从管理
用VB对SQL数据库中排序
在线课程网络安全措施
数据库中比较大小
雷沃谷神割台服务器配件
网络安全系统的技术实施方案
网络技术系统
数据库不能有重复数据库
商丘市网络安全作品征集投票
数据库恢复要多长时间
保证网络安全的方法和技术
漯河企业财务软件开发
怎样查询服务器是否续费
大数据服务器品牌
服务器人员面试题
SDH设备 网管 服务器 架构