Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the recover source code in Go programming

2025-04-01 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >

Share

Shulou(Shulou.com)05/31 Report--

This article introduces the relevant knowledge of "what is the source code of recover in Go programming". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

The real body of recover

Just as we did for panic, we also write a simple piece of code that tries to find the underlying implementation of the built-in function recover () through its assembly coding.

Write the following simple code and save it in a file called compile.go:

/ / recover/compile.gopackage recoverfunc compile () {defer func () {recover ()} ()}

Then compile the code using the following command:

Go tool compile-S recover/compile.go

Then find the assembly code corresponding to the recover () statement according to the line number of the code:

0x0024 00036 (recover/compile.go:5) PCDATA $0, $10x0024 00036 (recover/compile.go:5) PCDATA $1, $00x0024 00036 (recover/compile.go:5) LEAQ "".. FP + 40 (SP), AX0x0029 00041 (recover/compile.go:5) PCDATA $0, $00x0029 00041 (recover/compile.go:5) MOVQ AX, (SP) 0x002d 00045 (recover/compile.go:5) CALL runtime.gorecover (SB)

We can see that the recover () function call is replaced with the runtime.gorecover () function. The runtime.gorecover () implementation source code is located in src/runtime/panic.go.

Gorecover ()

The implementation of the runtime.gorecover () function is brief:

Func gorecover (argp uintptr) interface {} {gp: = getg () / / get the panic instance, only panic occurs The instance is not nil p: = gp._panic / / recover constraint if p! = nil & &! p.goexit & &! p.recovered & & argp = = uintptr (p.argp) {p.recovered = true return p.arg} return nil}

A short code contains a lot of information. It can explain the following problems:

How exactly does recover () restore panic?

Why does recover () have to take effect in the defer () function?

If the function A () is called in the defer () function, why doesn't recover () in A () take effect?

Recovery logic

The runtime.gorecover () function obtains the current panic instance (p in the above code) through the _ panic in the co-program data structure. If the current panic state supports recover, mark the panic instance with recovered status (p.recovered = true), and finally return the parameter (p.arg) of the panic () function.

In addition, the defer function that currently executes recover () is executed by runtime.gopanic (). After the execution of the defer function ends, the runtime.gopanic () function will check the recovered status of the panic instance. If it is found that panic has been restored, runtime.gopanic () will end the current panic process and restore the program flow to normal.

Effective condition

From the if statement of the code, you can see that four conditions need to be met before panic can be restored, and none of the four conditions are indispensable:

P! = nil: panic must exist

! p.goexit: non-runtime.Goexit ()

! p.recovered:panic has not been restored

Argp = = uintptr (p.argp): recover () must be called directly by defer ().

When no panic is generated in the current co-program, the linked list of panic in the co-program structure is empty and does not meet the recovery condition.

When the program runs runtime.Goexit (), a panic instance is also created, marking the instance's goexit attribute as true, but this type of panic cannot be restored.

Suppose the function contains multiple defer functions, and after the previous defer eliminates the panic through recover (), the remaining defer in the function will still execute, but cannot recover () again, as shown in the following code, the recover () in the first line of the function defer will return nil.

Func foo () {defer func () {recover ()} () / restore is invalid because _ panic.recovered = true defer func () {recover ()} () / tag _ panic.recovered = true panic ("err")}

Careful readers may find that the built-in function recover () has no arguments, while the runtime.gorecover () function has arguments. Why? This is precisely to restrict that recover () must be called directly by defer ().

The parameter address of the runtime.gorecover () function is the parameter address of the calling recover () function, which is usually the parameter address of the defer function. The parameter address of the current defer function is also saved in the same _ panic instance. If the two are the same, it means that recover () is called directly by the defer function. Examples are as follows:

Func foo () {defer func () {/ / suppose the function is A func () {/ / suppose the function is B / / runtime.gorecover (B), pass in the parameter address of function B / / argp = = uintptr (p.argp) failed to detect, cannot recover if err: = recover () Err! = nil {fmt.Println ("A")}} ()} ()} Design ideas

Through the analysis of the above source code, we can well answer the following questions:

Why does recover () have to take effect in the defer () function?

If the function A () is called in the defer () function, why doesn't recover () in A () take effect?

If recover () is not in the defer () function, then recover () may appear before panic (), or after panic (), before panic (), cannot take effect because the panic instance cannot be found, and after panic (), the code does not have a chance to execute, so recover () must exist in the defer function to take effect.

From the above analysis, we understand from the code level why the recover () function must be called directly by defer to take effect. But why should there be such a design?

The author also did not find the official information about this design, but I think this design is very reasonable.

Consider the following code:

Func foo () {defer func () {thirdPartPkg.Clean () / / call third-party package cleanup resources} () if err! = nil {/ / condition does not meet trigger panic panic (xxx)}}

Sometimes we explicitly trigger panic in the code, and often we call third-party package cleanup resources in the defer function. If the third-party package also uses recover (), then the panic we trigger will be intercepted, and the interception may be unexpected and not what we expect.

This is the end of the content of "what is the recover source code in Go programming". Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report