net: implement netpoll for windows

Moves the network poller from net package into runtime.

benchmark                           old ns/op    new ns/op    delta
BenchmarkTCP4OneShot                   316386       287061   -9.27%
BenchmarkTCP4OneShot-2                 339822       313424   -7.77%
BenchmarkTCP4OneShot-3                 330057       306589   -7.11%
BenchmarkTCP4OneShotTimeout            341775       287061  -16.01%
BenchmarkTCP4OneShotTimeout-2          380835       295849  -22.32%
BenchmarkTCP4OneShotTimeout-3          398412       328070  -17.66%
BenchmarkTCP4Persistent                 40622        33392  -17.80%
BenchmarkTCP4Persistent-2               44528        35736  -19.74%
BenchmarkTCP4Persistent-3               44919        36907  -17.84%
BenchmarkTCP4PersistentTimeout          45309        33588  -25.87%
BenchmarkTCP4PersistentTimeout-2        50289        38079  -24.28%
BenchmarkTCP4PersistentTimeout-3        51559        37103  -28.04%
BenchmarkTCP6OneShot                   361305       345645   -4.33%
BenchmarkTCP6OneShot-2                 361305       331976   -8.12%
BenchmarkTCP6OneShot-3                 376929       347598   -7.78%
BenchmarkTCP6OneShotTimeout            361305       322212  -10.82%
BenchmarkTCP6OneShotTimeout-2          378882       333928  -11.86%
BenchmarkTCP6OneShotTimeout-3          388647       335881  -13.58%
BenchmarkTCP6Persistent                 47653        35345  -25.83%
BenchmarkTCP6Persistent-2               49215        35736  -27.39%
BenchmarkTCP6Persistent-3               38474        37493   -2.55%
BenchmarkTCP6PersistentTimeout          56637        34369  -39.32%
BenchmarkTCP6PersistentTimeout-2        42575        38079  -10.56%
BenchmarkTCP6PersistentTimeout-3        44137        37689  -14.61%

R=dvyukov
CC=golang-dev
https://golang.org/cl/8670044
diff --git a/src/pkg/runtime/defs_windows.go b/src/pkg/runtime/defs_windows.go
index 0d525b9..01aea92 100644
--- a/src/pkg/runtime/defs_windows.go
+++ b/src/pkg/runtime/defs_windows.go
@@ -7,8 +7,8 @@
 /*
 Input to cgo.
 
-GOARCH=amd64 cgo -cdefs defs.go >amd64/defs.h
-GOARCH=386 cgo -cdefs defs.go >386/defs.h
+GOARCH=amd64 go tool cgo -cdefs defs_windows.go > defs_windows_amd64.h
+GOARCH=386 go tool cgo -cdefs defs_windows.go > defs_windows_386.h
 */
 
 package runtime
@@ -57,6 +57,9 @@
 	EXCEPTION_FLT_UNDERFLOW        = C.STATUS_FLOAT_UNDERFLOW
 	EXCEPTION_INT_DIVIDE_BY_ZERO   = C.STATUS_INTEGER_DIVIDE_BY_ZERO
 	EXCEPTION_INT_OVERFLOW         = C.STATUS_INTEGER_OVERFLOW
+
+	INFINITE     = C.INFINITE
+	WAIT_TIMEOUT = C.WAIT_TIMEOUT
 )
 
 type SystemInfo C.SYSTEM_INFO
@@ -64,3 +67,4 @@
 type FloatingSaveArea C.FLOATING_SAVE_AREA
 type M128a C.M128A
 type Context C.CONTEXT
+type Overlapped C.OVERLAPPED
diff --git a/src/pkg/runtime/defs_windows_386.h b/src/pkg/runtime/defs_windows_386.h
index 3377db9..db3629a 100644
--- a/src/pkg/runtime/defs_windows_386.h
+++ b/src/pkg/runtime/defs_windows_386.h
@@ -30,6 +30,9 @@
 	EXCEPTION_FLT_UNDERFLOW		= 0xc0000093,
 	EXCEPTION_INT_DIVIDE_BY_ZERO	= 0xc0000094,
 	EXCEPTION_INT_OVERFLOW		= 0xc0000095,
+
+	INFINITE	= 0xffffffff,
+	WAIT_TIMEOUT	= 0x102,
 };
 
 typedef struct SystemInfo SystemInfo;
@@ -37,6 +40,7 @@
 typedef struct FloatingSaveArea FloatingSaveArea;
 typedef struct M128a M128a;
 typedef struct Context Context;
+typedef struct Overlapped Overlapped;
 
 #pragma pack on
 
@@ -98,6 +102,12 @@
 	uint32	SegSs;
 	uint8	ExtendedRegisters[512];
 };
+struct Overlapped {
+	uint32	Internal;
+	uint32	InternalHigh;
+	byte	anon0[8];
+	byte	*hEvent;
+};
 
 
 #pragma pack off
diff --git a/src/pkg/runtime/defs_windows_amd64.h b/src/pkg/runtime/defs_windows_amd64.h
index c0a99ea..fe26f5a 100644
--- a/src/pkg/runtime/defs_windows_amd64.h
+++ b/src/pkg/runtime/defs_windows_amd64.h
@@ -30,6 +30,9 @@
 	EXCEPTION_FLT_UNDERFLOW		= 0xc0000093,
 	EXCEPTION_INT_DIVIDE_BY_ZERO	= 0xc0000094,
 	EXCEPTION_INT_OVERFLOW		= 0xc0000095,
+
+	INFINITE	= 0xffffffff,
+	WAIT_TIMEOUT	= 0x102,
 };
 
 typedef struct SystemInfo SystemInfo;
