diff options
author | Russ Cox <rsc@golang.org> | 2014-09-08 00:08:51 -0400 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2014-09-08 00:08:51 -0400 |
commit | 8528da672cc093d4dd06732819abc1f7b6b5a46e (patch) | |
tree | 334be80d4a4c85b77db6f6fdb67cbf0528cba5f5 /src/runtime/netpoll_windows.c | |
parent | 73bcb69f272cbf34ddcc9daa56427a8683b5a95d (diff) | |
download | go-8528da672cc093d4dd06732819abc1f7b6b5a46e.tar.gz |
build: move package sources from src/pkg to src
Preparation was in CL 134570043.
This CL contains only the effect of 'hg mv src/pkg/* src'.
For more about the move, see golang.org/s/go14nopkg.
Diffstat (limited to 'src/runtime/netpoll_windows.c')
-rw-r--r-- | src/runtime/netpoll_windows.c | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/src/runtime/netpoll_windows.c b/src/runtime/netpoll_windows.c new file mode 100644 index 000000000..64da41ad9 --- /dev/null +++ b/src/runtime/netpoll_windows.c @@ -0,0 +1,163 @@ +// 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); +} |