diff options
author | Alex Brainman <alex.brainman@gmail.com> | 2014-11-14 14:07:28 +1100 |
---|---|---|
committer | Alex Brainman <alex.brainman@gmail.com> | 2014-11-14 14:07:28 +1100 |
commit | 49fb52997fba9f2daa48677a2084852b0c9d94a8 (patch) | |
tree | f11960dc14b61b94e5ff807ece053fe1d18471cc /src/runtime | |
parent | f175ae7b214ea0dffe02aeb590ee994dab8e5f3c (diff) | |
download | go-49fb52997fba9f2daa48677a2084852b0c9d94a8.tar.gz |
[dev.cc] runtime: convert netpoll_windows.c to Go
LGTM=rsc
R=rsc
CC=dvyukov, golang-codereviews
https://codereview.appspot.com/172530043
Diffstat (limited to 'src/runtime')
-rw-r--r-- | src/runtime/netpoll_windows.c | 163 | ||||
-rw-r--r-- | src/runtime/netpoll_windows.go | 156 | ||||
-rw-r--r-- | src/runtime/os_windows.go | 4 |
3 files changed, 156 insertions, 167 deletions
diff --git a/src/runtime/netpoll_windows.c b/src/runtime/netpoll_windows.c deleted file mode 100644 index 64da41ad9..000000000 --- a/src/runtime/netpoll_windows.c +++ /dev/null @@ -1,163 +0,0 @@ -// 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" -#pragma dynimport runtime·WSAGetOverlappedResult WSAGetOverlappedResult "ws2_32.dll" - -extern void *runtime·CreateIoCompletionPort; -extern void *runtime·GetQueuedCompletionStatus; -extern void *runtime·WSAGetOverlappedResult; - -#define INVALID_HANDLE_VALUE ((uintptr)-1) - -// net_op must be the same as beginning of net.operation. Keep these in sync. -typedef struct net_op net_op; -struct net_op -{ - // used by windows - Overlapped o; - // used by netpoll - PollDesc* pd; - int32 mode; - int32 errno; - uint32 qty; -}; - -typedef struct OverlappedEntry OverlappedEntry; -struct OverlappedEntry -{ - uintptr key; - net_op* op; // In reality it's Overlapped*, but we cast it to net_op* anyway. - uintptr internal; - uint32 qty; -}; - -static void handlecompletion(G **gpp, net_op *o, int32 errno, uint32 qty); - -static uintptr iocphandle = INVALID_HANDLE_VALUE; // completion port io handle - -void -runtime·netpollinit(void) -{ - iocphandle = (uintptr)runtime·stdcall4(runtime·CreateIoCompletionPort, INVALID_HANDLE_VALUE, 0, 0, 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·stdcall4(runtime·CreateIoCompletionPort, fd, iocphandle, 0, 0) == 0) - return -runtime·getlasterror(); - return 0; -} - -int32 -runtime·netpollclose(uintptr fd) -{ - // nothing to do - USED(fd); - return 0; -} - -void -runtime·netpollarm(PollDesc* pd, int32 mode) -{ - USED(pd, mode); - runtime·throw("unused"); -} - -// Polls for completed network IO. -// Returns list of goroutines that become runnable. -G* -runtime·netpoll(bool block) -{ - OverlappedEntry entries[64]; - uint32 wait, qty, key, flags, n, i; - int32 errno; - net_op *op; - G *gp; - - if(iocphandle == INVALID_HANDLE_VALUE) - return nil; - gp = nil; - wait = 0; - if(block) - wait = INFINITE; -retry: - if(runtime·GetQueuedCompletionStatusEx != nil) { - n = nelem(entries) / runtime·gomaxprocs; - if(n < 8) - n = 8; - if(block) - g->m->blocked = true; - if(runtime·stdcall6(runtime·GetQueuedCompletionStatusEx, iocphandle, (uintptr)entries, n, (uintptr)&n, wait, 0) == 0) { - g->m->blocked = false; - errno = runtime·getlasterror(); - if(!block && errno == WAIT_TIMEOUT) - return nil; - runtime·printf("netpoll: GetQueuedCompletionStatusEx failed (errno=%d)\n", errno); - runtime·throw("netpoll: GetQueuedCompletionStatusEx failed"); - } - g->m->blocked = false; - for(i = 0; i < n; i++) { - op = entries[i].op; - errno = 0; - qty = 0; - if(runtime·stdcall5(runtime·WSAGetOverlappedResult, runtime·netpollfd(op->pd), (uintptr)op, (uintptr)&qty, 0, (uintptr)&flags) == 0) - errno = runtime·getlasterror(); - handlecompletion(&gp, op, errno, qty); - } - } else { - op = nil; - errno = 0; - qty = 0; - if(block) - g->m->blocked = true; - if(runtime·stdcall5(runtime·GetQueuedCompletionStatus, iocphandle, (uintptr)&qty, (uintptr)&key, (uintptr)&op, wait) == 0) { - g->m->blocked = false; - errno = runtime·getlasterror(); - if(!block && errno == WAIT_TIMEOUT) - return nil; - if(op == nil) { - runtime·printf("netpoll: GetQueuedCompletionStatus failed (errno=%d)\n", errno); - runtime·throw("netpoll: GetQueuedCompletionStatus failed"); - } - // dequeued failed IO packet, so report that - } - g->m->blocked = false; - handlecompletion(&gp, op, errno, qty); - } - if(block && gp == nil) - goto retry; - return gp; -} - -static void -handlecompletion(G **gpp, net_op *op, int32 errno, uint32 qty) -{ - int32 mode; - - if(op == nil) - runtime·throw("netpoll: GetQueuedCompletionStatus returned op == nil"); - mode = op->mode; - if(mode != 'r' && mode != 'w') { - runtime·printf("netpoll: GetQueuedCompletionStatus returned invalid mode=%d\n", mode); - runtime·throw("netpoll: GetQueuedCompletionStatus returned invalid mode"); - } - op->errno = errno; - op->qty = qty; - runtime·netpollready(gpp, op->pd, mode); -} diff --git a/src/runtime/netpoll_windows.go b/src/runtime/netpoll_windows.go new file mode 100644 index 000000000..88e878137 --- /dev/null +++ b/src/runtime/netpoll_windows.go @@ -0,0 +1,156 @@ +// 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 + +//go:cgo_import_dynamic runtime._CreateIoCompletionPort CreateIoCompletionPort "kernel32.dll" +//go:cgo_import_dynamic runtime._GetQueuedCompletionStatus GetQueuedCompletionStatus "kernel32.dll" +//go:cgo_import_dynamic runtime._WSAGetOverlappedResult WSAGetOverlappedResult "ws2_32.dll" + +var ( + _CreateIoCompletionPort, + _GetQueuedCompletionStatus, + _WSAGetOverlappedResult stdFunction +) + +const _INVALID_HANDLE_VALUE = ^uintptr(0) + +// net_op must be the same as beginning of net.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 = uintptr(stdcall4(_CreateIoCompletionPort, _INVALID_HANDLE_VALUE, 0, 0, _DWORD_MAX)) + if iocphandle == 0 { + println("netpoll: failed to create iocp handle (errno=", getlasterror(), ")") + gothrow("netpoll: failed to create iocp handle") + } +} + +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) { + gothrow("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 *g + + mp := getg().m + + if iocphandle == _INVALID_HANDLE_VALUE { + return nil + } + gp = 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("netpoll: GetQueuedCompletionStatusEx failed (errno=", errno, ")") + gothrow("netpoll: GetQueuedCompletionStatusEx failed") + } + mp.blocked = false + for i = 0; i < n; i++ { + op = entries[i].op + errno = 0 + qty = 0 + if stdcall5(_WSAGetOverlappedResult, netpollfd(op.pd), 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("netpoll: GetQueuedCompletionStatus failed (errno=", errno, ")") + gothrow("netpoll: GetQueuedCompletionStatus failed") + } + // dequeued failed IO packet, so report that + } + mp.blocked = false + handlecompletion(&gp, op, errno, qty) + } + if block && gp == nil { + goto retry + } + return gp +} + +func handlecompletion(gpp **g, op *net_op, errno int32, qty uint32) { + if op == nil { + gothrow("netpoll: GetQueuedCompletionStatus returned op == nil") + } + mode := op.mode + if mode != 'r' && mode != 'w' { + println("netpoll: GetQueuedCompletionStatus returned invalid mode=", mode) + gothrow("netpoll: GetQueuedCompletionStatus returned invalid mode") + } + op.errno = errno + op.qty = qty + netpollready(gpp, op.pd, mode) +} diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go index 1528d2fd1..fcd8f44cc 100644 --- a/src/runtime/os_windows.go +++ b/src/runtime/os_windows.go @@ -21,10 +21,6 @@ func asmstdcall(fn unsafe.Pointer) func getlasterror() uint32 func setlasterror(err uint32) func usleep1(usec uint32) -func netpollinit() -func netpollopen(fd uintptr, pd *pollDesc) int32 -func netpollclose(fd uintptr) int32 -func netpollarm(pd *pollDesc, mode int) func os_sigpipe() { gothrow("too many writes on closed pipe") |