@@ -37,6 +40,7 @@
 typedef struct FloatingSaveArea FloatingSaveArea;
 typedef struct M128a M128a;
 typedef struct Context Context;
+typedef struct Overlapped Overlapped;
 
 #pragma pack on
 
@@ -113,6 +117,12 @@
 	uint64	LastExceptionToRip;
 	uint64	LastExceptionFromRip;
 };
+struct Overlapped {
+	uint64	Internal;
+	uint64	InternalHigh;
+	byte	anon0[8];
+	byte	*hEvent;
+};
 
 
 #pragma pack off
diff --git a/src/pkg/runtime/netpoll.goc b/src/pkg/runtime/netpoll.goc
index e9c0218..66557cc 100644
--- a/src/pkg/runtime/netpoll.goc
+++ b/src/pkg/runtime/netpoll.goc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin linux
+// +build darwin linux windows
 
 package net
 
diff --git a/src/pkg/runtime/netpoll_stub.c b/src/pkg/runtime/netpoll_stub.c
index 39d19a4c..c6ecf67 100644
--- a/src/pkg/runtime/netpoll_stub.c
+++ b/src/pkg/runtime/netpoll_stub.c
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build freebsd netbsd openbsd plan9 windows
+// +build freebsd netbsd openbsd plan9
 
 #include "runtime.h"
 
diff --git a/src/pkg/runtime/netpoll_windows.c b/src/pkg/runtime/netpoll_windows.c
new file mode 100644
index 0000000..52ba7e4
--- /dev/null
+++ b/src/pkg/runtime/netpoll_windows.c
@@ -0,0 +1,110 @@
+// Copyright 2013 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.
+
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+
+#define DWORD_MAX 0xffffffff
+
+#pragma dynimport runtime·CreateIoCompletionPort CreateIoCompletionPort "kernel32.dll"
+#pragma dynimport runtime·GetQueuedCompletionStatus GetQueuedCompletionStatus "kernel32.dll"
+
+extern void *runtime·CreateIoCompletionPort;
+extern void *runtime·GetQueuedCompletionStatus;
+
+#define INVALID_HANDLE_VALUE ((uintptr)-1)
+
+// net_anOp must be the same as beginning of net.anOp. Keep these in sync.
+typedef struct net_anOp net_anOp;
+struct net_anOp
+{
+	// used by windows
+	Overlapped	o;
+	// used by netpoll
+	uintptr	runtimeCtx;
+	int32	mode;
+	int32	errno;
+	uint32	qty;
+};
+
+static uintptr iocphandle = INVALID_HANDLE_VALUE;  // completion port io handle
+
+void
+runtime·netpollinit(void)
+{
+	iocphandle = (uintptr)runtime·stdcall(runtime·CreateIoCompletionPort, 4, INVALID_HANDLE_VALUE, (uintptr)0, (uintptr)0, (uintptr)DWORD_MAX);
+	if(iocphandle == 0) {
+		runtime·printf("netpoll: failed to create iocp handle (errno=%d)\n", runtime·getlasterror());
+		runtime·throw("netpoll: failed to create iocp handle");
+	}
+	return;
+}
+
+int32
+runtime·netpollopen(uintptr fd, PollDesc *pd)
+{
+	USED(pd);
+	if(runtime·stdcall(runtime·CreateIoCompletionPort, 4, fd, iocphandle, (uintptr)0, (uintptr)0) == 0)
+		return -runtime·getlasterror();
+	return 0;
+}
+
+int32
+runtime·netpollclose(uintptr fd)
+{
+	// nothing to do
+	USED(fd);
+	return 0;
+}
+
+// Polls for completed network IO.
+// Returns list of goroutines that become runnable.
+G*
+runtime·netpoll(bool block)
+{
+	uint32 wait, qty, key;
+	int32 mode, errno;
+	net_anOp *o;
+	G *gp;
+
+	if(iocphandle == INVALID_HANDLE_VALUE)
+		return nil;
+	o = nil;
+	errno = 0;
+	qty = 0;
+	wait = INFINITE;
+	if(!block)
+		// TODO(brainman): should use 0 here instead, but scheduler hogs CPU
+		wait = 1;
+	// TODO(brainman): Need a loop here to fetch all pending notifications
+	// (or at least a batch). Scheduler will behave better if is given
+	// a batch of newly runnable goroutines.
+	// TODO(brainman): Call GetQueuedCompletionStatusEx() here when possible.
+	if(runtime·stdcall(runtime·GetQueuedCompletionStatus, 5, iocphandle, &qty, &key, &o, (uintptr)wait) == 0) {
+		errno = runtime·getlasterror();
+		if(o == nil && errno == WAIT_TIMEOUT) {
+			if(!block)
+				return nil;
+			runtime·throw("netpoll: GetQueuedCompletionStatus timed out");
+		}
+		if(o == nil) {
+			runtime·printf("netpoll: GetQueuedCompletionStatus failed (errno=%d)\n", errno);
+			runtime·throw("netpoll: GetQueuedCompletionStatus failed");
+		}
+		// dequeued failed IO packet, so report that
+	}
+	if(o == nil)
+		runtime·throw("netpoll: GetQueuedCompletionStatus returned o == nil");
+	mode = o->mode;
+	if(mode != 'r' && mode != 'w') {
+		runtime·printf("netpoll: GetQueuedCompletionStatus returned invalid mode=%d\n", mode);
+		runtime·throw("netpoll: GetQueuedCompletionStatus returned invalid mode");
+	}
+	o->errno = errno;
+	o->qty = qty;
+	gp = nil;
+	runtime·netpollready(&gp, (void*)o->runtimeCtx, mode);
+	return gp;
+}