...

Source file src/runtime/netpoll_windows.go

     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) gList {
    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 toRun gList
    72	
    73		mp := getg().m
    74	
    75		if iocphandle == _INVALID_HANDLE_VALUE {
    76			return gList{}
    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 gList{}
    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(&toRun, 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 gList{}
   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(&toRun, op, errno, qty)
   131		}
   132		if block && toRun.empty() {
   133			goto retry
   134		}
   135		return toRun
   136	}
   137	
   138	func handlecompletion(toRun *gList, 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(toRun, op.pd, mode)
   151	}
   152	

View as plain text