github.com/gidoBOSSftw5731/go/src@v0.0.0-20210226122457-d24b0edbf019/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 //go:build linux 6 // +build linux 7 8 package runtime 9 10 import ( 11 "runtime/internal/atomic" 12 "unsafe" 13 ) 14 15 func epollcreate(size int32) int32 16 func epollcreate1(flags int32) int32 17 18 //go:noescape 19 func epollctl(epfd, op, fd int32, ev *epollevent) int32 20 21 //go:noescape 22 func epollwait(epfd int32, ev *epollevent, nev, timeout int32) int32 23 func closeonexec(fd int32) 24 25 var ( 26 epfd int32 = -1 // epoll descriptor 27 28 netpollBreakRd, netpollBreakWr uintptr // for netpollBreak 29 30 netpollWakeSig uint32 // used to avoid duplicate calls of netpollBreak 31 ) 32 33 func netpollinit() { 34 epfd = epollcreate1(_EPOLL_CLOEXEC) 35 if epfd < 0 { 36 epfd = epollcreate(1024) 37 if epfd < 0 { 38 println("runtime: epollcreate failed with", -epfd) 39 throw("runtime: netpollinit failed") 40 } 41 closeonexec(epfd) 42 } 43 r, w, errno := nonblockingPipe() 44 if errno != 0 { 45 println("runtime: pipe failed with", -errno) 46 throw("runtime: pipe failed") 47 } 48 ev := epollevent{ 49 events: _EPOLLIN, 50 } 51 *(**uintptr)(unsafe.Pointer(&ev.data)) = &netpollBreakRd 52 errno = epollctl(epfd, _EPOLL_CTL_ADD, r, &ev) 53 if errno != 0 { 54 println("runtime: epollctl failed with", -errno) 55 throw("runtime: epollctl failed") 56 } 57 netpollBreakRd = uintptr(r) 58 netpollBreakWr = uintptr(w) 59 } 60 61 func netpollIsPollDescriptor(fd uintptr) bool { 62 return fd == uintptr(epfd) || fd == netpollBreakRd || fd == netpollBreakWr 63 } 64 65 func netpollopen(fd uintptr, pd *pollDesc) int32 { 66 var ev epollevent 67 ev.events = _EPOLLIN | _EPOLLOUT | _EPOLLRDHUP | _EPOLLET 68 *(**pollDesc)(unsafe.Pointer(&ev.data)) = pd 69 return -epollctl(epfd, _EPOLL_CTL_ADD, int32(fd), &ev) 70 } 71 72 func netpollclose(fd uintptr) int32 { 73 var ev epollevent 74 return -epollctl(epfd, _EPOLL_CTL_DEL, int32(fd), &ev) 75 } 76 77 func netpollarm(pd *pollDesc, mode int) { 78 throw("runtime: unused") 79 } 80 81 // netpollBreak interrupts an epollwait. 82 func netpollBreak() { 83 if atomic.Cas(&netpollWakeSig, 0, 1) { 84 for { 85 var b byte 86 n := write(netpollBreakWr, unsafe.Pointer(&b), 1) 87 if n == 1 { 88 break 89 } 90 if n == -_EINTR { 91 continue 92 } 93 if n == -_EAGAIN { 94 return 95 } 96 println("runtime: netpollBreak write failed with", -n) 97 throw("runtime: netpollBreak write failed") 98 } 99 } 100 } 101 102 // netpoll checks for ready network connections. 103 // Returns list of goroutines that become runnable. 104 // delay < 0: blocks indefinitely 105 // delay == 0: does not block, just polls 106 // delay > 0: block for up to that many nanoseconds 107 func netpoll(delay int64) gList { 108 if epfd == -1 { 109 return gList{} 110 } 111 var waitms int32 112 if delay < 0 { 113 waitms = -1 114 } else if delay == 0 { 115 waitms = 0 116 } else if delay < 1e6 { 117 waitms = 1 118 } else if delay < 1e15 { 119 waitms = int32(delay / 1e6) 120 } else { 121 // An arbitrary cap on how long to wait for a timer. 122 // 1e9 ms == ~11.5 days. 123 waitms = 1e9 124 } 125 var events [128]epollevent 126 retry: 127 n := epollwait(epfd, &events[0], int32(len(events)), waitms) 128 if n < 0 { 129 if n != -_EINTR { 130 println("runtime: epollwait on fd", epfd, "failed with", -n) 131 throw("runtime: netpoll failed") 132 } 133 // If a timed sleep was interrupted, just return to 134 // recalculate how long we should sleep now. 135 if waitms > 0 { 136 return gList{} 137 } 138 goto retry 139 } 140 var toRun gList 141 for i := int32(0); i < n; i++ { 142 ev := &events[i] 143 if ev.events == 0 { 144 continue 145 } 146 147 if *(**uintptr)(unsafe.Pointer(&ev.data)) == &netpollBreakRd { 148 if ev.events != _EPOLLIN { 149 println("runtime: netpoll: break fd ready for", ev.events) 150 throw("runtime: netpoll: break fd ready for something unexpected") 151 } 152 if delay != 0 { 153 // netpollBreak could be picked up by a 154 // nonblocking poll. Only read the byte 155 // if blocking. 156 var tmp [16]byte 157 read(int32(netpollBreakRd), noescape(unsafe.Pointer(&tmp[0])), int32(len(tmp))) 158 atomic.Store(&netpollWakeSig, 0) 159 } 160 continue 161 } 162 163 var mode int32 164 if ev.events&(_EPOLLIN|_EPOLLRDHUP|_EPOLLHUP|_EPOLLERR) != 0 { 165 mode += 'r' 166 } 167 if ev.events&(_EPOLLOUT|_EPOLLHUP|_EPOLLERR) != 0 { 168 mode += 'w' 169 } 170 if mode != 0 { 171 pd := *(**pollDesc)(unsafe.Pointer(&ev.data)) 172 pd.everr = false 173 if ev.events == _EPOLLERR { 174 pd.everr = true 175 } 176 netpollready(&toRun, pd, mode) 177 } 178 } 179 return toRun 180 }