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//go:build unix || windows || wasip1 6 7package poll 8 9import ( 10 "errors" 11 "sync" 12 "syscall" 13 "time" 14 _ "unsafe" // for go:linkname 15) 16 17// runtimeNano returns the current value of the runtime clock in nanoseconds. 18// 19//go:linkname runtimeNano runtime.nanotime 20func runtimeNano() int64 21 22func runtime_pollServerInit() 23func runtime_pollOpen(fd uintptr) (uintptr, int) 24func runtime_pollClose(ctx uintptr) 25func runtime_pollWait(ctx uintptr, mode int) int 26func runtime_pollWaitCanceled(ctx uintptr, mode int) 27func runtime_pollReset(ctx uintptr, mode int) int 28func runtime_pollSetDeadline(ctx uintptr, d int64, mode int) 29func runtime_pollUnblock(ctx uintptr) 30func runtime_isPollServerDescriptor(fd uintptr) bool 31 32type pollDesc struct { 33 runtimeCtx uintptr 34} 35 36var serverInit sync.Once 37 38func (pd *pollDesc) init(fd *FD) error { 39 serverInit.Do(runtime_pollServerInit) 40 ctx, errno := runtime_pollOpen(uintptr(fd.Sysfd)) 41 if errno != 0 { 42 return errnoErr(syscall.Errno(errno)) 43 } 44 pd.runtimeCtx = ctx 45 return nil 46} 47 48func (pd *pollDesc) close() { 49 if pd.runtimeCtx == 0 { 50 return 51 } 52 runtime_pollClose(pd.runtimeCtx) 53 pd.runtimeCtx = 0 54} 55 56// Evict evicts fd from the pending list, unblocking any I/O running on fd. 57func (pd *pollDesc) evict() { 58 if pd.runtimeCtx == 0 { 59 return 60 } 61 runtime_pollUnblock(pd.runtimeCtx) 62} 63 64func (pd *pollDesc) prepare(mode int, isFile bool) error { 65 if pd.runtimeCtx == 0 { 66 return nil 67 } 68 res := runtime_pollReset(pd.runtimeCtx, mode) 69 return convertErr(res, isFile) 70} 71 72func (pd *pollDesc) prepareRead(isFile bool) error { 73 return pd.prepare('r', isFile) 74} 75 76func (pd *pollDesc) prepareWrite(isFile bool) error { 77 return pd.prepare('w', isFile) 78} 79 80func (pd *pollDesc) wait(mode int, isFile bool) error { 81 if pd.runtimeCtx == 0 { 82 return errors.New("waiting for unsupported file type") 83 } 84 res := runtime_pollWait(pd.runtimeCtx, mode) 85 return convertErr(res, isFile) 86} 87 88func (pd *pollDesc) waitRead(isFile bool) error { 89 return pd.wait('r', isFile) 90} 91 92func (pd *pollDesc) waitWrite(isFile bool) error { 93 return pd.wait('w', isFile) 94} 95 96func (pd *pollDesc) waitCanceled(mode int) { 97 if pd.runtimeCtx == 0 { 98 return 99 } 100 runtime_pollWaitCanceled(pd.runtimeCtx, mode) 101} 102 103func (pd *pollDesc) pollable() bool { 104 return pd.runtimeCtx != 0 105} 106 107// Error values returned by runtime_pollReset and runtime_pollWait. 108// These must match the values in runtime/netpoll.go. 109const ( 110 pollNoError = 0 111 pollErrClosing = 1 112 pollErrTimeout = 2 113 pollErrNotPollable = 3 114) 115 116func convertErr(res int, isFile bool) error { 117 switch res { 118 case pollNoError: 119 return nil 120 case pollErrClosing: 121 return errClosing(isFile) 122 case pollErrTimeout: 123 return ErrDeadlineExceeded 124 case pollErrNotPollable: 125 return ErrNotPollable 126 } 127 println("unreachable: ", res) 128 panic("unreachable") 129} 130 131// SetDeadline sets the read and write deadlines associated with fd. 132func (fd *FD) SetDeadline(t time.Time) error { 133 return setDeadlineImpl(fd, t, 'r'+'w') 134} 135 136// SetReadDeadline sets the read deadline associated with fd. 137func (fd *FD) SetReadDeadline(t time.Time) error { 138 return setDeadlineImpl(fd, t, 'r') 139} 140 141// SetWriteDeadline sets the write deadline associated with fd. 142func (fd *FD) SetWriteDeadline(t time.Time) error { 143 return setDeadlineImpl(fd, t, 'w') 144} 145 146func setDeadlineImpl(fd *FD, t time.Time, mode int) error { 147 var d int64 148 if !t.IsZero() { 149 d = int64(time.Until(t)) 150 if d == 0 { 151 d = -1 // don't confuse deadline right now with no deadline 152 } 153 } 154 if err := fd.incref(); err != nil { 155 return err 156 } 157 defer fd.decref() 158 if fd.pd.runtimeCtx == 0 { 159 return ErrNoDeadline 160 } 161 runtime_pollSetDeadline(fd.pd.runtimeCtx, d, mode) 162 return nil 163} 164 165// IsPollDescriptor reports whether fd is the descriptor being used by the poller. 166// This is only used for testing. 167// 168// IsPollDescriptor should be an internal detail, 169// but widely used packages access it using linkname. 170// Notable members of the hall of shame include: 171// - github.com/opencontainers/runc 172// 173// Do not remove or change the type signature. 174// See go.dev/issue/67401. 175// 176//go:linkname IsPollDescriptor 177func IsPollDescriptor(fd uintptr) bool { 178 return runtime_isPollServerDescriptor(fd) 179} 180