mirror of
https://github.com/golang/go
synced 2024-11-20 06:34:40 -07:00
181e26b9fa
This CL revises CL 7504 to use explicitly uintptr types for the struct fields that are going to be updated sometimes without write barriers. The result is that the fields are now updated *always* without write barriers. This approach has two important properties: 1) Now the GC never looks at the field, so if the missing reference could cause a problem, it will do so all the time, not just when the write barrier is missed at just the right moment. 2) Now a write barrier never happens for the field, avoiding the (correct) detection of inconsistent write barriers when GODEBUG=wbshadow=1. Change-Id: Iebd3962c727c0046495cc08914a8dc0808460e0e Reviewed-on: https://go-review.googlesource.com/9019 Reviewed-by: Austin Clements <austin@google.com> Run-TryBot: Russ Cox <rsc@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
146 lines
3.6 KiB
Go
146 lines
3.6 KiB
Go
// Copyright 2013 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package runtime
|
|
|
|
import (
|
|
"unsafe"
|
|
)
|
|
|
|
const _DWORD_MAX = 0xffffffff
|
|
|
|
const _INVALID_HANDLE_VALUE = ^uintptr(0)
|
|
|
|
// net_op must be the same as beginning of net.operation. Keep these in sync.
|
|
type net_op struct {
|
|
// used by windows
|
|
o overlapped
|
|
// used by netpoll
|
|
pd *pollDesc
|
|
mode int32
|
|
errno int32
|
|
qty uint32
|
|
}
|
|
|
|
type overlappedEntry struct {
|
|
key uintptr
|
|
op *net_op // In reality it's *overlapped, but we cast it to *net_op anyway.
|
|
internal uintptr
|
|
qty uint32
|
|
}
|
|
|
|
var iocphandle uintptr = _INVALID_HANDLE_VALUE // completion port io handle
|
|
|
|
func netpollinit() {
|
|
iocphandle = uintptr(stdcall4(_CreateIoCompletionPort, _INVALID_HANDLE_VALUE, 0, 0, _DWORD_MAX))
|
|
if iocphandle == 0 {
|
|
println("netpoll: failed to create iocp handle (errno=", getlasterror(), ")")
|
|
throw("netpoll: failed to create iocp handle")
|
|
}
|
|
}
|
|
|
|
func netpollopen(fd uintptr, pd *pollDesc) int32 {
|
|
if stdcall4(_CreateIoCompletionPort, fd, iocphandle, 0, 0) == 0 {
|
|
return -int32(getlasterror())
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func netpollclose(fd uintptr) int32 {
|
|
// nothing to do
|
|
return 0
|
|
}
|
|
|
|
func netpollarm(pd *pollDesc, mode int) {
|
|
throw("unused")
|
|
}
|
|
|
|
// Polls for completed network IO.
|
|
// Returns list of goroutines that become runnable.
|
|
func netpoll(block bool) *g {
|
|
var entries [64]overlappedEntry
|
|
var wait, qty, key, flags, n, i uint32
|
|
var errno int32
|
|
var op *net_op
|
|
var gp guintptr
|
|
|
|
mp := getg().m
|
|
|
|
if iocphandle == _INVALID_HANDLE_VALUE {
|
|
return nil
|
|
}
|
|
wait = 0
|
|
if block {
|
|
wait = _INFINITE
|
|
}
|
|
retry:
|
|
if _GetQueuedCompletionStatusEx != nil {
|
|
n = uint32(len(entries) / int(gomaxprocs))
|
|
if n < 8 {
|
|
n = 8
|
|
}
|
|
if block {
|
|
mp.blocked = true
|
|
}
|
|
if stdcall6(_GetQueuedCompletionStatusEx, iocphandle, uintptr(unsafe.Pointer(&entries[0])), uintptr(n), uintptr(unsafe.Pointer(&n)), uintptr(wait), 0) == 0 {
|
|
mp.blocked = false
|
|
errno = int32(getlasterror())
|
|
if !block && errno == _WAIT_TIMEOUT {
|
|
return nil
|
|
}
|
|
println("netpoll: GetQueuedCompletionStatusEx failed (errno=", errno, ")")
|
|
throw("netpoll: GetQueuedCompletionStatusEx failed")
|
|
}
|
|
mp.blocked = false
|
|
for i = 0; i < n; i++ {
|
|
op = entries[i].op
|
|
errno = 0
|
|
qty = 0
|
|
if stdcall5(_WSAGetOverlappedResult, op.pd.fd, uintptr(unsafe.Pointer(op)), uintptr(unsafe.Pointer(&qty)), 0, uintptr(unsafe.Pointer(&flags))) == 0 {
|
|
errno = int32(getlasterror())
|
|
}
|
|
handlecompletion(&gp, op, errno, qty)
|
|
}
|
|
} else {
|
|
op = nil
|
|
errno = 0
|
|
qty = 0
|
|
if block {
|
|
mp.blocked = true
|
|
}
|
|
if stdcall5(_GetQueuedCompletionStatus, iocphandle, uintptr(unsafe.Pointer(&qty)), uintptr(unsafe.Pointer(&key)), uintptr(unsafe.Pointer(&op)), uintptr(wait)) == 0 {
|
|
mp.blocked = false
|
|
errno = int32(getlasterror())
|
|
if !block && errno == _WAIT_TIMEOUT {
|
|
return nil
|
|
}
|
|
if op == nil {
|
|
println("netpoll: GetQueuedCompletionStatus failed (errno=", errno, ")")
|
|
throw("netpoll: GetQueuedCompletionStatus failed")
|
|
}
|
|
// dequeued failed IO packet, so report that
|
|
}
|
|
mp.blocked = false
|
|
handlecompletion(&gp, op, errno, qty)
|
|
}
|
|
if block && gp == 0 {
|
|
goto retry
|
|
}
|
|
return gp.ptr()
|
|
}
|
|
|
|
func handlecompletion(gpp *guintptr, op *net_op, errno int32, qty uint32) {
|
|
if op == nil {
|
|
throw("netpoll: GetQueuedCompletionStatus returned op == nil")
|
|
}
|
|
mode := op.mode
|
|
if mode != 'r' && mode != 'w' {
|
|
println("netpoll: GetQueuedCompletionStatus returned invalid mode=", mode)
|
|
throw("netpoll: GetQueuedCompletionStatus returned invalid mode")
|
|
}
|
|
op.errno = errno
|
|
op.qty = qty
|
|
netpollready(gpp, op.pd, mode)
|
|
}
|