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