proposal: allow programs to handle deadlock events #44026
It would be great if a Go program could detect when all (other) Goroutines are blocked and then allow it to take action to do something about the situation. Given that Go has a deadlock detector, it seems like this situation is already detected by the Go runtime.
I want to use this to implement fake time that:
Implementing such fake time can basically be done as follows:
This is something I have previously successfully implemented in other programming languages and that has been very useful. There are several use cases of this including:
Some ways to make the feature
What to do if no Goroutine can run now, but one or more Goroutines are pseudo-blocked, for example:
UPDATED: In a simple approach where the existing deadlock detector is used, any pseudo-blocked Goroutine would be considered non-blocked, and hence prevent fake time from increasing. The feature would still be very useful. However, a probably even more useful approach would be to consider pseudo-blocked Goroutines blocked. In that case, fake time would increase even in case of pseudo-blocked Go routines. If a program wants to prevent fake time from increasing because of a pseudo-blocked Goroutine it knows of, it can just prevent that manually (some details would need to be considered to make sure this can work correctly).
An off topic note
Should fake time not be an OS feature? Or a feature of a virtual machine hypervisor? Yes, I think absolutely it should!
The text was updated successfully, but these errors were encountered:
The majority of real Go programs read from the network or from pipes. Many also use timers. Some use the os/signal package to look for signals. Any Go program that does any of those things can never deadlock.
The Go runtime already supports fake time, although it is not fully supported. See https://golang.org/src/runtime/time_fake.go. That may be a more profitable approach than focusing on detecting deadlocks.
I don't think the fake time idea is very interesting, but having a way to try to resolve deadlock does seems to be useful, at least if we had a way to terminate the blocked goroutines, which IIRC, we don't have. Otherwise something like a runtime.SetDeadlockCallback(callback func(goroutineID ...int)) could be useful.
I think you have an important point about networking. I think the feature will still be useful in case networking is used: First, networking may be mocked in code during testing. Second, I have added some more text in the proposal under "UPDATED" with ideas on how to address this.
Regarding timers, a central idea is that the Go program should use fake versions of timers. Hence real native Go timers would not be used and hence not prevent deadlock detection.
Since I opened this issue I have used Go some more. I still think the requested feature would be extremely useful to mock time in tests as I have described previously. However, I want to mention a simpler application.
Suppose I have written this program:
Suppose I want to test the multiply function using gomock. After having generated mocks for the Result interface, I could try to do it like this:
Unfortunately there is a race and the test may fail or succeed depending on whether the Give function is called before the test ends or not.
If we have the feature of this issue I could just add the line:
at the end of the TestMultiply function and there will be no races.
Now, of course the problem can be solved by using channels or WaitGroups in the test (see for example https://medium.com/@poy/gomock-and-go-routines-6a7c01d989d5). However, that is cumbersome. Further, if multiply makes additional calls to Give after the test has finished, the test will still succeed even though it should not.