原創(chuàng),因為LINUX系統(tǒng)編程水平有限某些用詞不當請指出
一、信號處理以及多線程先信號處理基礎知識
在LINUX中信號是一種由內(nèi)核處理的一種軟中斷機制,他滿足簡單、不能攜帶大量信息、并且要滿足一定條件才會發(fā)送等特征。
信號會經(jīng)歷產(chǎn)生-->阻塞信號集-->未決信號集-->信號遞達-->信號處理方式
首先信號的產(chǎn)生可以有多種方式比如我們經(jīng)常用的kill命名,下面將一些kill 中常用信號列舉一下并且給出默認處理方式
(摘取自邢文鵬LINUX講義)
點擊(此處)折疊或打開
我們提供的服務有:成都網(wǎng)站建設、網(wǎng)站建設、微信公眾號開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認證、沈丘ssl等。為上千家企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務,是有科學管理、有技術的沈丘網(wǎng)站制作公司
- 1) SIGHUP:當用戶退出shell時,由該shell啟動的所有進程將收到這個信號,默認動作為終止進程
- 2)SIGINT:當用戶按下了<Ctrl+C>組合鍵時,用戶終端向正在運行中的由該終端啟動的程序發(fā)出此信號。默認動
- 作為終止里程。
- 3)SIGQUIT:當用戶按下<ctrl+\>組合鍵時產(chǎn)生該信號,用戶終端向正在運行中的由該終端啟動的程序發(fā)出些信
- 號。默認動作為終止進程。
- 4)SIGILL:CPU檢測到某進程執(zhí)行了非法指令。默認動作為終止進程并產(chǎn)生core文件
- 5)SIGTRAP:該信號由斷點指令或其他 trap指令產(chǎn)生。默認動作為終止里程 并產(chǎn)生core文件。
- 6 ) SIGABRT:調(diào)用abort函數(shù)時產(chǎn)生該信號。默認動作為終止進程并產(chǎn)生core文件。
- 7)SIGBUS:非法訪問內(nèi)存地址,包括內(nèi)存對齊出錯,默認動作為終止進程并產(chǎn)生core文件。
- 8)SIGFPE:在發(fā)生致命的運算錯誤時發(fā)出。不僅包括浮點運算錯誤,還包括溢出及除數(shù)為0等所有的算法錯誤。默
- 認動作為終止進程并產(chǎn)生core文件。
- 9)SIGKILL:無條件終止進程。本信號不能被忽略,處理和阻塞。默認動作為終止進程。它向系統(tǒng)管理員提供了可
- 以殺死任何進程的方法。
- 10)SIGUSE1:用戶定義 的信號。即程序員可以在程序中定義并使用該信號。默認動作為終止進程。
- 11)SIGSEGV:指示進程進行了無效內(nèi)存訪問。默認動作為終止進程并產(chǎn)生core文件。
- 12)SIGUSR2:這是另外一個用戶自定義信號 ,程序員可以在程序中定義 并使用該信號。默認動作為終止進程。1
- 13)SIGPIPE:Broken pipe向一個沒有讀端的管道寫數(shù)據(jù)。默認動作為終止進程。
- 14) SIGALRM:定時器超時,超時的時間 由系統(tǒng)調(diào)用alarm設置。默認動作為終止進程。
- 15)SIGTERM:程序結束信號,與SIGKILL不同的是,該信號可以被阻塞和終止。通常用來要示程序正常退出。執(zhí)行
- shell命令Kill時,缺省產(chǎn)生這個信號。默認動作為終止進程。
- 16)SIGCHLD:子進程結束時,父進程會收到這個信號。默認動作為忽略這個信號。
- 17)SIGCONT:停止進程的執(zhí)行。信號不能被忽略,處理和阻塞。默認動作為終止進程。
- 18)SIGTTIN:后臺進程讀終端控制臺。默認動作為暫停進程。
- 19)SIGTSTP:停止進程的運行。按下<ctrl+z>組合鍵時發(fā)出這個信號。默認動作為暫停進程。
- 21)SIGTTOU:該信號類似于SIGTTIN,在后臺進程要向終端輸出數(shù)據(jù)時發(fā)生。默認動作為暫停進程。
- 22)SIGURG:套接字上有緊急數(shù)據(jù)時,向當前正在運行的進程發(fā)出些信號,報告有緊急數(shù)據(jù)到達。如網(wǎng)絡帶外數(shù)據(jù)
- 到達,默認動作為忽略該信號。
- 23)SIGXFSZ:進程執(zhí)行時間超過了分配給該進程的CPU時間 ,系統(tǒng)產(chǎn)生該信號并發(fā)送給該進程。默認動作為終止
- 進程。
- 24)SIGXFSZ:超過文件的最大長度設置。默認動作為終止進程。
- 25)SIGVTALRM:虛擬時鐘超時時產(chǎn)生該信號。類似于SIGALRM,但是該信號只計算該進程占用CPU的使用時間。默
- 認動作為終止進程。
- 26)SGIPROF:類似于SIGVTALRM,它不公包括該進程占用CPU時間還包括執(zhí)行系統(tǒng)調(diào)用時間。默認動作為終止進
- 程。
- 27)SIGWINCH:窗口變化大小時發(fā)出。默認動作為忽略該信號。
- 28)SIGIO:此信號向進程指示發(fā)出了一個異步IO事件。默認動作為忽略。
- 29)SIGPWR:關機。默認動作為終止進程。
- 30)SIGSYS:無效的系統(tǒng)調(diào)用。默認動作為終止進程并產(chǎn)生core文件。
- 31)SIGRTMIN~(64)SIGRTMAX:LINUX的實時信號,它們沒有固定的含義(可以由用戶自定義)。所有的實時信
- 號的默認動作都為終止進程
其次我們經(jīng)常的按鍵也可以產(chǎn)生
Ctrl+c 2)SIGINT
Ctrl+\ 3)SIGQUIT
Ctrl+z 4)SIGTSTP
當然還有很多其他觸發(fā)方式比如硬件異常,raise函數(shù),abort函數(shù),alarm函數(shù)等等。
其次是阻塞信號集,阻塞信號集能夠?qū)ο氤?9/19號信號以外)的信號進行屏蔽,如果屏蔽后信號自然不會到達遞達狀態(tài),也就談不上
處理了。我們通過sigprocmask函數(shù)進行阻塞信號集的設置,但之前必須要設置sigset_t 集合,通過sigaddset sigdelset sigemptyset
sigfillset等函數(shù)設置。
未決信號集是不能被操作的,只能被獲取通過sigpending函數(shù)獲取,但是他和阻塞信號集一起可以控制信號的遞達
信號遞達后就需要處理信號,默認的行為上面都列舉了,但是信號(9/19號信號以外)是可以被捕獲改變其處理方式的,我們可以自定義函數(shù)
作為某個信號的處理方式,這可以通過signal函數(shù)和sigaction函數(shù)進行捕獲和處理,sigaction函數(shù)相對復雜需要有一個struct sigaction的
結構體變量,其中包含了sa_handler\sa_mask\sa_flags\sa_siaction 成員,這里不做解釋可以自行查看LINUX man page
上面是單進程下的信號處理方式,在多線程下,線程之間公用處理方式,但是可以有不同的信號屏蔽集,在多線程下一般采用設置統(tǒng)一的信號
屏蔽字和信號處理方式使用pthread_mask函數(shù)繼承到各個線程,同時使用sigwait/sigwaitinfo等函數(shù)設置一個單獨的信號處理線程來進行統(tǒng)一
處理,MySQL就是這樣處理的。
二、MYSQL中的信號處理
首先我們可以發(fā)現(xiàn)MYSQL中有一個單獨的signal處理線程
| 36 | 1927 | sql/signal_handler | NULL | BACKGROUND | NULL | NULL |
這個線程對整個MYSQLD進程的信號進行統(tǒng)一的處理,特別是涉及到SIGTERM,SIGQUIT,SIGHUP等信號的處理。
下面從源碼觸發(fā)我們來分析一下
1、信號初始化
void my_init_signals()函數(shù)
下面我們將一些關于信號處理的源碼放出來進行解釋
- /*
- 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).
- */
- //這里將一些列如段錯誤、浮點數(shù)例外、總線錯誤、CPU非法指令等信號的默認處理
- //方式進行修改,修改為handle_fatal_signal函數(shù)調(diào)用,這個函數(shù)應該是打印一些
- //出錯時候的狀態(tài)信息等,我沒有仔細看這個回調(diào)函數(shù)
- 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通信的
- //回調(diào)函數(shù)為empty_signal_handler
- // SIGUSR1 is used to interrupt the socket listener.
- sa.sa_handler= empty_signal_handler;
- (void) sigaction(SIGUSR1, &sa, NULL);
-
-
- //這里估計是什么特殊處理因為SIGTERM、SIGHUP已經(jīng)在后面設置了
- //阻塞,應該和平臺有關
- // 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);
到這里我們發(fā)現(xiàn)MYSQL線程實際上屏蔽了SIGQUIT、SIGHUP、SIGTERM、SIGTSTP
信號,通過一個專門的線程來處理這幾個信號。同時很多信號也重新捕獲改變了其
處理方式,詳見上面解釋。
2、信號處理線程
start_signal_handler-->signal_hand 來建立信號處理線程。
我們重點關注signal_hand這個回調(diào)函數(shù),下面是一些源碼和解釋
- 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) //調(diào)用sigwait堵塞捕獲信號
- {}
- if (cleanup_done)
- {
- my_thread_end();
- my_thread_exit(0); // Safety
- return NULL; // Avoid compiler warnings
- }
- switch (sig) { //下面的判斷非常重要如果是SIGTERM和SIGQUIT會
- //pthread_kill終止所有活動的會話線程每個線程將收到
- //SIGUSR1信號然后調(diào)用empty_signal_handler回調(diào)函數(shù)進行
- //處理然后close_connections然后my_thread_end關閉,
- //這里是否調(diào)用innodb關閉操作,可以通過GDB打斷點
- //到innobase_shutdown_for_mysql函數(shù)上,我做了
- //測試確實調(diào)用了后面會給出,也就是說kill SIGTERM和
- //SIGQUIT是安全的,因為他們調(diào)用innodb關閉函數(shù)正常
- //的關閉了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到底了做了什么
- //我們可以看到他調(diào)用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關閉函數(shù)的調(diào)用,
這很容易我只要斷點打到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 -3/kill -SIGQUIT做什么:
和上面一樣,這在源碼中清楚的看到了
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
函數(shù)調(diào)用關于參數(shù)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 */
他們基本都是自解釋的,不用過多描述,那么我們也清楚的明白了SIGHUP在mysqld中被從新定義了,做各種刷新操作而已。
當然大家千萬不要直接kill -9這個信號不能被屏蔽也不能被捕獲,而是強制終止進程這個時候innodb不可能調(diào)用
innobase_shutdown_for_mysql來干凈的關閉MYSQLD。
文章標題:MYSQL中對信號的處理(SIGTERM,SIGQUIT,SIGHUP等)
地址分享:http://bm7419.com/article44/igsphe.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供微信公眾號、網(wǎng)站改版、網(wǎng)站設計、網(wǎng)站策劃、網(wǎng)站內(nèi)鏈、網(wǎng)站制作
廣告
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉載內(nèi)容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉載,或轉載時需注明來源:
創(chuàng)新互聯(lián)