Skip to content

Commit

Permalink
runtime: always use GetQueuedCompletionStatusEx on Windows
Browse files Browse the repository at this point in the history
We used to fall back to GetQueuedCompletionStatus if
GetQueuedCompletionStatus was not available, but as of Go 1.11 we
require Windows 7 or later, so GetQueuedCompletionStatusEx is always
available.

Fixes #37957

Change-Id: I7d8d49a92ab7b1f5afdc54a442f696aaf4a5168e
Reviewed-on: https://go-review.googlesource.com/c/go/+/225059
Run-TryBot: Ian Lance Taylor <[email protected]>
TryBot-Result: Gobot Gobot <[email protected]>
Reviewed-by: Alex Brainman <[email protected]>
  • Loading branch information
ianlancetaylor committed Mar 24, 2020
1 parent 355f53f commit e3cf052
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 65 deletions.
87 changes: 26 additions & 61 deletions src/runtime/netpoll_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func netpollBreak() {
// delay > 0: block for up to that many nanoseconds
func netpoll(delay int64) gList {
var entries [64]overlappedEntry
var wait, qty, key, flags, n, i uint32
var wait, qty, flags, n, i uint32
var errno int32
var op *net_op
var toRun gList
Expand All @@ -99,82 +99,47 @@ func netpoll(delay int64) gList {
wait = 1e9
}

if _GetQueuedCompletionStatusEx != nil {
n = uint32(len(entries) / int(gomaxprocs))
if n < 8 {
n = 8
}
if delay != 0 {
mp.blocked = true
}
if stdcall6(_GetQueuedCompletionStatusEx, iocphandle, uintptr(unsafe.Pointer(&entries[0])), uintptr(n), uintptr(unsafe.Pointer(&n)), uintptr(wait), 0) == 0 {
mp.blocked = false
errno = int32(getlasterror())
if errno == _WAIT_TIMEOUT {
return gList{}
}
println("runtime: GetQueuedCompletionStatusEx failed (errno=", errno, ")")
throw("runtime: netpoll failed")
}
n = uint32(len(entries) / int(gomaxprocs))
if n < 8 {
n = 8
}
if delay != 0 {
mp.blocked = true
}
if stdcall6(_GetQueuedCompletionStatusEx, iocphandle, uintptr(unsafe.Pointer(&entries[0])), uintptr(n), uintptr(unsafe.Pointer(&n)), uintptr(wait), 0) == 0 {
mp.blocked = false
for i = 0; i < n; i++ {
op = entries[i].op
if op != nil {
errno = 0
qty = 0
if stdcall5(_WSAGetOverlappedResult, op.pd.fd, uintptr(unsafe.Pointer(op)), uintptr(unsafe.Pointer(&qty)), 0, uintptr(unsafe.Pointer(&flags))) == 0 {
errno = int32(getlasterror())
}
handlecompletion(&toRun, op, errno, qty)
} else {
if delay == 0 {
// Forward the notification to the
// blocked poller.
netpollBreak()
}
}
}
} else {
op = nil
errno = 0
qty = 0
if delay != 0 {
mp.blocked = true
errno = int32(getlasterror())
if errno == _WAIT_TIMEOUT {
return gList{}
}
if stdcall5(_GetQueuedCompletionStatus, iocphandle, uintptr(unsafe.Pointer(&qty)), uintptr(unsafe.Pointer(&key)), uintptr(unsafe.Pointer(&op)), uintptr(wait)) == 0 {
mp.blocked = false
errno = int32(getlasterror())
if errno == _WAIT_TIMEOUT {
return gList{}
}
if op == nil {
println("runtime: GetQueuedCompletionStatus failed (errno=", errno, ")")
throw("runtime: netpoll failed")
println("runtime: GetQueuedCompletionStatusEx failed (errno=", errno, ")")
throw("runtime: netpoll failed")
}
mp.blocked = false
for i = 0; i < n; i++ {
op = entries[i].op
if op != nil {
errno = 0
qty = 0
if stdcall5(_WSAGetOverlappedResult, op.pd.fd, uintptr(unsafe.Pointer(op)), uintptr(unsafe.Pointer(&qty)), 0, uintptr(unsafe.Pointer(&flags))) == 0 {
errno = int32(getlasterror())
}
// dequeued failed IO packet, so report that
}
mp.blocked = false
if op == nil {
handlecompletion(&toRun, op, errno, qty)
} else {
if delay == 0 {
// Forward the notification to the
// blocked poller.
netpollBreak()
}
return gList{}
}
handlecompletion(&toRun, op, errno, qty)
}
return toRun
}

func handlecompletion(toRun *gList, op *net_op, errno int32, qty uint32) {
if op == nil {
println("runtime: GetQueuedCompletionStatus returned op == nil")
throw("runtime: netpoll failed")
}
mode := op.mode
if mode != 'r' && mode != 'w' {
println("runtime: GetQueuedCompletionStatus returned invalid mode=", mode)
println("runtime: GetQueuedCompletionStatusEx returned invalid mode=", mode)
throw("runtime: netpoll failed")
}
op.errno = errno
Expand Down
6 changes: 2 additions & 4 deletions src/runtime/os_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const (
//go:cgo_import_dynamic runtime._GetEnvironmentStringsW GetEnvironmentStringsW%0 "kernel32.dll"
//go:cgo_import_dynamic runtime._GetProcAddress GetProcAddress%2 "kernel32.dll"
//go:cgo_import_dynamic runtime._GetProcessAffinityMask GetProcessAffinityMask%3 "kernel32.dll"
//go:cgo_import_dynamic runtime._GetQueuedCompletionStatus GetQueuedCompletionStatus%5 "kernel32.dll"
//go:cgo_import_dynamic runtime._GetQueuedCompletionStatusEx GetQueuedCompletionStatusEx%6 "kernel32.dll"
//go:cgo_import_dynamic runtime._GetStdHandle GetStdHandle%1 "kernel32.dll"
//go:cgo_import_dynamic runtime._GetSystemDirectoryA GetSystemDirectoryA%2 "kernel32.dll"
//go:cgo_import_dynamic runtime._GetSystemInfo GetSystemInfo%1 "kernel32.dll"
Expand Down Expand Up @@ -75,7 +75,7 @@ var (
_GetEnvironmentStringsW,
_GetProcAddress,
_GetProcessAffinityMask,
_GetQueuedCompletionStatus,
_GetQueuedCompletionStatusEx,
_GetStdHandle,
_GetSystemDirectoryA,
_GetSystemInfo,
Expand Down Expand Up @@ -111,7 +111,6 @@ var (
// We will load syscalls, if available, before using them.
_AddDllDirectory,
_AddVectoredContinueHandler,
_GetQueuedCompletionStatusEx,
_LoadLibraryExA,
_LoadLibraryExW,
_ stdFunction
Expand Down Expand Up @@ -239,7 +238,6 @@ func loadOptionalSyscalls() {
}
_AddDllDirectory = windowsFindfunc(k32, []byte("AddDllDirectory\000"))
_AddVectoredContinueHandler = windowsFindfunc(k32, []byte("AddVectoredContinueHandler\000"))
_GetQueuedCompletionStatusEx = windowsFindfunc(k32, []byte("GetQueuedCompletionStatusEx\000"))
_LoadLibraryExA = windowsFindfunc(k32, []byte("LoadLibraryExA\000"))
_LoadLibraryExW = windowsFindfunc(k32, []byte("LoadLibraryExW\000"))
useLoadLibraryEx = (_LoadLibraryExW != nil && _LoadLibraryExA != nil && _AddDllDirectory != nil)
Expand Down

0 comments on commit e3cf052

Please sign in to comment.