2010-06-29 21:23:39 -06:00
|
|
|
// Copyright 2010 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package net
|
|
|
|
|
|
|
|
import (
|
2012-02-13 22:57:57 -07:00
|
|
|
"errors"
|
2011-11-01 20:05:34 -06:00
|
|
|
"io"
|
2010-06-29 21:23:39 -06:00
|
|
|
"os"
|
2011-01-19 12:49:25 -07:00
|
|
|
"runtime"
|
2010-06-29 21:23:39 -06:00
|
|
|
"sync"
|
|
|
|
"syscall"
|
2011-01-19 12:49:25 -07:00
|
|
|
"time"
|
2010-06-29 21:23:39 -06:00
|
|
|
"unsafe"
|
|
|
|
)
|
|
|
|
|
2011-11-01 20:05:34 -06:00
|
|
|
var initErr error
|
2011-02-22 20:40:24 -07:00
|
|
|
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
// CancelIo Windows API cancels all outstanding IO for a particular
|
|
|
|
// socket on current thread. To overcome that limitation, we run
|
|
|
|
// special goroutine, locked to OS single thread, that both starts
|
|
|
|
// and cancels IO. It means, there are 2 unavoidable thread switches
|
|
|
|
// for every IO.
|
|
|
|
// Some newer versions of Windows has new CancelIoEx API, that does
|
|
|
|
// not have that limitation and can be used from any thread. This
|
|
|
|
// package uses CancelIoEx API, if present, otherwise it fallback
|
|
|
|
// to CancelIo.
|
|
|
|
|
|
|
|
var canCancelIO bool // determines if CancelIoEx API is present
|
|
|
|
|
2012-11-06 22:58:20 -07:00
|
|
|
func sysInit() {
|
2011-02-22 20:40:24 -07:00
|
|
|
var d syscall.WSAData
|
2011-09-08 00:32:40 -06:00
|
|
|
e := syscall.WSAStartup(uint32(0x202), &d)
|
2011-12-07 18:07:21 -07:00
|
|
|
if e != nil {
|
|
|
|
initErr = os.NewSyscallError("WSAStartup", e)
|
2011-02-22 20:40:24 -07:00
|
|
|
}
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
canCancelIO = syscall.LoadCancelIoEx() == nil
|
2012-11-06 22:58:20 -07:00
|
|
|
if syscall.LoadGetAddrInfo() == nil {
|
|
|
|
lookupIP = newLookupIP
|
|
|
|
}
|
2011-02-22 20:40:24 -07:00
|
|
|
}
|
|
|
|
|
2012-01-31 08:36:45 -07:00
|
|
|
func closesocket(s syscall.Handle) error {
|
2011-07-01 08:18:07 -06:00
|
|
|
return syscall.Closesocket(s)
|
2011-02-22 20:40:24 -07:00
|
|
|
}
|
|
|
|
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
// Interface for all IO operations.
|
2011-02-22 20:40:24 -07:00
|
|
|
type anOpIface interface {
|
|
|
|
Op() *anOp
|
|
|
|
Name() string
|
2012-01-31 08:36:45 -07:00
|
|
|
Submit() error
|
2011-02-22 20:40:24 -07:00
|
|
|
}
|
|
|
|
|
2010-06-29 21:23:39 -06:00
|
|
|
// IO completion result parameters.
|
|
|
|
type ioResult struct {
|
2011-02-22 20:40:24 -07:00
|
|
|
qty uint32
|
2011-11-13 20:44:52 -07:00
|
|
|
err error
|
2010-06-29 21:23:39 -06:00
|
|
|
}
|
|
|
|
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
// anOp implements functionality common to all IO operations.
|
2011-02-22 20:40:24 -07:00
|
|
|
type anOp struct {
|
|
|
|
// Used by IOCP interface, it must be first field
|
|
|
|
// of the struct, as our code rely on it.
|
|
|
|
o syscall.Overlapped
|
2010-06-29 21:23:39 -06:00
|
|
|
|
2011-09-15 21:40:02 -06:00
|
|
|
resultc chan ioResult
|
2011-11-13 20:44:52 -07:00
|
|
|
errnoc chan error
|
2011-02-22 20:40:24 -07:00
|
|
|
fd *netFD
|
|
|
|
}
|
2010-06-29 21:23:39 -06:00
|
|
|
|
2011-09-15 21:40:02 -06:00
|
|
|
func (o *anOp) Init(fd *netFD, mode int) {
|
2011-02-22 20:40:24 -07:00
|
|
|
o.fd = fd
|
2011-09-15 21:40:02 -06:00
|
|
|
var i int
|
|
|
|
if mode == 'r' {
|
|
|
|
i = 0
|
|
|
|
} else {
|
|
|
|
i = 1
|
|
|
|
}
|
|
|
|
if fd.resultc[i] == nil {
|
|
|
|
fd.resultc[i] = make(chan ioResult, 1)
|
|
|
|
}
|
|
|
|
o.resultc = fd.resultc[i]
|
|
|
|
if fd.errnoc[i] == nil {
|
2011-11-13 20:44:52 -07:00
|
|
|
fd.errnoc[i] = make(chan error)
|
2011-09-15 21:40:02 -06:00
|
|
|
}
|
|
|
|
o.errnoc = fd.errnoc[i]
|
2010-06-29 21:23:39 -06:00
|
|
|
}
|
|
|
|
|
2011-02-22 20:40:24 -07:00
|
|
|
func (o *anOp) Op() *anOp {
|
|
|
|
return o
|
|
|
|
}
|
2010-06-29 21:23:39 -06:00
|
|
|
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
// bufOp is used by IO operations that read / write
|
2011-02-22 20:40:24 -07:00
|
|
|
// data from / to client buffer.
|
|
|
|
type bufOp struct {
|
|
|
|
anOp
|
|
|
|
buf syscall.WSABuf
|
|
|
|
}
|
2010-06-29 21:23:39 -06:00
|
|
|
|
2011-09-15 21:40:02 -06:00
|
|
|
func (o *bufOp) Init(fd *netFD, buf []byte, mode int) {
|
|
|
|
o.anOp.Init(fd, mode)
|
2011-02-22 20:40:24 -07:00
|
|
|
o.buf.Len = uint32(len(buf))
|
|
|
|
if len(buf) == 0 {
|
|
|
|
o.buf.Buf = nil
|
|
|
|
} else {
|
|
|
|
o.buf.Buf = (*byte)(unsafe.Pointer(&buf[0]))
|
|
|
|
}
|
|
|
|
}
|
2010-06-29 21:23:39 -06:00
|
|
|
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
// resultSrv will retrieve all IO completion results from
|
2011-02-22 20:40:24 -07:00
|
|
|
// iocp and send them to the correspondent waiting client
|
|
|
|
// goroutine via channel supplied in the request.
|
|
|
|
type resultSrv struct {
|
2011-07-01 08:18:07 -06:00
|
|
|
iocp syscall.Handle
|
2010-06-29 21:23:39 -06:00
|
|
|
}
|
|
|
|
|
2011-02-22 20:40:24 -07:00
|
|
|
func (s *resultSrv) Run() {
|
|
|
|
var o *syscall.Overlapped
|
|
|
|
var key uint32
|
|
|
|
var r ioResult
|
|
|
|
for {
|
|
|
|
r.err = syscall.GetQueuedCompletionStatus(s.iocp, &(r.qty), &key, &o, syscall.INFINITE)
|
|
|
|
switch {
|
2011-11-13 20:44:52 -07:00
|
|
|
case r.err == nil:
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
// Dequeued successfully completed IO packet.
|
2011-11-13 20:44:52 -07:00
|
|
|
case r.err == syscall.Errno(syscall.WAIT_TIMEOUT) && o == nil:
|
2011-02-22 20:40:24 -07:00
|
|
|
// Wait has timed out (should not happen now, but might be used in the future).
|
|
|
|
panic("GetQueuedCompletionStatus timed out")
|
|
|
|
case o == nil:
|
|
|
|
// Failed to dequeue anything -> report the error.
|
2011-11-13 20:44:52 -07:00
|
|
|
panic("GetQueuedCompletionStatus failed " + r.err.Error())
|
2011-02-22 20:40:24 -07:00
|
|
|
default:
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
// Dequeued failed IO packet.
|
2011-02-22 20:40:24 -07:00
|
|
|
}
|
|
|
|
(*anOp)(unsafe.Pointer(o)).resultc <- r
|
2010-06-29 21:23:39 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
// ioSrv executes net IO requests.
|
2011-02-22 20:40:24 -07:00
|
|
|
type ioSrv struct {
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
submchan chan anOpIface // submit IO requests
|
|
|
|
canchan chan anOpIface // cancel IO requests
|
2010-06-29 21:23:39 -06:00
|
|
|
}
|
|
|
|
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
// ProcessRemoteIO will execute submit IO requests on behalf
|
2011-02-22 20:40:24 -07:00
|
|
|
// of other goroutines, all on a single os thread, so it can
|
|
|
|
// cancel them later. Results of all operations will be sent
|
|
|
|
// back to their requesters via channel supplied in request.
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
// It is used only when the CancelIoEx API is unavailable.
|
2011-02-22 20:40:24 -07:00
|
|
|
func (s *ioSrv) ProcessRemoteIO() {
|
|
|
|
runtime.LockOSThread()
|
|
|
|
defer runtime.UnlockOSThread()
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case o := <-s.submchan:
|
|
|
|
o.Op().errnoc <- o.Submit()
|
|
|
|
case o := <-s.canchan:
|
2011-07-01 08:18:07 -06:00
|
|
|
o.Op().errnoc <- syscall.CancelIo(syscall.Handle(o.Op().fd.sysfd))
|
2011-02-22 20:40:24 -07:00
|
|
|
}
|
2010-06-29 21:23:39 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
// ExecIO executes a single IO operation oi. It submits and cancels
|
|
|
|
// IO in the current thread for systems where Windows CancelIoEx API
|
|
|
|
// is available. Alternatively, it passes the request onto
|
2011-02-22 20:40:24 -07:00
|
|
|
// a special goroutine and waits for completion or cancels request.
|
2012-01-18 17:24:06 -07:00
|
|
|
// deadline is unix nanos.
|
2012-01-31 08:36:45 -07:00
|
|
|
func (s *ioSrv) ExecIO(oi anOpIface, deadline int64) (int, error) {
|
|
|
|
var err error
|
2011-02-22 20:40:24 -07:00
|
|
|
o := oi.Op()
|
2012-11-24 16:02:57 -07:00
|
|
|
// Calculate timeout delta.
|
|
|
|
var delta int64
|
|
|
|
if deadline != 0 {
|
|
|
|
delta = deadline - time.Now().UnixNano()
|
|
|
|
if delta <= 0 {
|
|
|
|
return 0, &OpError{oi.Name(), o.fd.net, o.fd.laddr, errTimeout}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Start IO.
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
if canCancelIO {
|
|
|
|
err = oi.Submit()
|
|
|
|
} else {
|
2011-02-22 20:40:24 -07:00
|
|
|
// Send request to a special dedicated thread,
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
// so it can stop the IO with CancelIO later.
|
2011-02-22 20:40:24 -07:00
|
|
|
s.submchan <- oi
|
2012-01-31 08:36:45 -07:00
|
|
|
err = <-o.errnoc
|
2011-02-22 20:40:24 -07:00
|
|
|
}
|
2012-01-31 08:36:45 -07:00
|
|
|
switch err {
|
2011-11-13 20:44:52 -07:00
|
|
|
case nil:
|
2011-02-22 20:40:24 -07:00
|
|
|
// IO completed immediately, but we need to get our completion message anyway.
|
|
|
|
case syscall.ERROR_IO_PENDING:
|
2011-07-13 11:54:51 -06:00
|
|
|
// IO started, and we have to wait for its completion.
|
2012-01-31 09:20:34 -07:00
|
|
|
err = nil
|
2011-02-22 20:40:24 -07:00
|
|
|
default:
|
2012-01-31 08:36:45 -07:00
|
|
|
return 0, &OpError{oi.Name(), o.fd.net, o.fd.laddr, err}
|
2011-02-22 20:40:24 -07:00
|
|
|
}
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
// Setup timer, if deadline is given.
|
|
|
|
var timer <-chan time.Time
|
2012-11-24 16:02:57 -07:00
|
|
|
if delta > 0 {
|
|
|
|
t := time.NewTimer(time.Duration(delta) * time.Nanosecond)
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
defer t.Stop()
|
|
|
|
timer = t.C
|
|
|
|
}
|
|
|
|
// Wait for our request to complete.
|
|
|
|
var r ioResult
|
2012-11-01 18:07:22 -06:00
|
|
|
var cancelled, timeout bool
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
select {
|
|
|
|
case r = <-o.resultc:
|
|
|
|
case <-timer:
|
|
|
|
cancelled = true
|
2012-11-01 18:07:22 -06:00
|
|
|
timeout = true
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
case <-o.fd.closec:
|
|
|
|
cancelled = true
|
|
|
|
}
|
|
|
|
if cancelled {
|
|
|
|
// Cancel it.
|
|
|
|
if canCancelIO {
|
|
|
|
err := syscall.CancelIoEx(syscall.Handle(o.Op().fd.sysfd), &o.o)
|
|
|
|
// Assuming ERROR_NOT_FOUND is returned, if IO is completed.
|
|
|
|
if err != nil && err != syscall.ERROR_NOT_FOUND {
|
|
|
|
// TODO(brainman): maybe do something else, but panic.
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
} else {
|
2011-02-22 20:40:24 -07:00
|
|
|
s.canchan <- oi
|
|
|
|
<-o.errnoc
|
2010-06-29 21:23:39 -06:00
|
|
|
}
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
// Wait for IO to be canceled or complete successfully.
|
2011-02-22 20:40:24 -07:00
|
|
|
r = <-o.resultc
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
if r.err == syscall.ERROR_OPERATION_ABORTED { // IO Canceled
|
2012-11-01 18:07:22 -06:00
|
|
|
if timeout {
|
|
|
|
r.err = errTimeout
|
|
|
|
} else {
|
|
|
|
r.err = errClosing
|
|
|
|
}
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
}
|
2010-06-29 21:23:39 -06:00
|
|
|
}
|
2011-11-13 20:44:52 -07:00
|
|
|
if r.err != nil {
|
|
|
|
err = &OpError{oi.Name(), o.fd.net, o.fd.laddr, r.err}
|
2011-02-22 20:40:24 -07:00
|
|
|
}
|
|
|
|
return int(r.qty), err
|
2010-06-29 21:23:39 -06:00
|
|
|
}
|
|
|
|
|
2011-02-22 20:40:24 -07:00
|
|
|
// Start helper goroutines.
|
|
|
|
var resultsrv *resultSrv
|
|
|
|
var iosrv *ioSrv
|
2010-08-05 14:14:41 -06:00
|
|
|
var onceStartServer sync.Once
|
2010-06-29 21:23:39 -06:00
|
|
|
|
|
|
|
func startServer() {
|
2011-02-22 20:40:24 -07:00
|
|
|
resultsrv = new(resultSrv)
|
2011-11-13 20:44:52 -07:00
|
|
|
var err error
|
|
|
|
resultsrv.iocp, err = syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 1)
|
|
|
|
if err != nil {
|
|
|
|
panic("CreateIoCompletionPort: " + err.Error())
|
2011-02-22 20:40:24 -07:00
|
|
|
}
|
|
|
|
go resultsrv.Run()
|
|
|
|
|
|
|
|
iosrv = new(ioSrv)
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
if !canCancelIO {
|
|
|
|
// Only CancelIo API is available. Lets start special goroutine
|
|
|
|
// locked to an OS thread, that both starts and cancels IO.
|
|
|
|
iosrv.submchan = make(chan anOpIface)
|
|
|
|
iosrv.canchan = make(chan anOpIface)
|
|
|
|
go iosrv.ProcessRemoteIO()
|
|
|
|
}
|
2010-06-29 21:23:39 -06:00
|
|
|
}
|
|
|
|
|
2011-02-22 20:40:24 -07:00
|
|
|
// Network file descriptor.
|
|
|
|
type netFD struct {
|
|
|
|
// locking/lifetime of sysfd
|
|
|
|
sysmu sync.Mutex
|
|
|
|
sysref int
|
|
|
|
closing bool
|
2010-06-29 21:23:39 -06:00
|
|
|
|
2011-02-22 20:40:24 -07:00
|
|
|
// immutable until Close
|
2012-01-26 09:31:42 -07:00
|
|
|
sysfd syscall.Handle
|
|
|
|
family int
|
|
|
|
sotype int
|
|
|
|
isConnected bool
|
|
|
|
net string
|
|
|
|
laddr Addr
|
|
|
|
raddr Addr
|
|
|
|
resultc [2]chan ioResult // read/write completion results
|
|
|
|
errnoc [2]chan error // read/write submit or cancel operation errors
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
closec chan bool // used by Close to cancel pending IO
|
2011-02-22 20:40:24 -07:00
|
|
|
|
2012-12-04 21:59:01 -07:00
|
|
|
// serialize access to Read and Write methods
|
|
|
|
rio, wio sync.Mutex
|
|
|
|
|
|
|
|
// read and write deadlines
|
|
|
|
rdeadline, wdeadline deadline
|
2011-02-22 20:40:24 -07:00
|
|
|
}
|
|
|
|
|
2012-01-31 08:36:45 -07:00
|
|
|
func allocFD(fd syscall.Handle, family, sotype int, net string) *netFD {
|
|
|
|
netfd := &netFD{
|
2010-06-29 21:23:39 -06:00
|
|
|
sysfd: fd,
|
|
|
|
family: family,
|
2012-01-19 16:33:37 -07:00
|
|
|
sotype: sotype,
|
2010-06-29 21:23:39 -06:00
|
|
|
net: net,
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
closec: make(chan bool),
|
2010-06-29 21:23:39 -06:00
|
|
|
}
|
2012-01-31 08:36:45 -07:00
|
|
|
return netfd
|
2011-02-22 20:40:24 -07:00
|
|
|
}
|
|
|
|
|
2012-01-31 08:36:45 -07:00
|
|
|
func newFD(fd syscall.Handle, family, proto int, net string) (*netFD, error) {
|
2011-02-22 20:40:24 -07:00
|
|
|
if initErr != nil {
|
|
|
|
return nil, initErr
|
|
|
|
}
|
|
|
|
onceStartServer.Do(startServer)
|
|
|
|
// Associate our socket with resultsrv.iocp.
|
2012-01-31 08:36:45 -07:00
|
|
|
if _, err := syscall.CreateIoCompletionPort(syscall.Handle(fd), resultsrv.iocp, 0, 0); err != nil {
|
|
|
|
return nil, err
|
2011-03-28 21:40:01 -06:00
|
|
|
}
|
|
|
|
return allocFD(fd, family, proto, net), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (fd *netFD) setAddr(laddr, raddr Addr) {
|
|
|
|
fd.laddr = laddr
|
|
|
|
fd.raddr = raddr
|
2012-12-04 21:26:18 -07:00
|
|
|
runtime.SetFinalizer(fd, (*netFD).closesocket)
|
2011-03-28 21:40:01 -06:00
|
|
|
}
|
|
|
|
|
2012-01-31 08:36:45 -07:00
|
|
|
func (fd *netFD) connect(ra syscall.Sockaddr) error {
|
2011-11-13 20:44:52 -07:00
|
|
|
return syscall.Connect(fd.sysfd, ra)
|
2010-06-29 21:23:39 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Add a reference to this fd.
|
2012-02-13 22:40:37 -07:00
|
|
|
// If closing==true, mark the fd as closing.
|
|
|
|
// Returns an error if the fd cannot be used.
|
|
|
|
func (fd *netFD) incref(closing bool) error {
|
|
|
|
if fd == nil {
|
|
|
|
return errClosing
|
|
|
|
}
|
2010-06-29 21:23:39 -06:00
|
|
|
fd.sysmu.Lock()
|
2012-02-13 22:40:37 -07:00
|
|
|
if fd.closing {
|
|
|
|
fd.sysmu.Unlock()
|
|
|
|
return errClosing
|
|
|
|
}
|
2010-06-29 21:23:39 -06:00
|
|
|
fd.sysref++
|
2012-02-13 22:40:37 -07:00
|
|
|
if closing {
|
|
|
|
fd.closing = true
|
|
|
|
}
|
|
|
|
closing = fd.closing
|
2010-06-29 21:23:39 -06:00
|
|
|
fd.sysmu.Unlock()
|
2012-02-13 22:40:37 -07:00
|
|
|
return nil
|
2010-06-29 21:23:39 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Remove a reference to this FD and close if we've been asked to do so (and
|
|
|
|
// there are no references left.
|
|
|
|
func (fd *netFD) decref() {
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
if fd == nil {
|
|
|
|
return
|
|
|
|
}
|
2010-06-29 21:23:39 -06:00
|
|
|
fd.sysmu.Lock()
|
|
|
|
fd.sysref--
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
if fd.closing && fd.sysref == 0 && fd.sysfd != syscall.InvalidHandle {
|
2011-01-11 21:55:17 -07:00
|
|
|
closesocket(fd.sysfd)
|
2011-07-01 08:18:07 -06:00
|
|
|
fd.sysfd = syscall.InvalidHandle
|
2011-01-11 21:55:17 -07:00
|
|
|
// no need for a finalizer anymore
|
|
|
|
runtime.SetFinalizer(fd, nil)
|
2010-06-29 21:23:39 -06:00
|
|
|
}
|
|
|
|
fd.sysmu.Unlock()
|
|
|
|
}
|
|
|
|
|
2011-11-01 20:05:34 -06:00
|
|
|
func (fd *netFD) Close() error {
|
2012-02-13 22:40:37 -07:00
|
|
|
if err := fd.incref(true); err != nil {
|
|
|
|
return err
|
2010-06-29 21:23:39 -06:00
|
|
|
}
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
defer fd.decref()
|
|
|
|
// unblock pending reader and writer
|
|
|
|
close(fd.closec)
|
|
|
|
// wait for both reader and writer to exit
|
|
|
|
fd.rio.Lock()
|
|
|
|
defer fd.rio.Unlock()
|
|
|
|
fd.wio.Lock()
|
|
|
|
defer fd.wio.Unlock()
|
2010-06-29 21:23:39 -06:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2011-11-01 20:05:34 -06:00
|
|
|
func (fd *netFD) shutdown(how int) error {
|
2012-11-02 03:46:47 -06:00
|
|
|
if err := fd.incref(false); err != nil {
|
|
|
|
return err
|
2011-09-28 09:12:38 -06:00
|
|
|
}
|
2012-11-02 03:46:47 -06:00
|
|
|
defer fd.decref()
|
2011-11-13 20:44:52 -07:00
|
|
|
err := syscall.Shutdown(fd.sysfd, how)
|
|
|
|
if err != nil {
|
|
|
|
return &OpError{"shutdown", fd.net, fd.laddr, err}
|
2011-10-12 11:45:25 -06:00
|
|
|
}
|
2011-09-28 09:12:38 -06:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2011-11-01 20:05:34 -06:00
|
|
|
func (fd *netFD) CloseRead() error {
|
2011-10-12 11:45:25 -06:00
|
|
|
return fd.shutdown(syscall.SHUT_RD)
|
|
|
|
}
|
|
|
|
|
2011-11-01 20:05:34 -06:00
|
|
|
func (fd *netFD) CloseWrite() error {
|
2011-10-12 11:45:25 -06:00
|
|
|
return fd.shutdown(syscall.SHUT_WR)
|
2011-09-28 09:12:38 -06:00
|
|
|
}
|
|
|
|
|
2012-12-04 21:26:18 -07:00
|
|
|
func (fd *netFD) closesocket() error {
|
|
|
|
return closesocket(fd.sysfd)
|
|
|
|
}
|
|
|
|
|
2011-02-22 20:40:24 -07:00
|
|
|
// Read from network.
|
2011-01-19 12:49:25 -07:00
|
|
|
|
2011-02-22 20:40:24 -07:00
|
|
|
type readOp struct {
|
|
|
|
bufOp
|
2011-01-19 12:49:25 -07:00
|
|
|
}
|
|
|
|
|
2012-01-31 08:36:45 -07:00
|
|
|
func (o *readOp) Submit() error {
|
2011-02-22 20:40:24 -07:00
|
|
|
var d, f uint32
|
2011-07-01 08:18:07 -06:00
|
|
|
return syscall.WSARecv(syscall.Handle(o.fd.sysfd), &o.buf, 1, &d, &f, &o.o, nil)
|
2011-02-22 20:40:24 -07:00
|
|
|
}
|
2011-01-19 12:49:25 -07:00
|
|
|
|
2011-02-22 20:40:24 -07:00
|
|
|
func (o *readOp) Name() string {
|
|
|
|
return "WSARecv"
|
2011-01-19 12:49:25 -07:00
|
|
|
}
|
|
|
|
|
2012-01-31 08:36:45 -07:00
|
|
|
func (fd *netFD) Read(buf []byte) (int, error) {
|
2012-02-13 22:40:37 -07:00
|
|
|
if err := fd.incref(false); err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
2010-06-29 21:23:39 -06:00
|
|
|
defer fd.decref()
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
fd.rio.Lock()
|
|
|
|
defer fd.rio.Unlock()
|
2011-02-22 20:40:24 -07:00
|
|
|
var o readOp
|
2011-09-15 21:40:02 -06:00
|
|
|
o.Init(fd, buf, 'r')
|
2012-12-04 21:59:01 -07:00
|
|
|
n, err := iosrv.ExecIO(&o, fd.rdeadline.value())
|
2010-07-21 00:51:07 -06:00
|
|
|
if err == nil && n == 0 {
|
2011-11-01 20:05:34 -06:00
|
|
|
err = io.EOF
|
2010-07-21 00:51:07 -06:00
|
|
|
}
|
2012-01-31 08:36:45 -07:00
|
|
|
return n, err
|
2010-06-29 21:23:39 -06:00
|
|
|
}
|
|
|
|
|
2011-02-22 20:40:24 -07:00
|
|
|
// ReadFrom from network.
|
|
|
|
|
|
|
|
type readFromOp struct {
|
|
|
|
bufOp
|
2011-07-25 19:55:52 -06:00
|
|
|
rsa syscall.RawSockaddrAny
|
|
|
|
rsan int32
|
2011-02-22 20:40:24 -07:00
|
|
|
}
|
|
|
|
|
2012-01-31 08:36:45 -07:00
|
|
|
func (o *readFromOp) Submit() error {
|
2011-02-22 20:40:24 -07:00
|
|
|
var d, f uint32
|
2011-07-25 19:55:52 -06:00
|
|
|
return syscall.WSARecvFrom(o.fd.sysfd, &o.buf, 1, &d, &f, &o.rsa, &o.rsan, &o.o, nil)
|
2011-02-22 20:40:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func (o *readFromOp) Name() string {
|
|
|
|
return "WSARecvFrom"
|
|
|
|
}
|
|
|
|
|
2011-11-01 20:05:34 -06:00
|
|
|
func (fd *netFD) ReadFrom(buf []byte) (n int, sa syscall.Sockaddr, err error) {
|
2011-02-22 20:40:24 -07:00
|
|
|
if len(buf) == 0 {
|
2010-11-22 09:01:30 -07:00
|
|
|
return 0, nil, nil
|
|
|
|
}
|
2012-02-13 22:40:37 -07:00
|
|
|
if err := fd.incref(false); err != nil {
|
|
|
|
return 0, nil, err
|
2010-11-22 09:01:30 -07:00
|
|
|
}
|
2012-02-13 22:40:37 -07:00
|
|
|
defer fd.decref()
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
fd.rio.Lock()
|
|
|
|
defer fd.rio.Unlock()
|
2011-02-22 20:40:24 -07:00
|
|
|
var o readFromOp
|
2011-09-15 21:40:02 -06:00
|
|
|
o.Init(fd, buf, 'r')
|
2011-07-25 19:55:52 -06:00
|
|
|
o.rsan = int32(unsafe.Sizeof(o.rsa))
|
2012-12-04 21:59:01 -07:00
|
|
|
n, err = iosrv.ExecIO(&o, fd.rdeadline.value())
|
2011-07-25 19:55:52 -06:00
|
|
|
if err != nil {
|
|
|
|
return 0, nil, err
|
|
|
|
}
|
2011-02-22 20:40:24 -07:00
|
|
|
sa, _ = o.rsa.Sockaddr()
|
2010-11-22 09:01:30 -07:00
|
|
|
return
|
2010-06-29 21:23:39 -06:00
|
|
|
}
|
|
|
|
|
2011-02-22 20:40:24 -07:00
|
|
|
// Write to network.
|
|
|
|
|
|
|
|
type writeOp struct {
|
|
|
|
bufOp
|
|
|
|
}
|
|
|
|
|
2012-01-31 08:36:45 -07:00
|
|
|
func (o *writeOp) Submit() error {
|
2011-02-22 20:40:24 -07:00
|
|
|
var d uint32
|
2011-07-01 08:18:07 -06:00
|
|
|
return syscall.WSASend(o.fd.sysfd, &o.buf, 1, &d, 0, &o.o, nil)
|
2011-02-22 20:40:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func (o *writeOp) Name() string {
|
|
|
|
return "WSASend"
|
|
|
|
}
|
|
|
|
|
2012-01-31 08:36:45 -07:00
|
|
|
func (fd *netFD) Write(buf []byte) (int, error) {
|
2012-02-13 22:40:37 -07:00
|
|
|
if err := fd.incref(false); err != nil {
|
|
|
|
return 0, err
|
2010-06-29 21:23:39 -06:00
|
|
|
}
|
2012-02-13 22:40:37 -07:00
|
|
|
defer fd.decref()
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
fd.wio.Lock()
|
|
|
|
defer fd.wio.Unlock()
|
2011-02-22 20:40:24 -07:00
|
|
|
var o writeOp
|
2011-09-15 21:40:02 -06:00
|
|
|
o.Init(fd, buf, 'w')
|
2012-12-04 21:59:01 -07:00
|
|
|
return iosrv.ExecIO(&o, fd.wdeadline.value())
|
2011-02-22 20:40:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// WriteTo to network.
|
|
|
|
|
|
|
|
type writeToOp struct {
|
|
|
|
bufOp
|
|
|
|
sa syscall.Sockaddr
|
|
|
|
}
|
|
|
|
|
2012-01-31 08:36:45 -07:00
|
|
|
func (o *writeToOp) Submit() error {
|
2011-02-22 20:40:24 -07:00
|
|
|
var d uint32
|
2011-07-01 08:18:07 -06:00
|
|
|
return syscall.WSASendto(o.fd.sysfd, &o.buf, 1, &d, 0, o.sa, &o.o, nil)
|
2011-02-22 20:40:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func (o *writeToOp) Name() string {
|
|
|
|
return "WSASendto"
|
2010-06-29 21:23:39 -06:00
|
|
|
}
|
|
|
|
|
2012-01-31 08:36:45 -07:00
|
|
|
func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) {
|
2011-02-22 20:40:24 -07:00
|
|
|
if len(buf) == 0 {
|
2010-11-22 09:01:30 -07:00
|
|
|
return 0, nil
|
|
|
|
}
|
2012-02-13 22:40:37 -07:00
|
|
|
if err := fd.incref(false); err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
2010-11-22 09:01:30 -07:00
|
|
|
defer fd.decref()
|
net: fix connection resets when closed on windows
It is common to close network connection while another goroutine is
blocked reading on another goroutine. This sequence corresponds to
windows calls to WSARecv to start io, followed by GetQueuedCompletionStatus
that blocks until io completes, and, finally, closesocket called from
another thread. We were expecting that closesocket would unblock
GetQueuedCompletionStatus, and it does, but not always
(http://code.google.com/p/go/issues/detail?id=4170#c5). Also that sequence
results in connection is being reset.
This CL inserts CancelIo between GetQueuedCompletionStatus and closesocket,
and waits for both WSARecv and GetQueuedCompletionStatus to complete before
proceeding to closesocket. This seems to fix both connection resets and
issue 4170. It also makes windows code behave similar to unix version.
Unfortunately, CancelIo needs to be called on the same thread as WSARecv.
So we have to employ strategy we use for connections with deadlines to
every connection now. It means, there are 2 unavoidable thread switches
for every io. Some newer versions of windows have new CancelIoEx api that
doesn't have these drawbacks, and this CL uses this capability when available.
As time goes by, we should have less of CancelIo and more of CancelIoEx
systems. Computers with CancelIoEx are also not affected by issue 4195 anymore.
Fixes #3710
Fixes #3746
Fixes #4170
Partial fix for issue 4195
R=golang-dev, mikioh.mikioh, bradfitz, rsc
CC=golang-dev
https://golang.org/cl/6604072
2012-10-30 17:24:37 -06:00
|
|
|
fd.wio.Lock()
|
|
|
|
defer fd.wio.Unlock()
|
2011-02-22 20:40:24 -07:00
|
|
|
var o writeToOp
|
2011-09-15 21:40:02 -06:00
|
|
|
o.Init(fd, buf, 'w')
|
2011-02-22 20:40:24 -07:00
|
|
|
o.sa = sa
|
2012-12-04 21:59:01 -07:00
|
|
|
return iosrv.ExecIO(&o, fd.wdeadline.value())
|
2011-02-22 20:40:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Accept new network connections.
|
|
|
|
|
|
|
|
type acceptOp struct {
|
|
|
|
anOp
|
2011-07-01 08:18:07 -06:00
|
|
|
newsock syscall.Handle
|
2011-02-22 20:40:24 -07:00
|
|
|
attrs [2]syscall.RawSockaddrAny // space for local and remote address only
|
|
|
|
}
|
|
|
|
|
2012-01-31 08:36:45 -07:00
|
|
|
func (o *acceptOp) Submit() error {
|
2011-02-22 20:40:24 -07:00
|
|
|
var d uint32
|
|
|
|
l := uint32(unsafe.Sizeof(o.attrs[0]))
|
2011-07-01 08:18:07 -06:00
|
|
|
return syscall.AcceptEx(o.fd.sysfd, o.newsock,
|
2011-02-22 20:40:24 -07:00
|
|
|
(*byte)(unsafe.Pointer(&o.attrs[0])), 0, l, l, &d, &o.o)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (o *acceptOp) Name() string {
|
|
|
|
return "AcceptEx"
|
2010-06-29 21:23:39 -06:00
|
|
|
}
|
|
|
|
|
2012-01-31 08:36:45 -07:00
|
|
|
func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (*netFD, error) {
|
2012-02-13 22:40:37 -07:00
|
|
|
if err := fd.incref(false); err != nil {
|
2012-02-13 22:57:57 -07:00
|
|
|
return nil, err
|
2010-06-29 21:23:39 -06:00
|
|
|
}
|
|
|
|
defer fd.decref()
|
|
|
|
|
|
|
|
// Get new socket.
|
2012-09-20 16:13:36 -06:00
|
|
|
// See ../syscall/exec_unix.go for description of ForkLock.
|
2010-06-29 21:23:39 -06:00
|
|
|
syscall.ForkLock.RLock()
|
2012-01-31 08:36:45 -07:00
|
|
|
s, err := syscall.Socket(fd.family, fd.sotype, 0)
|
|
|
|
if err != nil {
|
2010-06-29 21:23:39 -06:00
|
|
|
syscall.ForkLock.RUnlock()
|
2012-12-04 21:13:03 -07:00
|
|
|
return nil, &OpError{"socket", fd.net, fd.laddr, err}
|
2010-06-29 21:23:39 -06:00
|
|
|
}
|
|
|
|
syscall.CloseOnExec(s)
|
|
|
|
syscall.ForkLock.RUnlock()
|
|
|
|
|
|
|
|
// Associate our new socket with IOCP.
|
2010-08-05 14:14:41 -06:00
|
|
|
onceStartServer.Do(startServer)
|
2012-01-31 08:36:45 -07:00
|
|
|
if _, err := syscall.CreateIoCompletionPort(s, resultsrv.iocp, 0, 0); err != nil {
|
2012-12-04 21:13:03 -07:00
|
|
|
closesocket(s)
|
2012-01-31 08:36:45 -07:00
|
|
|
return nil, &OpError{"CreateIoCompletionPort", fd.net, fd.laddr, err}
|
2010-06-29 21:23:39 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Submit accept request.
|
2011-02-22 20:40:24 -07:00
|
|
|
var o acceptOp
|
2011-09-15 21:40:02 -06:00
|
|
|
o.Init(fd, 'r')
|
2011-02-22 20:40:24 -07:00
|
|
|
o.newsock = s
|
2012-12-04 21:59:01 -07:00
|
|
|
_, err = iosrv.ExecIO(&o, fd.rdeadline.value())
|
2011-02-22 20:40:24 -07:00
|
|
|
if err != nil {
|
2011-01-11 21:55:17 -07:00
|
|
|
closesocket(s)
|
2011-02-22 20:40:24 -07:00
|
|
|
return nil, err
|
2010-06-29 21:23:39 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Inherit properties of the listening socket.
|
2012-01-31 08:36:45 -07:00
|
|
|
err = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd)))
|
|
|
|
if err != nil {
|
2011-01-11 21:55:17 -07:00
|
|
|
closesocket(s)
|
2012-12-04 21:13:03 -07:00
|
|
|
return nil, &OpError{"Setsockopt", fd.net, fd.laddr, err}
|
2010-06-29 21:23:39 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get local and peer addr out of AcceptEx buffer.
|
2011-02-22 20:40:24 -07:00
|
|
|
var lrsa, rrsa *syscall.RawSockaddrAny
|
|
|
|
var llen, rlen int32
|
|
|
|
l := uint32(unsafe.Sizeof(*lrsa))
|
|
|
|
syscall.GetAcceptExSockaddrs((*byte)(unsafe.Pointer(&o.attrs[0])),
|
|
|
|
0, l, l, &lrsa, &llen, &rrsa, &rlen)
|
|
|
|
lsa, _ := lrsa.Sockaddr()
|
|
|
|
rsa, _ := rrsa.Sockaddr()
|
|
|
|
|
2012-01-31 08:36:45 -07:00
|
|
|
netfd := allocFD(s, fd.family, fd.sotype, fd.net)
|
|
|
|
netfd.setAddr(toAddr(lsa), toAddr(rsa))
|
|
|
|
return netfd, nil
|
2011-01-11 21:55:17 -07:00
|
|
|
}
|
|
|
|
|
2011-05-30 02:02:59 -06:00
|
|
|
// Unimplemented functions.
|
2010-11-05 12:02:03 -06:00
|
|
|
|
2012-01-31 08:36:45 -07:00
|
|
|
func (fd *netFD) dup() (*os.File, error) {
|
2010-11-05 12:02:03 -06:00
|
|
|
// TODO: Implement this
|
|
|
|
return nil, os.NewSyscallError("dup", syscall.EWINDOWS)
|
|
|
|
}
|
2010-12-07 11:40:14 -07:00
|
|
|
|
2012-02-16 16:04:29 -07:00
|
|
|
var errNoSupport = errors.New("address family not supported")
|
|
|
|
|
2011-11-01 20:05:34 -06:00
|
|
|
func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
|
2012-02-16 16:04:29 -07:00
|
|
|
return 0, 0, 0, nil, errNoSupport
|
2010-12-07 11:40:14 -07:00
|
|
|
}
|
|
|
|
|
2011-11-01 20:05:34 -06:00
|
|
|
func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
|
2012-02-16 16:04:29 -07:00
|
|
|
return 0, 0, errNoSupport
|
2010-12-07 11:40:14 -07:00
|
|
|
}
|