diff options
author | Alex Brainman <alex.brainman@gmail.com> | 2017-10-11 18:15:25 +1100 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2017-10-25 20:23:29 +0000 |
commit | f259aed0822dd42182b297740e3c5dcd09e40a84 (patch) | |
tree | 7d916089e8593ec0fbbcc02532f8ac28bf89b696 | |
parent | 39d4bb9c0f3ac3f87de64b069ea176595e39d46c (diff) | |
download | go-f259aed0822dd42182b297740e3c5dcd09e40a84.tar.gz go-f259aed0822dd42182b297740e3c5dcd09e40a84.zip |
[release-branch.go1.9] internal/poll: do not call SetFileCompletionNotificationModes if it is broken
Current code assumes that SetFileCompletionNotificationModes
is safe to call even if we know that it is not safe to use
FILE_SKIP_COMPLETION_PORT_ON_SUCCESS flag. It appears (see issue #22149),
SetFileCompletionNotificationModes crashes when we call it without
FILE_SKIP_COMPLETION_PORT_ON_SUCCESS flag.
Do not call SetFileCompletionNotificationModes in that situation.
We are allowed to do that, because SetFileCompletionNotificationModes
is just an optimisation.
Fixes #22149
Change-Id: I0ad3aff4eabd8c27739417a62c286b1819ae166a
Reviewed-on: https://go-review.googlesource.com/69870
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-on: https://go-review.googlesource.com/70989
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
-rw-r--r-- | src/internal/poll/fd_windows.go | 64 |
1 files changed, 37 insertions, 27 deletions
diff --git a/src/internal/poll/fd_windows.go b/src/internal/poll/fd_windows.go index b0991a29f2..2927463eee 100644 --- a/src/internal/poll/fd_windows.go +++ b/src/internal/poll/fd_windows.go @@ -31,11 +31,40 @@ var ( // package uses CancelIoEx API, if present, otherwise it fallback // to CancelIo. -var ( - canCancelIO bool // determines if CancelIoEx API is present - skipSyncNotif bool - hasLoadSetFileCompletionNotificationModes bool -) +var canCancelIO bool // determines if CancelIoEx API is present + +// This package uses SetFileCompletionNotificationModes Windows API +// to skip calling GetQueuedCompletionStatus if an IO operation completes +// synchronously. Unfortuently SetFileCompletionNotificationModes is not +// available on Windows XP. Also there is a known bug where +// SetFileCompletionNotificationModes crashes on some systems +// (see http://support.microsoft.com/kb/2568167 for details). + +var useSetFileCompletionNotificationModes bool // determines is SetFileCompletionNotificationModes is present and safe to use + +// checkSetFileCompletionNotificationModes verifies that +// SetFileCompletionNotificationModes Windows API is present +// on the system and is safe to use. +// See http://support.microsoft.com/kb/2568167 for details. +func checkSetFileCompletionNotificationModes() { + err := syscall.LoadSetFileCompletionNotificationModes() + if err != nil { + return + } + protos := [2]int32{syscall.IPPROTO_TCP, 0} + var buf [32]syscall.WSAProtocolInfo + len := uint32(unsafe.Sizeof(buf)) + n, err := syscall.WSAEnumProtocols(&protos[0], &buf[0], &len) + if err != nil { + return + } + for i := int32(0); i < n; i++ { + if buf[i].ServiceFlags1&syscall.XP1_IFS_HANDLES == 0 { + return + } + } + useSetFileCompletionNotificationModes = true +} func init() { var d syscall.WSAData @@ -44,26 +73,7 @@ func init() { initErr = e } canCancelIO = syscall.LoadCancelIoEx() == nil - hasLoadSetFileCompletionNotificationModes = syscall.LoadSetFileCompletionNotificationModes() == nil - if hasLoadSetFileCompletionNotificationModes { - // It's not safe to use FILE_SKIP_COMPLETION_PORT_ON_SUCCESS if non IFS providers are installed: - // http://support.microsoft.com/kb/2568167 - skipSyncNotif = true - protos := [2]int32{syscall.IPPROTO_TCP, 0} - var buf [32]syscall.WSAProtocolInfo - len := uint32(unsafe.Sizeof(buf)) - n, err := syscall.WSAEnumProtocols(&protos[0], &buf[0], &len) - if err != nil { - skipSyncNotif = false - } else { - for i := int32(0); i < n; i++ { - if buf[i].ServiceFlags1&syscall.XP1_IFS_HANDLES == 0 { - skipSyncNotif = false - break - } - } - } - } + checkSetFileCompletionNotificationModes() } // operation contains superset of data necessary to perform all async IO. @@ -344,12 +354,12 @@ func (fd *FD) Init(net string, pollable bool) (string, error) { if err != nil { return "", err } - if hasLoadSetFileCompletionNotificationModes { + if useSetFileCompletionNotificationModes { // We do not use events, so we can skip them always. flags := uint8(syscall.FILE_SKIP_SET_EVENT_ON_HANDLE) // It's not safe to skip completion notifications for UDP: // http://blogs.technet.com/b/winserverperformance/archive/2008/06/26/designing-applications-for-high-performance-part-iii.aspx - if skipSyncNotif && (net == "tcp" || net == "file") { + if net == "tcp" || net == "file" { flags |= syscall.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS } err := syscall.SetFileCompletionNotificationModes(fd.Sysfd, flags) |