| // 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. | 
 |  | 
 | package runtime | 
 |  | 
 | import ( | 
 | 	"unsafe" | 
 | ) | 
 |  | 
 | const _DWORD_MAX = 0xffffffff | 
 |  | 
 | const _INVALID_HANDLE_VALUE = ^uintptr(0) | 
 |  | 
 | // net_op must be the same as beginning of internal/poll.operation. | 
 | // Keep these in sync. | 
 | type net_op struct { | 
 | 	// used by windows | 
 | 	o overlapped | 
 | 	// used by netpoll | 
 | 	pd    *pollDesc | 
 | 	mode  int32 | 
 | 	errno int32 | 
 | 	qty   uint32 | 
 | } | 
 |  | 
 | type overlappedEntry struct { | 
 | 	key      uintptr | 
 | 	op       *net_op // In reality it's *overlapped, but we cast it to *net_op anyway. | 
 | 	internal uintptr | 
 | 	qty      uint32 | 
 | } | 
 |  | 
 | var iocphandle uintptr = _INVALID_HANDLE_VALUE // completion port io handle | 
 |  | 
 | func netpollinit() { | 
 | 	iocphandle = stdcall4(_CreateIoCompletionPort, _INVALID_HANDLE_VALUE, 0, 0, _DWORD_MAX) | 
 | 	if iocphandle == 0 { | 
 | 		println("runtime: CreateIoCompletionPort failed (errno=", getlasterror(), ")") | 
 | 		throw("runtime: netpollinit failed") | 
 | 	} | 
 | } | 
 |  | 
 | func netpolldescriptor() uintptr { | 
 | 	return iocphandle | 
 | } | 
 |  | 
 | func netpollopen(fd uintptr, pd *pollDesc) int32 { | 
 | 	if stdcall4(_CreateIoCompletionPort, fd, iocphandle, 0, 0) == 0 { | 
 | 		return int32(getlasterror()) | 
 | 	} | 
 | 	return 0 | 
 | } | 
 |  | 
 | func netpollclose(fd uintptr) int32 { | 
 | 	// nothing to do | 
 | 	return 0 | 
 | } | 
 |  | 
 | func netpollarm(pd *pollDesc, mode int) { | 
 | 	throw("runtime: unused") | 
 | } | 
 |  | 
 | // Polls for completed network IO. | 
 | // Returns list of goroutines that become runnable. | 
 | func netpoll(block bool) *g { | 
 | 	var entries [64]overlappedEntry | 
 | 	var wait, qty, key, flags, n, i uint32 | 
 | 	var errno int32 | 
 | 	var op *net_op | 
 | 	var gp guintptr | 
 |  | 
 | 	mp := getg().m | 
 |  | 
 | 	if iocphandle == _INVALID_HANDLE_VALUE { | 
 | 		return nil | 
 | 	} | 
 | 	wait = 0 | 
 | 	if block { | 
 | 		wait = _INFINITE | 
 | 	} | 
 | retry: | 
 | 	if _GetQueuedCompletionStatusEx != nil { | 
 | 		n = uint32(len(entries) / int(gomaxprocs)) | 
 | 		if n < 8 { | 
 | 			n = 8 | 
 | 		} | 
 | 		if block { | 
 | 			mp.blocked = true | 
 | 		} | 
 | 		if stdcall6(_GetQueuedCompletionStatusEx, iocphandle, uintptr(unsafe.Pointer(&entries[0])), uintptr(n), uintptr(unsafe.Pointer(&n)), uintptr(wait), 0) == 0 { | 
 | 			mp.blocked = false | 
 | 			errno = int32(getlasterror()) | 
 | 			if !block && errno == _WAIT_TIMEOUT { | 
 | 				return nil | 
 | 			} | 
 | 			println("runtime: GetQueuedCompletionStatusEx failed (errno=", errno, ")") | 
 | 			throw("runtime: netpoll failed") | 
 | 		} | 
 | 		mp.blocked = false | 
 | 		for i = 0; i < n; i++ { | 
 | 			op = entries[i].op | 
 | 			errno = 0 | 
 | 			qty = 0 | 
 | 			if stdcall5(_WSAGetOverlappedResult, op.pd.fd, uintptr(unsafe.Pointer(op)), uintptr(unsafe.Pointer(&qty)), 0, uintptr(unsafe.Pointer(&flags))) == 0 { | 
 | 				errno = int32(getlasterror()) | 
 | 			} | 
 | 			handlecompletion(&gp, op, errno, qty) | 
 | 		} | 
 | 	} else { | 
 | 		op = nil | 
 | 		errno = 0 | 
 | 		qty = 0 | 
 | 		if block { | 
 | 			mp.blocked = true | 
 | 		} | 
 | 		if stdcall5(_GetQueuedCompletionStatus, iocphandle, uintptr(unsafe.Pointer(&qty)), uintptr(unsafe.Pointer(&key)), uintptr(unsafe.Pointer(&op)), uintptr(wait)) == 0 { | 
 | 			mp.blocked = false | 
 | 			errno = int32(getlasterror()) | 
 | 			if !block && errno == _WAIT_TIMEOUT { | 
 | 				return nil | 
 | 			} | 
 | 			if op == nil { | 
 | 				println("runtime: GetQueuedCompletionStatus failed (errno=", errno, ")") | 
 | 				throw("runtime: netpoll failed") | 
 | 			} | 
 | 			// dequeued failed IO packet, so report that | 
 | 		} | 
 | 		mp.blocked = false | 
 | 		handlecompletion(&gp, op, errno, qty) | 
 | 	} | 
 | 	if block && gp == 0 { | 
 | 		goto retry | 
 | 	} | 
 | 	return gp.ptr() | 
 | } | 
 |  | 
 | func handlecompletion(gpp *guintptr, op *net_op, errno int32, qty uint32) { | 
 | 	if op == nil { | 
 | 		println("runtime: GetQueuedCompletionStatus returned op == nil") | 
 | 		throw("runtime: netpoll failed") | 
 | 	} | 
 | 	mode := op.mode | 
 | 	if mode != 'r' && mode != 'w' { | 
 | 		println("runtime: GetQueuedCompletionStatus returned invalid mode=", mode) | 
 | 		throw("runtime: netpoll failed") | 
 | 	} | 
 | 	op.errno = errno | 
 | 	op.qty = qty | 
 | 	netpollready(gpp, op.pd, mode) | 
 | } |