| // 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. | |
| // +build aix darwin dragonfly freebsd linux netbsd openbsd windows solaris | |
| 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) 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 { | |
| if ctx != 0 { | |
| runtime_pollUnblock(ctx) | |
| runtime_pollClose(ctx) | |
| } | |
| 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) | |
| } |