...
Source file
src/runtime/netpoll_epoll.go
Documentation: runtime
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 tp := taggedPointerPack(unsafe.Pointer(pd), pd.fdseq.Load())
56 *(*taggedPointer)(unsafe.Pointer(&ev.Data)) = tp
57 return syscall.EpollCtl(epfd, syscall.EPOLL_CTL_ADD, int32(fd), &ev)
58 }
59
60 func netpollclose(fd uintptr) uintptr {
61 var ev syscall.EpollEvent
62 return syscall.EpollCtl(epfd, syscall.EPOLL_CTL_DEL, int32(fd), &ev)
63 }
64
65 func netpollarm(pd *pollDesc, mode int) {
66 throw("runtime: unused")
67 }
68
69
70 func netpollBreak() {
71
72 if !netpollWakeSig.CompareAndSwap(0, 1) {
73 return
74 }
75
76 for {
77 var b byte
78 n := write(netpollBreakWr, unsafe.Pointer(&b), 1)
79 if n == 1 {
80 break
81 }
82 if n == -_EINTR {
83 continue
84 }
85 if n == -_EAGAIN {
86 return
87 }
88 println("runtime: netpollBreak write failed with", -n)
89 throw("runtime: netpollBreak write failed")
90 }
91 }
92
93
94
95
96
97
98 func netpoll(delay int64) (gList, int32) {
99 if epfd == -1 {
100 return gList{}, 0
101 }
102 var waitms int32
103 if delay < 0 {
104 waitms = -1
105 } else if delay == 0 {
106 waitms = 0
107 } else if delay < 1e6 {
108 waitms = 1
109 } else if delay < 1e15 {
110 waitms = int32(delay / 1e6)
111 } else {
112
113
114 waitms = 1e9
115 }
116 var events [128]syscall.EpollEvent
117 retry:
118 n, errno := syscall.EpollWait(epfd, events[:], int32(len(events)), waitms)
119 if errno != 0 {
120 if errno != _EINTR {
121 println("runtime: epollwait on fd", epfd, "failed with", errno)
122 throw("runtime: netpoll failed")
123 }
124
125
126 if waitms > 0 {
127 return gList{}, 0
128 }
129 goto retry
130 }
131 var toRun gList
132 delta := int32(0)
133 for i := int32(0); i < n; i++ {
134 ev := events[i]
135 if ev.Events == 0 {
136 continue
137 }
138
139 if *(**uintptr)(unsafe.Pointer(&ev.Data)) == &netpollBreakRd {
140 if ev.Events != syscall.EPOLLIN {
141 println("runtime: netpoll: break fd ready for", ev.Events)
142 throw("runtime: netpoll: break fd ready for something unexpected")
143 }
144 if delay != 0 {
145
146
147
148 var tmp [16]byte
149 read(int32(netpollBreakRd), noescape(unsafe.Pointer(&tmp[0])), int32(len(tmp)))
150 netpollWakeSig.Store(0)
151 }
152 continue
153 }
154
155 var mode int32
156 if ev.Events&(syscall.EPOLLIN|syscall.EPOLLRDHUP|syscall.EPOLLHUP|syscall.EPOLLERR) != 0 {
157 mode += 'r'
158 }
159 if ev.Events&(syscall.EPOLLOUT|syscall.EPOLLHUP|syscall.EPOLLERR) != 0 {
160 mode += 'w'
161 }
162 if mode != 0 {
163 tp := *(*taggedPointer)(unsafe.Pointer(&ev.Data))
164 pd := (*pollDesc)(tp.pointer())
165 tag := tp.tag()
166 if pd.fdseq.Load() == tag {
167 pd.setEventErr(ev.Events == syscall.EPOLLERR, tag)
168 delta += netpollready(&toRun, pd, mode)
169 }
170 }
171 }
172 return toRun, delta
173 }
174
View as plain text