Question about x/sync/singleflight redundant go panic(e) in doCall method

Hi,

I have a question regarding the following code in the singleflight package:

if len(c.chans) > 0 { go panic(e) select {} // Keep this goroutine around so that it will appear in the crash dump. }

It appears that the code uses go panic(e) inside a goroutine to trigger a panic in a separate goroutine. My question is whether this go panic(e) is really necessary, as it seems redundant.

Here’s why: In the DoChan method, the call to g.doCall(c, key, fn) is already executed inside a new goroutine, so any panic inside doCall will already happen in that goroutine. The caller of DoChan will not be able to recover from the panic, as it’s happening in a separate goroutine. Therefore, triggering go panic(e) or panic(e) doesn’t really change the outcome, and the program will eventually crash either way.

Could you clarify if go panic(e) is a defensive programming practice or if it’s an unnecessary redundancy? From my understanding, it doesn’t provide additional value in terms of preventing a crash or recovering from a panic.

Thank you!

As the comment states this is a workaround. They want to crash the program, but also want to see the current routine in the crash-dump as an active routine. If you panic() from a routine that routine will stop running and depending on the panic being re-panic-ed the call-stack will also be lost. This can make it very hard to reason about the program state when the panic occured.

This workaround will preserve the original go-routine in its original state to help finding a possible error. But this comes at the cost of not being able to recover from this panic, since it is thrown in a new go routine which will immediately lead to program termination.

The code go g.doCall(c, key, fn)has already started a new goroutine, which 100% guarantees that a panic triggered inside g.doCall’s internal code cannot be recovered by user-level recover. However, internally it again uses go panic(e). Clearly, this gois redundant?

If the code crashes with a panic and you take a memory dump, you will see all active go routines, their call-stacks and their variables.

You will not see the call-stack and variables of the function that panicked, because on panic the stack will unwind to the top level before the program terminates. So if you want to see the state of local variables in your doCall routine, you need to pause this routine and keep it alive until the panic is completed.