-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathtimeoutreader_unix.go
65 lines (55 loc) · 1.21 KB
/
timeoutreader_unix.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//go:build unix
// +build unix
package terminal
import (
"errors"
"io"
"os"
"syscall"
"time"
"fortio.org/log"
"fortio.org/safecast"
"golang.org/x/sys/unix"
)
const IsUnix = true
func TimeoutToTimeval(timeout time.Duration) *unix.Timeval {
tv := unix.NsecToTimeval(timeout.Nanoseconds())
return &tv
}
func ReadWithTimeout(fd int, tv *unix.Timeval, buf []byte) (int, error) {
var readfds unix.FdSet
readfds.Set(fd)
n, err := unix.Select(fd+1, &readfds, nil, nil, tv)
if errors.Is(err, syscall.EINTR) {
log.LogVf("Interrupted select")
return 0, nil
}
if err != nil {
log.Errf("Select error: %v", err)
return 0, err
}
if n == 0 {
return 0, nil // timeout case
}
n, err = unix.Read(fd, buf)
if n == 0 && err == nil {
err = io.EOF
}
return n, err
}
type TimeoutReader struct {
fd int
tv *unix.Timeval
}
func NewTimeoutReader(stream *os.File, timeout time.Duration) *TimeoutReader {
return &TimeoutReader{
fd: safecast.MustConvert[int](stream.Fd()),
tv: TimeoutToTimeval(timeout),
}
}
func (tr *TimeoutReader) Read(buf []byte) (int, error) {
return ReadWithTimeout(tr.fd, tr.tv, buf)
}
func (tr *TimeoutReader) ChangeTimeout(timeout time.Duration) {
tr.tv = TimeoutToTimeval(timeout)
}