net: reuse channels during io

R=golang-dev, bsiegert, rsc, hectorchu
CC=golang-dev
https://golang.org/cl/5016043
diff --git a/src/pkg/net/fd_windows.go b/src/pkg/net/fd_windows.go
index f15b6c0..b025bdd 100644
--- a/src/pkg/net/fd_windows.go
+++ b/src/pkg/net/fd_windows.go
@@ -52,15 +52,27 @@
 	// of the struct, as our code rely on it.
 	o syscall.Overlapped
 
-	resultc chan ioResult // io completion results
-	errnoc  chan int      // io submit / cancel operation errors
+	resultc chan ioResult
+	errnoc  chan int
 	fd      *netFD
 }
 
-func (o *anOp) Init(fd *netFD) {
+func (o *anOp) Init(fd *netFD, mode int) {
 	o.fd = fd
-	o.resultc = make(chan ioResult, 1)
-	o.errnoc = make(chan int)
+	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 {
+		fd.errnoc[i] = make(chan int)
+	}
+	o.errnoc = fd.errnoc[i]
 }
 
 func (o *anOp) Op() *anOp {
@@ -74,8 +86,8 @@
 	buf syscall.WSABuf
 }
 
-func (o *bufOp) Init(fd *netFD, buf []byte) {
-	o.anOp.Init(fd)
+func (o *bufOp) Init(fd *netFD, buf []byte, mode int) {
+	o.anOp.Init(fd, mode)
 	o.buf.Len = uint32(len(buf))
 	if len(buf) == 0 {
 		o.buf.Buf = nil
@@ -208,12 +220,14 @@
 	closing bool
 
 	// immutable until Close
-	sysfd  syscall.Handle
-	family int
-	proto  int
-	net    string
-	laddr  Addr
-	raddr  Addr
+	sysfd   syscall.Handle
+	family  int
+	proto   int
+	net     string
+	laddr   Addr
+	raddr   Addr
+	resultc [2]chan ioResult // read/write completion results
+	errnoc  [2]chan int      // read/write submit or cancel operation errors
 
 	// owned by client
 	rdeadline_delta int64
@@ -325,7 +339,7 @@
 		return 0, os.EINVAL
 	}
 	var o readOp
-	o.Init(fd, buf)
+	o.Init(fd, buf, 'r')
 	n, err = iosrv.ExecIO(&o, fd.rdeadline_delta)
 	if err == nil && n == 0 {
 		err = os.EOF
@@ -365,7 +379,7 @@
 		return 0, nil, os.EINVAL
 	}
 	var o readFromOp
-	o.Init(fd, buf)
+	o.Init(fd, buf, 'r')
 	o.rsan = int32(unsafe.Sizeof(o.rsa))
 	n, err = iosrv.ExecIO(&o, fd.rdeadline_delta)
 	if err != nil {
@@ -402,7 +416,7 @@
 		return 0, os.EINVAL
 	}
 	var o writeOp
-	o.Init(fd, buf)
+	o.Init(fd, buf, 'w')
 	return iosrv.ExecIO(&o, fd.wdeadline_delta)
 }
 
@@ -437,7 +451,7 @@
 		return 0, os.EINVAL
 	}
 	var o writeToOp
-	o.Init(fd, buf)
+	o.Init(fd, buf, 'w')
 	o.sa = sa
 	return iosrv.ExecIO(&o, fd.wdeadline_delta)
 }
@@ -487,7 +501,7 @@
 
 	// Submit accept request.
 	var o acceptOp
-	o.Init(fd)
+	o.Init(fd, 'r')
 	o.newsock = s
 	_, err = iosrv.ExecIO(&o, 0)
 	if err != nil {
diff --git a/src/pkg/net/sendfile_windows.go b/src/pkg/net/sendfile_windows.go
index 3772eee..d9c2f53 100644
--- a/src/pkg/net/sendfile_windows.go
+++ b/src/pkg/net/sendfile_windows.go
@@ -54,7 +54,7 @@
 	defer c.decref()
 
 	var o sendfileOp
-	o.Init(c)
+	o.Init(c, 'w')
 	o.n = uint32(n)
 	o.src = f.Fd()
 	done, err := iosrv.ExecIO(&o, 0)