-
Notifications
You must be signed in to change notification settings - Fork 14
/
poll_linux.go
112 lines (100 loc) · 2.73 KB
/
poll_linux.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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// Copyright (c) 2020 Meng Huang ([email protected])
// This package is licensed under a MIT license that can be found in the LICENSE file.
//go:build linux
// +build linux
package netpoll
import (
"sync"
"syscall"
"time"
)
// Tag is the poll type.
var Tag = "epoll"
// Poll represents the poll that supports non-blocking I/O on file descriptors with polling.
type Poll struct {
fd int
events []syscall.EpollEvent
pool *sync.Pool
timeout int
}
// Create creates a new poll.
func Create() (*Poll, error) {
fd, err := syscall.EpollCreate1(0)
if err != nil {
return nil, err
}
return &Poll{
fd: fd,
events: make([]syscall.EpollEvent, 1024),
pool: &sync.Pool{New: func() interface{} {
return syscall.EpollEvent{}
}},
timeout: 1000,
}, nil
}
// SetTimeout sets the wait timeout.
func (p *Poll) SetTimeout(d time.Duration) (err error) {
if d < 0 {
return ErrTimeout
}
p.timeout = int(d / time.Millisecond)
return nil
}
// Register registers a file descriptor.
func (p *Poll) Register(fd int) (err error) {
event := p.pool.Get().(syscall.EpollEvent)
event.Fd, event.Events = int32(fd), syscall.EPOLLIN
err = syscall.EpollCtl(p.fd, syscall.EPOLL_CTL_ADD, fd, &event)
p.pool.Put(event)
return
}
// Write adds a write event.
func (p *Poll) Write(fd int) (err error) {
event := p.pool.Get().(syscall.EpollEvent)
event.Fd, event.Events = int32(fd), syscall.EPOLLIN|syscall.EPOLLOUT
err = syscall.EpollCtl(p.fd, syscall.EPOLL_CTL_MOD, fd, &event)
p.pool.Put(event)
return
}
// Unregister unregisters a file descriptor.
func (p *Poll) Unregister(fd int) (err error) {
event := p.pool.Get().(syscall.EpollEvent)
event.Fd, event.Events = int32(fd), syscall.EPOLLIN|syscall.EPOLLOUT
err = syscall.EpollCtl(p.fd, syscall.EPOLL_CTL_DEL, fd, &event)
p.pool.Put(event)
return
}
// Wait waits events.
func (p *Poll) Wait(events []Event) (n int, err error) {
if cap(p.events) >= len(events) {
p.events = p.events[:len(events)]
} else {
p.events = make([]syscall.EpollEvent, len(events))
}
n, err = syscall.EpollWait(p.fd, p.events, p.timeout)
if err != nil {
if err != syscall.EINTR {
return 0, err
}
err = nil
}
for i := 0; i < n; i++ {
ev := p.events[i]
events[i].Fd = int(ev.Fd)
if ev.Events&syscall.EPOLLIN != 0 {
events[i].Mode = READ
} else if ev.Events&syscall.EPOLLOUT != 0 {
events[i].Mode = WRITE
event := p.pool.Get().(syscall.EpollEvent)
event.Fd, event.Events = ev.Fd, syscall.EPOLLIN
syscall.EpollCtl(p.fd, syscall.EPOLL_CTL_MOD, int(ev.Fd), &event)
p.pool.Put(event)
}
}
return
}
// Close closes the poll fd. The underlying file descriptor is closed by the
// destroy method when there are no remaining references.
func (p *Poll) Close() error {
return syscall.Close(p.fd)
}