github.com/fenixara/go@v0.0.0-20170127160404-96ea0918e670/src/runtime/netpoll_windows.go (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  package runtime
     6  
     7  import (
     8  	"unsafe"
     9  )
    10  
    11  const _DWORD_MAX = 0xffffffff
    12  
    13  const _INVALID_HANDLE_VALUE = ^uintptr(0)
    14  
    15  // net_op must be the same as beginning of net.operation. Keep these in sync.
    16  type net_op struct {
    17  	// used by windows
    18  	o overlapped
    19  	// used by netpoll
    20  	pd    *pollDesc
    21  	mode  int32
    22  	errno int32
    23  	qty   uint32
    24  }
    25  
    26  type overlappedEntry struct {
    27  	key      uintptr
    28  	op       *net_op // In reality it's *overlapped, but we cast it to *net_op anyway.
    29  	internal uintptr
    30  	qty      uint32
    31  }
    32  
    33  var iocphandle uintptr = _INVALID_HANDLE_VALUE // completion port io handle
    34  
    35  func netpollinit() {
    36  	iocphandle = stdcall4(_CreateIoCompletionPort, _INVALID_HANDLE_VALUE, 0, 0, _DWORD_MAX)
    37  	if iocphandle == 0 {
    38  		println("netpoll: failed to create iocp handle (errno=", getlasterror(), ")")
    39  		throw("netpoll: failed to create iocp handle")
    40  	}
    41  }
    42  
    43  func netpollopen(fd uintptr, pd *pollDesc) int32 {
    44  	if stdcall4(_CreateIoCompletionPort, fd, iocphandle, 0, 0) == 0 {
    45  		return -int32(getlasterror())
    46  	}
    47  	return 0
    48  }
    49  
    50  func netpollclose(fd uintptr) int32 {
    51  	// nothing to do
    52  	return 0
    53  }
    54  
    55  func netpollarm(pd *pollDesc, mode int) {
    56  	throw("unused")
    57  }
    58  
    59  // Polls for completed network IO.
    60  // Returns list of goroutines that become runnable.
    61  func netpoll(block bool) *g {
    62  	var entries [64]overlappedEntry
    63  	var wait, qty, key, flags, n, i uint32
    64  	var errno int32
    65  	var op *net_op
    66  	var gp guintptr
    67  
    68  	mp := getg().m
    69  
    70  	if iocphandle == _INVALID_HANDLE_VALUE {
    71  		return nil
    72  	}
    73  	wait = 0
    74  	if block {
    75  		wait = _INFINITE
    76  	}
    77  retry:
    78  	if _GetQueuedCompletionStatusEx != nil {
    79  		n = uint32(len(entries) / int(gomaxprocs))
    80  		if n < 8 {
    81  			n = 8
    82  		}
    83  		if block {
    84  			mp.blocked = true
    85  		}
    86  		if stdcall6(_GetQueuedCompletionStatusEx, iocphandle, uintptr(unsafe.Pointer(&entries[0])), uintptr(n), uintptr(unsafe.Pointer(&n)), uintptr(wait), 0) == 0 {
    87  			mp.blocked = false
    88  			errno = int32(getlasterror())
    89  			if !block && errno == _WAIT_TIMEOUT {
    90  				return nil
    91  			}
    92  			println("netpoll: GetQueuedCompletionStatusEx failed (errno=", errno, ")")
    93  			throw("netpoll: GetQueuedCompletionStatusEx failed")
    94  		}
    95  		mp.blocked = false
    96  		for i = 0; i < n; i++ {
    97  			op = entries[i].op
    98  			errno = 0
    99  			qty = 0
   100  			if stdcall5(_WSAGetOverlappedResult, op.pd.fd, uintptr(unsafe.Pointer(op)), uintptr(unsafe.Pointer(&qty)), 0, uintptr(unsafe.Pointer(&flags))) == 0 {
   101  				errno = int32(getlasterror())
   102  			}
   103  			handlecompletion(&gp, op, errno, qty)
   104  		}
   105  	} else {
   106  		op = nil
   107  		errno = 0
   108  		qty = 0
   109  		if block {
   110  			mp.blocked = true
   111  		}
   112  		if stdcall5(_GetQueuedCompletionStatus, iocphandle, uintptr(unsafe.Pointer(&qty)), uintptr(unsafe.Pointer(&key)), uintptr(unsafe.Pointer(&op)), uintptr(wait)) == 0 {
   113  			mp.blocked = false
   114  			errno = int32(getlasterror())
   115  			if !block && errno == _WAIT_TIMEOUT {
   116  				return nil
   117  			}
   118  			if op == nil {
   119  				println("netpoll: GetQueuedCompletionStatus failed (errno=", errno, ")")
   120  				throw("netpoll: GetQueuedCompletionStatus failed")
   121  			}
   122  			// dequeued failed IO packet, so report that
   123  		}
   124  		mp.blocked = false
   125  		handlecompletion(&gp, op, errno, qty)
   126  	}
   127  	if block && gp == 0 {
   128  		goto retry
   129  	}
   130  	return gp.ptr()
   131  }
   132  
   133  func handlecompletion(gpp *guintptr, op *net_op, errno int32, qty uint32) {
   134  	if op == nil {
   135  		throw("netpoll: GetQueuedCompletionStatus returned op == nil")
   136  	}
   137  	mode := op.mode
   138  	if mode != 'r' && mode != 'w' {
   139  		println("netpoll: GetQueuedCompletionStatus returned invalid mode=", mode)
   140  		throw("netpoll: GetQueuedCompletionStatus returned invalid mode")
   141  	}
   142  	op.errno = errno
   143  	op.qty = qty
   144  	netpollready(gpp, op.pd, mode)
   145  }