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