Skip to main content

preempt

📅 2026-02-05 ✏️ 2026-03-06 CS GO
No related notes

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