在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)
型
1条答案
按热度按时间aamkag611#
来自https://go.dev/ref/spec#Handling_panics
如果满足以下任一条件,recover的返回值为nil:
(emph矿山)
最后一个要点是你的案子。只有“延迟1”是直接延迟的。你的“defer 2”并不是针对main的defered(但是只针对defer 1,并且该函数没有死机:它不在调用堆栈上,在死机期间正在展开)。
(It帮助我们了解语言规范:规范简短明了,而且经常很有帮助。)