其實這個操作就是向前臺程序傳送sigint訊號。
以下是linux支援的訊號列表:
使用kill -n pid或在**中使用int kill(pid_t pid, int sig);可以向乙個程序傳送訊號。
如果**中沒有顯式的用signal去註冊訊號對應的控制代碼,那就會採用預設的處理方式,例如接收到sigint缺省會將程序停止。
新的問題來了,當使用了kill、signal這些api之後,核心發生了什麼?這些訊號怎麼能夠傳到指定的程序?又是怎麼被處理的?
signal:這是乙個signal_struct結構,裡面有乙個比較關鍵的成員wait_chldexit,指向乙個等待佇列,當程序呼叫wait或者waitpid的時候,該程序就會在這個佇列上等,知道核心發現對應的子程序退出則將其喚醒
sighand:這是個大小為64的sigaction的指標陣列對應上文64種訊號的handler,sigaction中有乙個sa_handler成員預設是0,代表採用系統預設操作處理該訊號。
blocked:乙個位圖,代表程序目前遮蔽哪些訊號
pending:乙個sigpending結構,底下串著sigqueue,這些sigqueue就是待處理的訊號了,它包含user_struct用於記錄訊號發起者的資訊、siginfo用於記錄關於訊號的全部資訊。
將這些結構組織一下,大概是這樣的:
這些資訊都是有預設值的,在fork的copy_process過程中,會呼叫copy_sighand和copy_signal來拷貝父程序的訊號處理方法,如果父程序對某個訊號設定了控制代碼,那麼子程序會繼承過來。如果一直父程序一直往上都沒有為任何訊號設定控制代碼,那就繼承init_task設定好的值,sighand->action[n].sa_handler應該為0(sig_dfl)。init_task初始化時訊號相關成員的初始化如下:
拿子程序退出舉例,在程式設計中一般會呼叫wait來處理子程序退出,一旦子程序呼叫了exit,父程序就會從wait返回。
了解上面task結構體中的這些和訊號相關的成員,大概也可以猜到核心是怎麼實現訊號處理的了,實際上子程序在退出時向父程序傳送sigchld訊號,並去喚醒父程序處理。
所以就可以猜測sys_exit系統呼叫肯定會構造乙個sigqueue的結構,然後掛到父程序的pending裡面並嘗試去父程序的wait_chldexit中喚醒父程序處理。實際就是這樣的,exit系統呼叫的通知父程序的流程大致如下:
值得一提的是sig_ign和sa_nocldwait可能會導致不向程序傳送訊號,但是子程序退出時一定會喚醒父程序。
kill系統調流程也差不多,最終也是呼叫__send_signal
把sigqueue掛到程序的pending上。
至於訊號的處理的時機,即從核心態返回使用者態(從系統呼叫或者中斷返回)的時候都在work_pending檢查處理。
以arm64為例:
tif_sigpending是在__send_signal中呼叫complete_signal設定的。
Linux如何處理共享中斷
linux可以讓多個裝置共享乙個中斷號,而且共享同一中斷的中斷處理程式形成乙個鍊錶,核心對每個中斷處理程式都要執行,那麼,沒有產生中斷的裝置本 該靠邊站的,它的中斷處理程式也被執行了?到底是怎麼會事?實際上 共享的處理程式與非共享的處理程式在註冊和執行方式上比較相似,但差異主要有以下三處 reque...
如何處理DDoS
ddos 簡述 ddos是分布式拒絕服務 distributed denial of service 的英文縮寫,其 方式通常是利用很多受 者控制的 殭屍主機 向目標主機傳送大量看似合法的資料報,從而造成主機資源被耗盡或網路被堵塞,導致主機無法繼續正常提供服務。ddos通常可以分為兩類,即資源耗費式...
如何處理DDoS
ddos 簡述 ddos是分布式拒絕服務 distributed denial of service 的英文縮寫,其 方式通常是利用很多受 者控制的 殭屍主機 向目標主機傳送大量看似合法的資料報,從而造成主機資源被耗盡或網路被堵塞,導致主機無法繼續正常提供服務。ddos通常可以分為兩類,即資源耗費式...