mirror of https://github.com/golang/go.git
runtime,internal/poll: move websocket handling out of the runtime on Windows
On Windows, the netpoll is currently coupled with the websocket usage in the internal/poll package. This CL moves the websocket handling out of the runtime and puts it into the internal/poll package, which already contains most of the async I/O logic for websockets. This is a good refactor per se, as the Go runtime shouldn't know about websockets. In addition, it will make it easier (in a future CL) to only load ws2_32.dll when the Go program actually uses websockets. Change-Id: Ic820872cf9bdbbf092505ed7f7504edb6687735e Reviewed-on: https://go-review.googlesource.com/c/go/+/556936 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Bryan Mills <bcmills@google.com> Reviewed-by: Cherry Mui <cherryyz@google.com>
This commit is contained in:
parent
704401ffa0
commit
d0dc93c8e1
|
|
@ -71,8 +71,6 @@ type operation struct {
|
||||||
// fields used by runtime.netpoll
|
// fields used by runtime.netpoll
|
||||||
runtimeCtx uintptr
|
runtimeCtx uintptr
|
||||||
mode int32
|
mode int32
|
||||||
errno int32
|
|
||||||
qty uint32
|
|
||||||
|
|
||||||
// fields used only by net package
|
// fields used only by net package
|
||||||
fd *FD
|
fd *FD
|
||||||
|
|
@ -83,6 +81,7 @@ type operation struct {
|
||||||
rsan int32
|
rsan int32
|
||||||
handle syscall.Handle
|
handle syscall.Handle
|
||||||
flags uint32
|
flags uint32
|
||||||
|
qty uint32
|
||||||
bufs []syscall.WSABuf
|
bufs []syscall.WSABuf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -174,9 +173,9 @@ func execIO(o *operation, submit func(o *operation) error) (int, error) {
|
||||||
// Wait for our request to complete.
|
// Wait for our request to complete.
|
||||||
err = fd.pd.wait(int(o.mode), fd.isFile)
|
err = fd.pd.wait(int(o.mode), fd.isFile)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
err = windows.WSAGetOverlappedResult(fd.Sysfd, &o.o, &o.qty, false, &o.flags)
|
||||||
// All is good. Extract our IO results and return.
|
// All is good. Extract our IO results and return.
|
||||||
if o.errno != 0 {
|
if err != nil {
|
||||||
err = syscall.Errno(o.errno)
|
|
||||||
// More data available. Return back the size of received data.
|
// More data available. Return back the size of received data.
|
||||||
if err == syscall.ERROR_MORE_DATA || err == windows.WSAEMSGSIZE {
|
if err == syscall.ERROR_MORE_DATA || err == windows.WSAEMSGSIZE {
|
||||||
return int(o.qty), err
|
return int(o.qty), err
|
||||||
|
|
@ -202,8 +201,8 @@ func execIO(o *operation, submit func(o *operation) error) (int, error) {
|
||||||
}
|
}
|
||||||
// Wait for cancellation to complete.
|
// Wait for cancellation to complete.
|
||||||
fd.pd.waitCanceled(int(o.mode))
|
fd.pd.waitCanceled(int(o.mode))
|
||||||
if o.errno != 0 {
|
err = windows.WSAGetOverlappedResult(fd.Sysfd, &o.o, &o.qty, false, &o.flags)
|
||||||
err = syscall.Errno(o.errno)
|
if err != nil {
|
||||||
if err == syscall.ERROR_OPERATION_ABORTED { // IO Canceled
|
if err == syscall.ERROR_OPERATION_ABORTED { // IO Canceled
|
||||||
err = netpollErr
|
err = netpollErr
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -235,6 +235,7 @@ type WSAMsg struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
//sys WSASocket(af int32, typ int32, protocol int32, protinfo *syscall.WSAProtocolInfo, group uint32, flags uint32) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = ws2_32.WSASocketW
|
//sys WSASocket(af int32, typ int32, protocol int32, protinfo *syscall.WSAProtocolInfo, group uint32, flags uint32) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = ws2_32.WSASocketW
|
||||||
|
//sys WSAGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) = ws2_32.WSAGetOverlappedResult
|
||||||
|
|
||||||
func loadWSASendRecvMsg() error {
|
func loadWSASendRecvMsg() error {
|
||||||
sendRecvMsgFunc.once.Do(func() {
|
sendRecvMsgFunc.once.Do(func() {
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,7 @@ var (
|
||||||
procCreateEnvironmentBlock = moduserenv.NewProc("CreateEnvironmentBlock")
|
procCreateEnvironmentBlock = moduserenv.NewProc("CreateEnvironmentBlock")
|
||||||
procDestroyEnvironmentBlock = moduserenv.NewProc("DestroyEnvironmentBlock")
|
procDestroyEnvironmentBlock = moduserenv.NewProc("DestroyEnvironmentBlock")
|
||||||
procGetProfilesDirectoryW = moduserenv.NewProc("GetProfilesDirectoryW")
|
procGetProfilesDirectoryW = moduserenv.NewProc("GetProfilesDirectoryW")
|
||||||
|
procWSAGetOverlappedResult = modws2_32.NewProc("WSAGetOverlappedResult")
|
||||||
procWSASocketW = modws2_32.NewProc("WSASocketW")
|
procWSASocketW = modws2_32.NewProc("WSASocketW")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -426,6 +427,18 @@ func GetProfilesDirectory(dir *uint16, dirLen *uint32) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WSAGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) {
|
||||||
|
var _p0 uint32
|
||||||
|
if wait {
|
||||||
|
_p0 = 1
|
||||||
|
}
|
||||||
|
r1, _, e1 := syscall.Syscall6(procWSAGetOverlappedResult.Addr(), 5, uintptr(h), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(bytes)), uintptr(_p0), uintptr(unsafe.Pointer(flags)), 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func WSASocket(af int32, typ int32, protocol int32, protinfo *syscall.WSAProtocolInfo, group uint32, flags uint32) (handle syscall.Handle, err error) {
|
func WSASocket(af int32, typ int32, protocol int32, protinfo *syscall.WSAProtocolInfo, group uint32, flags uint32) (handle syscall.Handle, err error) {
|
||||||
r0, _, e1 := syscall.Syscall6(procWSASocketW.Addr(), 6, uintptr(af), uintptr(typ), uintptr(protocol), uintptr(unsafe.Pointer(protinfo)), uintptr(group), uintptr(flags))
|
r0, _, e1 := syscall.Syscall6(procWSASocketW.Addr(), 6, uintptr(af), uintptr(typ), uintptr(protocol), uintptr(unsafe.Pointer(protinfo)), uintptr(group), uintptr(flags))
|
||||||
handle = syscall.Handle(r0)
|
handle = syscall.Handle(r0)
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,8 @@ type net_op struct {
|
||||||
// used by windows
|
// used by windows
|
||||||
o overlapped
|
o overlapped
|
||||||
// used by netpoll
|
// used by netpoll
|
||||||
pd *pollDesc
|
pd *pollDesc
|
||||||
mode int32
|
mode int32
|
||||||
errno int32
|
|
||||||
qty uint32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type overlappedEntry struct {
|
type overlappedEntry struct {
|
||||||
|
|
@ -86,7 +84,7 @@ func netpollBreak() {
|
||||||
// delay > 0: block for up to that many nanoseconds
|
// delay > 0: block for up to that many nanoseconds
|
||||||
func netpoll(delay int64) (gList, int32) {
|
func netpoll(delay int64) (gList, int32) {
|
||||||
var entries [64]overlappedEntry
|
var entries [64]overlappedEntry
|
||||||
var wait, qty, flags, n, i uint32
|
var wait, n, i uint32
|
||||||
var errno int32
|
var errno int32
|
||||||
var op *net_op
|
var op *net_op
|
||||||
var toRun gList
|
var toRun gList
|
||||||
|
|
@ -131,12 +129,12 @@ func netpoll(delay int64) (gList, int32) {
|
||||||
for i = 0; i < n; i++ {
|
for i = 0; i < n; i++ {
|
||||||
op = entries[i].op
|
op = entries[i].op
|
||||||
if op != nil && op.pd == entries[i].key {
|
if op != nil && op.pd == entries[i].key {
|
||||||
errno = 0
|
mode := op.mode
|
||||||
qty = 0
|
if mode != 'r' && mode != 'w' {
|
||||||
if stdcall5(_WSAGetOverlappedResult, op.pd.fd, uintptr(unsafe.Pointer(op)), uintptr(unsafe.Pointer(&qty)), 0, uintptr(unsafe.Pointer(&flags))) == 0 {
|
println("runtime: GetQueuedCompletionStatusEx returned net_op with invalid mode=", mode)
|
||||||
errno = int32(getlasterror())
|
throw("runtime: netpoll failed")
|
||||||
}
|
}
|
||||||
delta += handlecompletion(&toRun, op, errno, qty)
|
delta += netpollready(&toRun, op.pd, mode)
|
||||||
} else {
|
} else {
|
||||||
netpollWakeSig.Store(0)
|
netpollWakeSig.Store(0)
|
||||||
if delay == 0 {
|
if delay == 0 {
|
||||||
|
|
@ -148,14 +146,3 @@ func netpoll(delay int64) (gList, int32) {
|
||||||
}
|
}
|
||||||
return toRun, delta
|
return toRun, delta
|
||||||
}
|
}
|
||||||
|
|
||||||
func handlecompletion(toRun *gList, op *net_op, errno int32, qty uint32) int32 {
|
|
||||||
mode := op.mode
|
|
||||||
if mode != 'r' && mode != 'w' {
|
|
||||||
println("runtime: GetQueuedCompletionStatusEx returned invalid mode=", mode)
|
|
||||||
throw("runtime: netpoll failed")
|
|
||||||
}
|
|
||||||
op.errno = errno
|
|
||||||
op.qty = qty
|
|
||||||
return netpollready(toRun, op.pd, mode)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,6 @@ var (
|
||||||
// These are from non-kernel32.dll, so we prefer to LoadLibraryEx them.
|
// These are from non-kernel32.dll, so we prefer to LoadLibraryEx them.
|
||||||
_timeBeginPeriod,
|
_timeBeginPeriod,
|
||||||
_timeEndPeriod,
|
_timeEndPeriod,
|
||||||
_WSAGetOverlappedResult,
|
|
||||||
_ stdFunction
|
_ stdFunction
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -148,7 +147,6 @@ var (
|
||||||
ntdlldll = [...]uint16{'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', 0}
|
ntdlldll = [...]uint16{'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', 0}
|
||||||
powrprofdll = [...]uint16{'p', 'o', 'w', 'r', 'p', 'r', 'o', 'f', '.', 'd', 'l', 'l', 0}
|
powrprofdll = [...]uint16{'p', 'o', 'w', 'r', 'p', 'r', 'o', 'f', '.', 'd', 'l', 'l', 0}
|
||||||
winmmdll = [...]uint16{'w', 'i', 'n', 'm', 'm', '.', 'd', 'l', 'l', 0}
|
winmmdll = [...]uint16{'w', 'i', 'n', 'm', 'm', '.', 'd', 'l', 'l', 0}
|
||||||
ws2_32dll = [...]uint16{'w', 's', '2', '_', '3', '2', '.', 'd', 'l', 'l', 0}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Function to be called by windows CreateThread
|
// Function to be called by windows CreateThread
|
||||||
|
|
@ -256,15 +254,6 @@ func loadOptionalSyscalls() {
|
||||||
}
|
}
|
||||||
_RtlGetCurrentPeb = windowsFindfunc(n32, []byte("RtlGetCurrentPeb\000"))
|
_RtlGetCurrentPeb = windowsFindfunc(n32, []byte("RtlGetCurrentPeb\000"))
|
||||||
_RtlGetNtVersionNumbers = windowsFindfunc(n32, []byte("RtlGetNtVersionNumbers\000"))
|
_RtlGetNtVersionNumbers = windowsFindfunc(n32, []byte("RtlGetNtVersionNumbers\000"))
|
||||||
|
|
||||||
ws232 := windowsLoadSystemLib(ws2_32dll[:])
|
|
||||||
if ws232 == 0 {
|
|
||||||
throw("ws2_32.dll not found")
|
|
||||||
}
|
|
||||||
_WSAGetOverlappedResult = windowsFindfunc(ws232, []byte("WSAGetOverlappedResult\000"))
|
|
||||||
if _WSAGetOverlappedResult == nil {
|
|
||||||
throw("WSAGetOverlappedResult not found")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func monitorSuspendResume() {
|
func monitorSuspendResume() {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue