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