preempt
0.1 · preempt#
runtime/signal_unix.go
func initsig(preinit bool) {
// 预初始化
if !preinit {
signalsOK = true
}
// 遍历信号数组
for i := uint32(0); i < _NSIG; i++ {
t := &sigtable[i] // https://de.wikipedia.org/wiki/Signal_(Unix)
// 略过信号:SIGKILL, SIGSTOP, SIGCONT, SIGTSTP, SIGTTIN, SIGTTOU
if t.flags == 0 || t.flags&_SigDefault != 0 {
continue
}
// ...
setsig(i, funcPC(sighandler))
}
}
func setsig(i uint32, fn uintptr) {
var sa sigactiont
sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTORER | _SA_RESTART
sigfillset(&sa.sa_mask)
// ...
if fn == funcPC(sighandler) {
// CGO 相关
if iscgo {
fn = funcPC(cgoSigtramp)
} else {
// 当 fn 等于 sighandler 的时候,调用的函数会被替换成 sigtramp
fn = funcPC(sigtramp)
}
}
sa.sa_handler = fn
sigaction(i, &sa, nil) // sigaction 函数在 Linux 下会调用系统调用函数 sys_signal 以及 sys_rt_sigaction 实现安装信号
}
func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
// ...
sighandler(sig, info, ctx, g)
// ...
}
func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
_g_ := getg()
c := &sigctxt{info, ctxt}
// ...
// 如果是一个抢占信号
// const sigPreempt = _SIGURG
if sig == sigPreempt && debug.asyncpreemptoff == 0 {
// 处理抢占信号
doSigPreempt(gp, c)
}
// ...
}
func doSigPreempt(gp *g, ctxt *sigctxt) {
// 检查此 G 是否要被抢占并且可以安全地抢占
if wantAsyncPreempt(gp) {
// 检查是否能安全的进行抢占
if ok, newpc := isAsyncSafePoint(gp, ctxt.sigpc(), ctxt.sigsp(), ctxt.siglr()); ok {
// 修改寄存器,并执行抢占调用
ctxt.pushCall(funcPC(asyncPreempt), newpc)
}
}
// 更新一下抢占相关字段
atomic.Xadd(&gp.m.preemptGen, 1)
atomic.Store(&gp.m.signalPending, 0)
}
runtime/signal_unix.go
// 保存用户态寄存器后调用asyncPreempt2
func asyncPreempt()
func asyncPreempt2() {
gp := getg()
gp.asyncSafePoint = true
// 该 G 是否可以被抢占
if gp.preemptStop {
mcall(preemptPark)
} else {
// 让 G 放弃当前在 M 上的执行权利,将 G 放入全局队列等待后续调度
mcall(gopreempt_m)
}
gp.asyncSafePoint = false
}
src/runtime/sys_linux_amd64.s
TEXT runtime·sigtramp<ABIInternal>(SB),NOSPLIT,$72
// ...
CALL $·sigtrampgo(SB)
// ...
RET