Skip to content

Instantly share code, notes, and snippets.

@dblohm7
Created April 29, 2022 21:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dblohm7/e644522feb753cf26d19f4ed20e9c320 to your computer and use it in GitHub Desktop.
Save dblohm7/e644522feb753cf26d19f4ed20e9c320 to your computer and use it in GitHub Desktop.
Go runtime deadlock
package main
import (
"fmt"
"unsafe"
"golang.org/x/sys/windows"
)
func init() {
doStuff()
}
var (
k32 = windows.NewLazySystemDLL("kernel32.dll")
procQueueUserWorkItem = k32.NewProc("QueueUserWorkItem")
callback = windows.NewCallback(WorkItemCallback)
)
type CallbackData struct {
done chan struct{}
fn func()
}
func (cbd *CallbackData) Run() {
defer close(cbd.done)
if cbd.fn != nil {
(cbd.fn)()
}
}
func (cbd *CallbackData) Wait() {
<-cbd.done
}
func WorkItemCallback(parameter uintptr) uintptr {
cbdata := (*CallbackData)(unsafe.Pointer(parameter))
cbdata.Run()
return 0
}
// QueueUserWorkItem is used to simulate a Windows API that posts callbacks
// to the Windows thread pool. A typical go program would never want to directly
// call this.
func QueueUserWorkItem(cbdata *CallbackData) (err error) {
r, _, e := procQueueUserWorkItem.Call(callback, uintptr(unsafe.Pointer(cbdata)), 0)
if r == 0 {
err = e
}
return
}
func doStuff() {
cbd := CallbackData{
done: make(chan struct{}),
fn: func() {
fmt.Println("Callback complete")
},
}
err := QueueUserWorkItem(&cbd)
if err != nil {
panic(err)
}
cbd.Wait()
}
func main() {
fmt.Println("main")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment