github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/runtime/netpoll_epoll.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build linux 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 //go:noescape 18 func epollctl(epfd, op, fd int32, ev *epollevent) int32 19 20 //go:noescape 21 func epollwait(epfd int32, ev *epollevent, nev, timeout int32) int32 22 func closeonexec(fd int32) 23 24 var ( 25 epfd int32 = -1 // epoll descriptor 26 27 netpollBreakRd, netpollBreakWr uintptr // for netpollBreak 28 29 netpollWakeSig uint32 // used to avoid duplicate calls of netpollBreak 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 // netpollBreak interrupts an epollwait. 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 // netpoll checks for ready network connections. 102 // Returns list of goroutines that become runnable. 103 // delay < 0: blocks indefinitely 104 // delay == 0: does not block, just polls 105 // delay > 0: block for up to that many nanoseconds 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 // An arbitrary cap on how long to wait for a timer. 121 // 1e9 ms == ~11.5 days. 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 // If a timed sleep was interrupted, just return to 133 // recalculate how long we should sleep now. 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 // netpollBreak could be picked up by a 153 // nonblocking poll. Only read the byte 154 // if blocking. 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.everr = false 172 if ev.events == _EPOLLERR { 173 pd.everr = true 174 } 175 netpollready(&toRun, pd, mode) 176 } 177 } 178 return toRun 179 }