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