github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/pkg/runtime/netpoll_windows.c (about)

     1  // Copyright 2013 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  #include "runtime.h"
     6  #include "defs_GOOS_GOARCH.h"
     7  #include "os_GOOS.h"
     8  
     9  #define DWORD_MAX 0xffffffff
    10  
    11  #pragma dynimport runtime·CreateIoCompletionPort CreateIoCompletionPort "kernel32.dll"
    12  #pragma dynimport runtime·GetQueuedCompletionStatus GetQueuedCompletionStatus "kernel32.dll"
    13  #pragma dynimport runtime·WSAGetOverlappedResult WSAGetOverlappedResult "ws2_32.dll"
    14  
    15  extern void *runtime·CreateIoCompletionPort;
    16  extern void *runtime·GetQueuedCompletionStatus;
    17  extern void *runtime·WSAGetOverlappedResult;
    18  
    19  #define INVALID_HANDLE_VALUE ((uintptr)-1)
    20  
    21  // net_op must be the same as beginning of net.operation. Keep these in sync.
    22  typedef struct net_op net_op;
    23  struct net_op
    24  {
    25  	// used by windows
    26  	Overlapped	o;
    27  	// used by netpoll
    28  	PollDesc*	pd;
    29  	int32	mode;
    30  	int32	errno;
    31  	uint32	qty;
    32  };
    33  
    34  typedef struct OverlappedEntry OverlappedEntry;
    35  struct OverlappedEntry
    36  {
    37  	uintptr	key;
    38  	net_op*	op;  // In reality it's Overlapped*, but we cast it to net_op* anyway.
    39  	uintptr	internal;
    40  	uint32	qty;
    41  };
    42  
    43  static void handlecompletion(G **gpp, net_op *o, int32 errno, uint32 qty);
    44  
    45  static uintptr iocphandle = INVALID_HANDLE_VALUE;  // completion port io handle
    46  
    47  void
    48  runtime·netpollinit(void)
    49  {
    50  	iocphandle = (uintptr)runtime·stdcall(runtime·CreateIoCompletionPort, 4, INVALID_HANDLE_VALUE, (uintptr)0, (uintptr)0, (uintptr)DWORD_MAX);
    51  	if(iocphandle == 0) {
    52  		runtime·printf("netpoll: failed to create iocp handle (errno=%d)\n", runtime·getlasterror());
    53  		runtime·throw("netpoll: failed to create iocp handle");
    54  	}
    55  	return;
    56  }
    57  
    58  int32
    59  runtime·netpollopen(uintptr fd, PollDesc *pd)
    60  {
    61  	USED(pd);
    62  	if(runtime·stdcall(runtime·CreateIoCompletionPort, 4, fd, iocphandle, (uintptr)0, (uintptr)0) == 0)
    63  		return -runtime·getlasterror();
    64  	return 0;
    65  }
    66  
    67  int32
    68  runtime·netpollclose(uintptr fd)
    69  {
    70  	// nothing to do
    71  	USED(fd);
    72  	return 0;
    73  }
    74  
    75  // Polls for completed network IO.
    76  // Returns list of goroutines that become runnable.
    77  G*
    78  runtime·netpoll(bool block)
    79  {
    80  	OverlappedEntry entries[64];
    81  	uint32 wait, qty, key, flags, n, i;
    82  	int32 errno;
    83  	net_op *op;
    84  	G *gp;
    85  
    86  	if(iocphandle == INVALID_HANDLE_VALUE)
    87  		return nil;
    88  	gp = nil;
    89  	wait = 0;
    90  	if(block)
    91  		wait = INFINITE;
    92  retry:
    93  	if(runtime·GetQueuedCompletionStatusEx != nil) {
    94  		n = nelem(entries) / runtime·gomaxprocs;
    95  		if(n < 8)
    96  			n = 8;
    97  		if(runtime·stdcall(runtime·GetQueuedCompletionStatusEx, 6, iocphandle, entries, (uintptr)n, &n, (uintptr)wait, (uintptr)0) == 0) {
    98  			errno = runtime·getlasterror();
    99  			if(!block && errno == WAIT_TIMEOUT)
   100  				return nil;
   101  			runtime·printf("netpoll: GetQueuedCompletionStatusEx failed (errno=%d)\n", errno);
   102  			runtime·throw("netpoll: GetQueuedCompletionStatusEx failed");
   103  		}
   104  		for(i = 0; i < n; i++) {
   105  			op = entries[i].op;
   106  			errno = 0;
   107  			qty = 0;
   108  			if(runtime·stdcall(runtime·WSAGetOverlappedResult, 5, runtime·netpollfd(op->pd), op, &qty, (uintptr)0, (uintptr)&flags) == 0)
   109  				errno = runtime·getlasterror();
   110  			handlecompletion(&gp, op, errno, qty);
   111  		}
   112  	} else {
   113  		op = nil;
   114  		errno = 0;
   115  		qty = 0;
   116  		if(runtime·stdcall(runtime·GetQueuedCompletionStatus, 5, iocphandle, &qty, &key, &op, (uintptr)wait) == 0) {
   117  			errno = runtime·getlasterror();
   118  			if(!block && errno == WAIT_TIMEOUT)
   119  				return nil;
   120  			if(op == nil) {
   121  				runtime·printf("netpoll: GetQueuedCompletionStatus failed (errno=%d)\n", errno);
   122  				runtime·throw("netpoll: GetQueuedCompletionStatus failed");
   123  			}
   124  			// dequeued failed IO packet, so report that
   125  		}
   126  		handlecompletion(&gp, op, errno, qty);
   127  	}
   128  	if(block && gp == nil)
   129  		goto retry;
   130  	return gp;
   131  }
   132  
   133  static void
   134  handlecompletion(G **gpp, net_op *op, int32 errno, uint32 qty)
   135  {
   136  	int32 mode;
   137  
   138  	if(op == nil)
   139  		runtime·throw("netpoll: GetQueuedCompletionStatus returned op == nil");
   140  	mode = op->mode;
   141  	if(mode != 'r' && mode != 'w') {
   142  		runtime·printf("netpoll: GetQueuedCompletionStatus returned invalid mode=%d\n", mode);
   143  		runtime·throw("netpoll: GetQueuedCompletionStatus returned invalid mode");
   144  	}
   145  	op->errno = errno;
   146  	op->qty = qty;
   147  	runtime·netpollready(gpp, op->pd, mode);
   148  }