Navigation Menu

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

syscall: cannot call Win32 API functions that spawn new threads #9240

Closed
dgolub opened this issue Dec 10, 2014 · 8 comments
Closed

syscall: cannot call Win32 API functions that spawn new threads #9240

dgolub opened this issue Dec 10, 2014 · 8 comments

Comments

@dgolub
Copy link

dgolub commented Dec 10, 2014

It is not possible to call Win32 API functions that spawn new threads because the callback wrapper generated by syscall.NewCallback does not perform the needed steps to set up the call stack as needed by the Go runtime for a new thread. Attempting to call such functions will cause the new thread to hang forever. This can be easily reproduced with the following simple test program:

package main

import (
    "fmt"
    "syscall"
)

func ThreadProc(p uintptr) uintptr {
    fmt.Println("FOO")
    return 0
}

func main() {
    modkernel32 := syscall.MustLoadDLL("kernel32.dll")
    procCreateThread := modkernel32.MustFindProc("CreateThread")
    r1, _, _ := procCreateThread.Call(0, 0, syscall.NewCallback(ThreadProc), 0, 0, 0)
    h := syscall.Handle(r1)
    syscall.WaitForSingleObject(h, syscall.INFINITE)
    syscall.CloseHandle(h)
}

This will hang forever in Go. Translating this program into C/C++ and compiling it with an adequate compiler such as Microsoft Visual C++ will give the expected output of printing FOO and terminating.

@ianlancetaylor
Copy link
Contributor

You can't arbitrarily create new threads on Unix systems either. The Go runtime more or less has to be in charge of threading.

Calling CreateThread in a Go program is not obviously useful. Is there a problem in more obviously useful code?

@dgolub
Copy link
Author

dgolub commented Dec 10, 2014

If you try to implement a Windows service in Go, calling StartServiceCtrlDispatcher will invoke the service main callback in a new thread. That's the motivating case for this issue. I used CreateThread in the example code because it's the simplest way to reproduce the issue.

@ianlancetaylor
Copy link
Contributor

Is this the Windows version of issue #227?

@dgolub
Copy link
Author

dgolub commented Dec 10, 2014

Not exactly. It looks like #227 involves forking a separate process, which you can do on Windows without an issue by calling CreateProcess. This is an issue with using Win32 API calls that spawn a new thread within the current process.

@alexbrainman
Copy link
Member

I think this is a dup of #6751.

Alex

@mattn
Copy link
Member

mattn commented Dec 11, 2014

Sorry about previous mistake comment.
I figure out pattern to reproduce. Below should work. Having import "C" seems initialize C runtime?

package main

import (
    "C"
    "fmt"
    "syscall"
)

func ThreadProc(p uintptr) uintptr {
    fmt.Println("FOO")
    return 0
}

func main() {
    modkernel32 := syscall.MustLoadDLL("kernel32.dll")
    procCreateThread := modkernel32.MustFindProc("CreateThread")
    r1, _, _ := procCreateThread.Call(0, 0, syscall.NewCallback(ThreadProc), 0, 0, 0)
    h := syscall.Handle(r1)
    syscall.WaitForSingleObject(h, syscall.INFINITE)
    syscall.CloseHandle(h)
}

@rsc rsc removed the os-windows label Apr 10, 2015
@rsc
Copy link
Contributor

rsc commented Apr 10, 2015

We actually do allow calls from non-Go-created threads, provided cgo is in use. We should probably assume cgo is in use all the time on Windows, since it effectively is.

@alexbrainman
Copy link
Member

Dup of #6751.

Alex

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

6 participants