github.com/mtsmfm/go/src@v0.0.0-20221020090648-44bdcb9f8fde/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 7 package runtime 8 9 import ( 10 "runtime/internal/atomic" 11 "runtime/internal/syscall" 12 "unsafe" 13 ) 14 15 var ( 16 epfd int32 = -1 // epoll descriptor 17 18 netpollBreakRd, netpollBreakWr uintptr // for netpollBreak 19 20 netpollWakeSig atomic.Uint32 // used to avoid duplicate calls of netpollBreak 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 *(**pollDesc)(unsafe.Pointer(&ev.Data)) = pd 56 return syscall.EpollCtl(epfd, syscall.EPOLL_CTL_ADD, int32(fd), &ev) 57 } 58 59 func netpollclose(fd uintptr) uintptr { 60 var ev syscall.EpollEvent 61 return syscall.EpollCtl(epfd, syscall.EPOLL_CTL_DEL, int32(fd), &ev) 62 } 63 64 func netpollarm(pd *pollDesc, mode int) { 65 throw("runtime: unused") 66 } 67 68 // netpollBreak interrupts an epollwait. 69 func netpollBreak() { 70 // Failing to cas indicates there is an in-flight wakeup, so we're done here. 71 if !netpollWakeSig.CompareAndSwap(0, 1) { 72 return 73 } 74 75 for { 76 var b byte 77 n := write(netpollBreakWr, unsafe.Pointer(&b), 1) 78 if n == 1 { 79 break 80 } 81 if n == -_EINTR { 82 continue 83 } 84 if n == -_EAGAIN { 85 return 86 } 87 println("runtime: netpollBreak write failed with", -n) 88 throw("runtime: netpollBreak write failed") 89 } 90 } 91 92 // netpoll checks for ready network connections. 93 // Returns list of goroutines that become runnable. 94 // delay < 0: blocks indefinitely 95 // delay == 0: does not block, just polls 96 // delay > 0: block for up to that many nanoseconds 97 func netpoll(delay int64) gList { 98 if epfd == -1 { 99 return gList{} 100 } 101 var waitms int32 102 if delay < 0 { 103 waitms = -1 104 } else if delay == 0 { 105 waitms = 0 106 } else if delay < 1e6 { 107 waitms = 1 108 } else if delay < 1e15 { 109 waitms = int32(delay / 1e6) 110 } else { 111 // An arbitrary cap on how long to wait for a timer. 112 // 1e9 ms == ~11.5 days. 113 waitms = 1e9 114 } 115 var events [128]syscall.EpollEvent 116 retry: 117 n, errno := syscall.EpollWait(epfd, events[:], int32(len(events)), waitms) 118 if errno != 0 { 119 if errno != _EINTR { 120 println("runtime: epollwait on fd", epfd, "failed with", errno) 121 throw("runtime: netpoll failed") 122 } 123 // If a timed sleep was interrupted, just return to 124 // recalculate how long we should sleep now. 125 if waitms > 0 { 126 return gList{} 127 } 128 goto retry 129 } 130 var toRun gList 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)) == &netpollBreakRd { 138 if ev.Events != syscall.EPOLLIN { 139 println("runtime: netpoll: break fd ready for", ev.Events) 140 throw("runtime: netpoll: break fd ready for something unexpected") 141 } 142 if delay != 0 { 143 // netpollBreak could be picked up by a 144 // nonblocking poll. Only read the byte 145 // if blocking. 146 var tmp [16]byte 147 read(int32(netpollBreakRd), noescape(unsafe.Pointer(&tmp[0])), int32(len(tmp))) 148 netpollWakeSig.Store(0) 149 } 150 continue 151 } 152 153 var mode int32 154 if ev.Events&(syscall.EPOLLIN|syscall.EPOLLRDHUP|syscall.EPOLLHUP|syscall.EPOLLERR) != 0 { 155 mode += 'r' 156 } 157 if ev.Events&(syscall.EPOLLOUT|syscall.EPOLLHUP|syscall.EPOLLERR) != 0 { 158 mode += 'w' 159 } 160 if mode != 0 { 161 pd := *(**pollDesc)(unsafe.Pointer(&ev.Data)) 162 pd.setEventErr(ev.Events == syscall.EPOLLERR) 163 netpollready(&toRun, pd, mode) 164 } 165 } 166 return toRun 167 }