learning
POSIX決定Linux中signal如何實現
Linux kernel對signal的傳遞過程分成了兩階段
Signal generation: 產生signal, 由kernel在目標process的task_struct
更新signal的狀態
Signal delivery: 傳遞signal, kernel將process的control flow交給signal handler
Signal已被產生但還沒傳遞時,稱為pending signal
Note: SIGKILL. SIGSTOP不能被ignore
task_struct
中跟signal相關的data與其structure
可以看到一個process會有兩個sigpending
,一個是thread共享的,
放在signal->shared_pending
中,另一個是private的,放在pending
中,給kill
這類針對所有thread的signal使用
以下函數都可以產生Signal
以send_sig
為例, function在kernel/signal.c
中,v5.10.5
版本的呼叫流程大概如下圖,而上述的function最終都會呼叫到send_signal
__send_signal
pid_type
來判斷要signal要放進signal->shared_pending
還是pending
__sigqueue_alloc
來創建一個signal queue,加到pending->list
中SIGKILL
signalfd_notify
用來通知signalfd
有signal來了sigaddset
把pending->signal
中代表sig
的bit改成1Note: sigpending->signal是一個64bit的結構,每個bit對應一個signal
complete_signal
,用signal_wake_up
在要接收signal的thread中設置TIF_SIGPENDING
來完成signal的產生Note: 如果是SIGKILL,所有thread都會被設置TIF_SIGPENDING
從kernel mode切換回user mode時, kernel都會檢查TIF_SIGPENDING
,如果有被set,代表此thread有signal要處理
ret_to_user
跳回userspace,TIF_SIGPENDING
,若為1就跳到working_pending
do_notify_resume
,會呼叫do_signal
do_signal
Kernel對signal的處理,主要在兩個function上
get_signal
: 從queue將此次處理的signal取出,放進一個ksignal
的struct中handle_signal
: 負責為user space準備好處理signal需要的環境get_signal
signr
指定為要處理的signal numberdequeue_signal
往下執行會呼叫sigdelset
跟__sigqueue_free
collect_signal
中的sigdelset
會負責將對應的bit清成0collect_signal
中的__sigqueue_free
負責將signal從queue中移除recalc_sigpending
檢查是否還有待傳遞的signal,沒有就把TIF_SIGPENDING
清成0handle_signal
負責準備處理signal需要的環境
setup_rt_frame
呼叫get_sigframe
(下面第4行)負責處理1.
的部分
pt_regs
的struct保存user space在進入kernek前的registerpt_regs
就會丟失,因為每次由進入kernel space的時候,kernel space的stack都一定是空的,因此不能把user space的context保存在kernel上,必須保存在user space的stack上get_sigframe
規劃2.3.
則由上面第18行的setup_return
(以ARM64為例)完成
setup_sigframe
已經將user space的 context存到user
中,因此這邊可以直接修改pt_regs
來將PC指向signal handlerregs[0]
存signal number,regs[29]
是stack pointer, regs[30]
是Link Register(存放函數的return address)sigtramp
指向VDSO的rt_sigreturn
(定義在arch/arm64/kernel/vdso/sigreturn.S
),並在第24行將return address設為sigtramp
,因此signal handler執行完後會接著執行rt_sigreturn
sys_rt_sigreturn
,呼叫restore_sigframe
來恢復user space的執行