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