gorecover函数如何获取其argp参数?

fdbelqdn  于 2023-08-01  发布在  Go
关注(0)|答案(1)|浏览(141)

在golang运行时源代码中,嵌套的延迟函数调用的recover接收到的panic与当前goroutine的panic不同,这是什么逻辑?

gorecover函数如何获取其argp参数?

这个答案只告诉我原理,Why recover() does not work in a nested deferred function?

  • 但我想弄清楚golang运行时实现的细节。*

我的演示代码:

package main

import "fmt"

func main() {
    defer func() {
        fmt.Println("enter defer 1")
        defer func() {
            fmt.Println("enter defer 2")
            recover()
            // if e := recover(); e != nil {
            //  fmt.Println("recover")
            // }
            fmt.Println("exit defer 2")
        }()
        fmt.Println("exit defer 1")
    }()
    panic(404)
}

字符串
我的输出

➜  cmd git:(master) ✗ go run main.go                              
enter defer 1
exit defer 1
enter defer 2
exit defer 2
panic: 404

goroutine 1 [running]:
main.main()
        /Users/polar/code/leetcode/leetcode-go/demo/defer-demo/cmd2/main.go:18 +0x49
exit status 2


我尝试调试以在这段golang运行时源代码中获得更多信息:
golang运行时恢复函数的源代码。

// /Paht/to/go/src/runtime/panic.go
func gorecover(argp uintptr) any {
    // Must be in a function running as part of a deferred call during the panic.
    // Must be called from the topmost function of the call
    // (the function used in the defer statement).
    // p.argp is the argument pointer of that topmost deferred function call.
    // Compare against argp reported by caller.
    // If they match, the caller is the one who can recover.
    gp := getg()
    p := gp._panic
    if p != nil && !p.goexit && !p.recovered && argp == uintptr(p.argp) {
        p.recovered = true
        return p.arg
    }
    return nil
}


以下是我得到的:

gp._panic的值为

*runtime._panic 
{argp: unsafe.Pointer(0xc00007be58), 
arg: interface {}(int) 404, 
link: *runtime._panic nil, 
pc: 0, 
sp: unsafe.Pointer(0x0), 
recovered: false, 
aborted: false, 
goexit: false}

argp的值为

(unreadable could not find loclist entry at 0x2ffec for address 0x1036d0a)

aamkag61

aamkag611#

来自https://go.dev/ref/spec#Handling_panics
如果满足以下任一条件,recover的返回值为nil:

  • panic的参数为零;
  • goroutine并没有惊慌失措
  • recover没有被延迟函数直接调用。

(emph矿山)
最后一个要点是你的案子。只有“延迟1”是直接延迟的。你的“defer 2”并不是针对main的defered(但是只针对defer 1,并且该函数没有死机:它不在调用堆栈上,在死机期间正在展开)。
(It帮助我们了解语言规范:规范简短明了,而且经常很有帮助。)

相关问题