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 func netpoll(delay int64) (gList, int32) {
97 if epfd == -1 {
98 return gList{}, 0
99 }
100 var waitms int32
101 if delay < 0 {
102 waitms = -1
103 } else if delay == 0 {
104 waitms = 0
105 } else if delay < 1e6 {
106 waitms = 1
107 } else if delay < 1e15 {
108 waitms = int32(delay / 1e6)
109 } else {
110
111
112 waitms = 1e9
113 }
114 var events [128]syscall.EpollEvent
115 retry:
116 n, errno := syscall.EpollWait(epfd, events[:], int32(len(events)), waitms)
117 if errno != 0 {
118 if errno != _EINTR {
119 println("runtime: epollwait on fd", epfd, "failed with", errno)
120 throw("runtime: netpoll failed")
121 }
122
123
124 if waitms > 0 {
125 return gList{}, 0
126 }
127 goto retry
128 }
129 var toRun gList
130 delta := int32(0)
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)) == &netpollEventFd {
138 if ev.Events != syscall.EPOLLIN {
139 println("runtime: netpoll: eventfd ready for", ev.Events)
140 throw("runtime: netpoll: eventfd ready for something unexpected")
141 }
142 if delay != 0 {
143
144
145
146
147
148 var one uint64
149 read(int32(netpollEventFd), noescape(unsafe.Pointer(&one)), int32(unsafe.Sizeof(one)))
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