// 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. //go:build unix || windows || wasip1 package poll import ( "errors" "sync" "syscall" "time" _ "unsafe" // for go:linkname ) // runtimeNano returns the current value of the runtime clock in nanoseconds. // //go:linkname runtimeNano runtime.nanotime func runtimeNano() int64 func runtime_pollServerInit() func runtime_pollOpen(fd uintptr) (uintptr, int) func runtime_pollClose(ctx uintptr) func runtime_pollWait(ctx uintptr, mode int) int func runtime_pollWaitCanceled(ctx uintptr, mode int) func runtime_pollReset(ctx uintptr, mode int) int func runtime_pollSetDeadline(ctx uintptr, d int64, mode int) func runtime_pollUnblock(ctx uintptr) func runtime_isPollServerDescriptor(fd uintptr) bool type pollDesc struct { runtimeCtx uintptr } var serverInit sync.Once func (pd *pollDesc) init(fd *FD) error { serverInit.Do(runtime_pollServerInit) ctx, errno := runtime_pollOpen(uintptr(fd.Sysfd)) if errno != 0 { return errnoErr(syscall.Errno(errno)) } pd.runtimeCtx = ctx return nil } func (pd *pollDesc) close() { if pd.runtimeCtx == 0 { return } runtime_pollClose(pd.runtimeCtx) pd.runtimeCtx = 0 } // Evict evicts fd from the pending list, unblocking any I/O running on fd. func (pd *pollDesc) evict() { if pd.runtimeCtx == 0 { return } runtime_pollUnblock(pd.runtimeCtx) } func (pd *pollDesc) prepare(mode int, isFile bool) error { if pd.runtimeCtx == 0 { return nil } res := runtime_pollReset(pd.runtimeCtx, mode) return convertErr(res, isFile) } func (pd *pollDesc) prepareRead(isFile bool) error { return pd.prepare('r', isFile) } func (pd *pollDesc) prepareWrite(isFile bool) error { return pd.prepare('w', isFile) } func (pd *pollDesc) wait(mode int, isFile bool) error { if pd.runtimeCtx == 0 { return errors.New("waiting for unsupported file type") } res := runtime_pollWait(pd.runtimeCtx, mode) return convertErr(res, isFile) } func (pd *pollDesc) waitRead(isFile bool) error { return pd.wait('r', isFile) } func (pd *pollDesc) waitWrite(isFile bool) error { return pd.wait('w', isFile) } func (pd *pollDesc) waitCanceled(mode int) { if pd.runtimeCtx == 0 { return } runtime_pollWaitCanceled(pd.runtimeCtx, mode) } func (pd *pollDesc) pollable() bool { return pd.runtimeCtx != 0 } // Error values returned by runtime_pollReset and runtime_pollWait. // These must match the values in runtime/netpoll.go. const ( pollNoError = 0 pollErrClosing = 1 pollErrTimeout = 2 pollErrNotPollable = 3 ) func convertErr(res int, isFile bool) error { switch res { case pollNoError: return nil case pollErrClosing: return errClosing(isFile) case pollErrTimeout: return ErrDeadlineExceeded case pollErrNotPollable: return ErrNotPollable } println("unreachable: ", res) panic("unreachable") } // SetDeadline sets the read and write deadlines associated with fd. func (fd *FD) SetDeadline(t time.Time) error { return setDeadlineImpl(fd, t, 'r'+'w') } // SetReadDeadline sets the read deadline associated with fd. func (fd *FD) SetReadDeadline(t time.Time) error { return setDeadlineImpl(fd, t, 'r') } // SetWriteDeadline sets the write deadline associated with fd. func (fd *FD) SetWriteDeadline(t time.Time) error { return setDeadlineImpl(fd, t, 'w') } func setDeadlineImpl(fd *FD, t time.Time, mode int) error { var d int64 if !t.IsZero() { d = int64(time.Until(t)) if d == 0 { d = -1 // don't confuse deadline right now with no deadline } } if err := fd.incref(); err != nil { return err } defer fd.decref() if fd.pd.runtimeCtx == 0 { return ErrNoDeadline } runtime_pollSetDeadline(fd.pd.runtimeCtx, d, mode) return nil } // IsPollDescriptor reports whether fd is the descriptor being used by the poller. // This is only used for testing. func IsPollDescriptor(fd uintptr) bool { return runtime_isPollServerDescriptor(fd) }