aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Brainman <alex.brainman@gmail.com>2017-10-11 18:15:25 +1100
committerRuss Cox <rsc@golang.org>2017-10-25 20:23:29 +0000
commitf259aed0822dd42182b297740e3c5dcd09e40a84 (patch)
tree7d916089e8593ec0fbbcc02532f8ac28bf89b696
parent39d4bb9c0f3ac3f87de64b069ea176595e39d46c (diff)
downloadgo-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.go64
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)