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// +build aix darwin dragonfly freebsd hurd linux netbsd openbsd windows solaris
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//go:linkname runtimeNano runtime.nanotime
19func runtimeNano() int64
20
21func runtime_pollServerInit()
22func runtime_pollOpen(fd uintptr) (uintptr, int)
23func runtime_pollClose(ctx uintptr)
24func runtime_pollWait(ctx uintptr, mode int) int
25func runtime_pollWaitCanceled(ctx uintptr, mode int) int
26func runtime_pollReset(ctx uintptr, mode int) int
27func runtime_pollSetDeadline(ctx uintptr, d int64, mode int)
28func runtime_pollUnblock(ctx uintptr)
29func runtime_isPollServerDescriptor(fd uintptr) bool
30
31type pollDesc struct {
32	runtimeCtx uintptr
33}
34
35var serverInit sync.Once
36
37func (pd *pollDesc) init(fd *FD) error {
38	serverInit.Do(runtime_pollServerInit)
39	ctx, errno := runtime_pollOpen(uintptr(fd.Sysfd))
40	if errno != 0 {
41		if ctx != 0 {
42			runtime_pollUnblock(ctx)
43			runtime_pollClose(ctx)
44		}
45		return errnoErr(syscall.Errno(errno))
46	}
47	pd.runtimeCtx = ctx
48	return nil
49}
50
51func (pd *pollDesc) close() {
52	if pd.runtimeCtx == 0 {
53		return
54	}
55	runtime_pollClose(pd.runtimeCtx)
56	pd.runtimeCtx = 0
57}
58
59// Evict evicts fd from the pending list, unblocking any I/O running on fd.
60func (pd *pollDesc) evict() {
61	if pd.runtimeCtx == 0 {
62		return
63	}
64	runtime_pollUnblock(pd.runtimeCtx)
65}
66
67func (pd *pollDesc) prepare(mode int, isFile bool) error {
68	if pd.runtimeCtx == 0 {
69		return nil
70	}
71	res := runtime_pollReset(pd.runtimeCtx, mode)
72	return convertErr(res, isFile)
73}
74
75func (pd *pollDesc) prepareRead(isFile bool) error {
76	return pd.prepare('r', isFile)
77}
78
79func (pd *pollDesc) prepareWrite(isFile bool) error {
80	return pd.prepare('w', isFile)
81}
82
83func (pd *pollDesc) wait(mode int, isFile bool) error {
84	if pd.runtimeCtx == 0 {
85		return errors.New("waiting for unsupported file type")
86	}
87	res := runtime_pollWait(pd.runtimeCtx, mode)
88	return convertErr(res, isFile)
89}
90
91func (pd *pollDesc) waitRead(isFile bool) error {
92	return pd.wait('r', isFile)
93}
94
95func (pd *pollDesc) waitWrite(isFile bool) error {
96	return pd.wait('w', isFile)
97}
98
99func (pd *pollDesc) waitCanceled(mode int) {
100	if pd.runtimeCtx == 0 {
101		return
102	}
103	runtime_pollWaitCanceled(pd.runtimeCtx, mode)
104}
105
106func (pd *pollDesc) pollable() bool {
107	return pd.runtimeCtx != 0
108}
109
110func convertErr(res int, isFile bool) error {
111	switch res {
112	case 0:
113		return nil
114	case 1:
115		return errClosing(isFile)
116	case 2:
117		return ErrTimeout
118	case 3:
119		return ErrNotPollable
120	}
121	println("unreachable: ", res)
122	panic("unreachable")
123}
124
125// SetDeadline sets the read and write deadlines associated with fd.
126func (fd *FD) SetDeadline(t time.Time) error {
127	return setDeadlineImpl(fd, t, 'r'+'w')
128}
129
130// SetReadDeadline sets the read deadline associated with fd.
131func (fd *FD) SetReadDeadline(t time.Time) error {
132	return setDeadlineImpl(fd, t, 'r')
133}
134
135// SetWriteDeadline sets the write deadline associated with fd.
136func (fd *FD) SetWriteDeadline(t time.Time) error {
137	return setDeadlineImpl(fd, t, 'w')
138}
139
140func setDeadlineImpl(fd *FD, t time.Time, mode int) error {
141	var d int64
142	if !t.IsZero() {
143		d = int64(time.Until(t))
144		if d == 0 {
145			d = -1 // don't confuse deadline right now with no deadline
146		}
147	}
148	if err := fd.incref(); err != nil {
149		return err
150	}
151	defer fd.decref()
152	if fd.pd.runtimeCtx == 0 {
153		return ErrNoDeadline
154	}
155	runtime_pollSetDeadline(fd.pd.runtimeCtx, d, mode)
156	return nil
157}
158
159// IsPollDescriptor reports whether fd is the descriptor being used by the poller.
160// This is only used for testing.
161func IsPollDescriptor(fd uintptr) bool {
162	return runtime_isPollServerDescriptor(fd)
163}
164