Source file
src/runtime/netpoll_epoll.go
Documentation: runtime
1
2
3
4
5
6
7
8 package runtime
9
10 import (
11 "runtime/internal/atomic"
12 "unsafe"
13 )
14
15 func epollcreate(size int32) int32
16 func epollcreate1(flags int32) int32
17
18
19 func epollctl(epfd, op, fd int32, ev *epollevent) int32
20
21
22 func epollwait(epfd int32, ev *epollevent, nev, timeout int32) int32
23 func closeonexec(fd int32)
24
25 var (
26 epfd int32 = -1
27
28 netpollBreakRd, netpollBreakWr uintptr
29
30 netpollWakeSig uint32
31 )
32
33 func netpollinit() {
34 epfd = epollcreate1(_EPOLL_CLOEXEC)
35 if epfd < 0 {
36 epfd = epollcreate(1024)
37 if epfd < 0 {
38 println("runtime: epollcreate failed with", -epfd)
39 throw("runtime: netpollinit failed")
40 }
41 closeonexec(epfd)
42 }
43 r, w, errno := nonblockingPipe()
44 if errno != 0 {
45 println("runtime: pipe failed with", -errno)
46 throw("runtime: pipe failed")
47 }
48 ev := epollevent{
49 events: _EPOLLIN,
50 }
51 *(**uintptr)(unsafe.Pointer(&ev.data)) = &netpollBreakRd
52 errno = epollctl(epfd, _EPOLL_CTL_ADD, r, &ev)
53 if errno != 0 {
54 println("runtime: epollctl failed with", -errno)
55 throw("runtime: epollctl failed")
56 }
57 netpollBreakRd = uintptr(r)
58 netpollBreakWr = uintptr(w)
59 }
60
61 func netpollIsPollDescriptor(fd uintptr) bool {
62 return fd == uintptr(epfd) || fd == netpollBreakRd || fd == netpollBreakWr
63 }
64
65 func netpollopen(fd uintptr, pd *pollDesc) int32 {
66 var ev epollevent
67 ev.events = _EPOLLIN | _EPOLLOUT | _EPOLLRDHUP | _EPOLLET
68 *(**pollDesc)(unsafe.Pointer(&ev.data)) = pd
69 return -epollctl(epfd, _EPOLL_CTL_ADD, int32(fd), &ev)
70 }
71
72 func netpollclose(fd uintptr) int32 {
73 var ev epollevent
74 return -epollctl(epfd, _EPOLL_CTL_DEL, int32(fd), &ev)
75 }
76
77 func netpollarm(pd *pollDesc, mode int) {
78 throw("runtime: unused")
79 }
80
81
82 func netpollBreak() {
83 if atomic.Cas(&netpollWakeSig, 0, 1) {
84 for {
85 var b byte
86 n := write(netpollBreakWr, unsafe.Pointer(&b), 1)
87 if n == 1 {
88 break
89 }
90 if n == -_EINTR {
91 continue
92 }
93 if n == -_EAGAIN {
94 return
95 }
96 println("runtime: netpollBreak write failed with", -n)
97 throw("runtime: netpollBreak write failed")
98 }
99 }
100 }
101
102
103
104
105
106
107 func netpoll(delay int64) gList {
108 if epfd == -1 {
109 return gList{}
110 }
111 var waitms int32
112 if delay < 0 {
113 waitms = -1
114 } else if delay == 0 {
115 waitms = 0
116 } else if delay < 1e6 {
117 waitms = 1
118 } else if delay < 1e15 {
119 waitms = int32(delay / 1e6)
120 } else {
121
122
123 waitms = 1e9
124 }
125 var events [128]epollevent
126 retry:
127 n := epollwait(epfd, &events[0], int32(len(events)), waitms)
128 if n < 0 {
129 if n != -_EINTR {
130 println("runtime: epollwait on fd", epfd, "failed with", -n)
131 throw("runtime: netpoll failed")
132 }
133
134
135 if waitms > 0 {
136 return gList{}
137 }
138 goto retry
139 }
140 var toRun gList
141 for i := int32(0); i < n; i++ {
142 ev := &events[i]
143 if ev.events == 0 {
144 continue
145 }
146
147 if *(**uintptr)(unsafe.Pointer(&ev.data)) == &netpollBreakRd {
148 if ev.events != _EPOLLIN {
149 println("runtime: netpoll: break fd ready for", ev.events)
150 throw("runtime: netpoll: break fd ready for something unexpected")
151 }
152 if delay != 0 {
153
154
155
156 var tmp [16]byte
157 read(int32(netpollBreakRd), noescape(unsafe.Pointer(&tmp[0])), int32(len(tmp)))
158 atomic.Store(&netpollWakeSig, 0)
159 }
160 continue
161 }
162
163 var mode int32
164 if ev.events&(_EPOLLIN|_EPOLLRDHUP|_EPOLLHUP|_EPOLLERR) != 0 {
165 mode += 'r'
166 }
167 if ev.events&(_EPOLLOUT|_EPOLLHUP|_EPOLLERR) != 0 {
168 mode += 'w'
169 }
170 if mode != 0 {
171 pd := *(**pollDesc)(unsafe.Pointer(&ev.data))
172 pd.everr = false
173 if ev.events == _EPOLLERR {
174 pd.everr = true
175 }
176 netpollready(&toRun, pd, mode)
177 }
178 }
179 return toRun
180 }
181
View as plain text