安全点分析

回收的安全点

什么时候才能进行抢占呢?如何才能区分该抢占信号是运行时发出的还是用户代码发出的呢?
TODO:

TODO: 解释执行栈映射补充寄存器映射,中断信号 SIGURG

// wantAsyncPreempt 返回异步抢占是否被 gp 请求
func wantAsyncPreempt(gp *g) bool {
    // 同时检查 G 和 P
    return (gp.preempt || gp.m.p != 0 && gp.m.p.ptr().preempt) && readgstatus(gp)&^_Gscan == _Grunning
}

什么时候才是安全的异步抢占点呢?
TODO:

func isAsyncSafePoint(gp *g, pc, sp, lr uintptr) bool {
    mp := gp.m

    // Only user Gs can have safe-points. We check this first
    // because it's extremely common that we'll catch mp in the
    // scheduler processing this G preemption.
    if mp.curg != gp {
        return false
    }

    // Check M state.
    if mp.p == 0 || !canPreemptM(mp) {
        return false
    }

    // Check stack space.
    if sp < gp.stack.lo || sp-gp.stack.lo < asyncPreemptStack {
        return false
    }

    // Check if PC is an unsafe-point.
    f := findfunc(pc)
    if !f.valid() {
        // Not Go code.
        return false
    }
    ...
    smi := pcdatavalue(f, _PCDATA_RegMapIndex, pc, nil)
    if smi == -2 {
        // Unsafe-point marked by compiler. This includes
        // atomic sequences (e.g., write barrier) and nosplit
        // functions (except at calls).
        return false
    }
    if fd := funcdata(f, _FUNCDATA_LocalsPointerMaps); fd == nil || fd == unsafe.Pointer(&no_pointers_stackmap) {
        // This is assembly code. Don't assume it's
        // well-formed. We identify assembly code by
        // checking that it has either no stack map, or
        // no_pointers_stackmap, which is the stack map
        // for ones marked as NO_LOCAL_POINTERS.
        //
        // TODO: Are there cases that are safe but don't have a
        // locals pointer map, like empty frame functions?
        return false
    }
    if hasPrefix(funcname(f), "runtime.") ||
        hasPrefix(funcname(f), "runtime/internal/") ||
        hasPrefix(funcname(f), "reflect.") {
        // For now we never async preempt the runtime or
        // anything closely tied to the runtime. Known issues
        // include: various points in the scheduler ("don't
        // preempt between here and here"), much of the defer
        // implementation (untyped info on stack), bulk write
        // barriers (write barrier check),
        // reflect.{makeFuncStub,methodValueCall}.
        //
        // TODO(austin): We should improve this, or opt things
        // in incrementally.
        return false
    }

    return true
}

其他抢占触发点

TODO: 一些 GC 的处理, suspendG

preemptStop 会在什么时候被设置为抢占呢?GC。

最后编辑: kuteng  文档更新时间: 2021-10-19 14:31   作者:kuteng