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