github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/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 "internal/runtime/syscall" 11 "runtime/internal/atomic" 12 "unsafe" 13 ) 14 15 var ( 16 epfd int32 = -1 // epoll descriptor 17 netpollEventFd uintptr // eventfd for netpollBreak 18 netpollWakeSig atomic.Uint32 // used to avoid duplicate calls of netpollBreak 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 // netpollBreak interrupts an epollwait. 67 func netpollBreak() { 68 // Failing to cas indicates there is an in-flight wakeup, so we're done here. 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 // netpoll checks for ready network connections. 92 // Returns list of goroutines that become runnable. 93 // delay < 0: blocks indefinitely 94 // delay == 0: does not block, just polls 95 // delay > 0: block for up to that many nanoseconds 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 // An arbitrary cap on how long to wait for a timer. 111 // 1e9 ms == ~11.5 days. 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 // If a timed sleep was interrupted, just return to 123 // recalculate how long we should sleep now. 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 // netpollBreak could be picked up by a 144 // nonblocking poll. Only read the 8-byte 145 // integer if blocking. 146 // Since EFD_SEMAPHORE was not specified, 147 // the eventfd counter will be reset to 0. 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 }