github.com/ltltlt/go-source-code@v0.0.0-20190830023027-95be009773aa/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 "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 25 func netpollinit() { 26 epfd = epollcreate1(_EPOLL_CLOEXEC) 27 if epfd >= 0 { 28 return 29 } 30 epfd = epollcreate(1024) 31 if epfd >= 0 { 32 closeonexec(epfd) 33 return 34 } 35 println("runtime: epollcreate failed with", -epfd) 36 throw("runtime: netpollinit failed") 37 } 38 39 func netpolldescriptor() uintptr { 40 return uintptr(epfd) 41 } 42 43 // 注册一个fd, 让fd与这个pd关联 44 func netpollopen(fd uintptr, pd *pollDesc) int32 { 45 var ev epollevent 46 ev.events = _EPOLLIN | _EPOLLOUT | _EPOLLRDHUP | _EPOLLET 47 *(**pollDesc)(unsafe.Pointer(&ev.data)) = pd 48 return -epollctl(epfd, _EPOLL_CTL_ADD, int32(fd), &ev) 49 } 50 51 func netpollclose(fd uintptr) int32 { 52 var ev epollevent 53 return -epollctl(epfd, _EPOLL_CTL_DEL, int32(fd), &ev) 54 } 55 56 func netpollarm(pd *pollDesc, mode int) { 57 throw("runtime: unused") 58 } 59 60 // polls for ready network connections 61 // 轮询准备好的网络连接 62 // returns list of goroutines that become runnable 63 // 返回可运行的goroutine列表 64 func netpoll(block bool) *g { 65 if epfd == -1 { 66 return nil 67 } 68 waitms := int32(-1) 69 if !block { 70 waitms = 0 71 } 72 var events [128]epollevent 73 retry: 74 n := epollwait(epfd, &events[0], int32(len(events)), waitms) 75 if n < 0 { 76 if n != -_EINTR { 77 println("runtime: epollwait on fd", epfd, "failed with", -n) 78 throw("runtime: netpoll failed") 79 } 80 goto retry 81 } 82 var gp guintptr 83 // 把结果串成一个链表, 先遍历到的放后面 84 for i := int32(0); i < n; i++ { 85 ev := &events[i] 86 if ev.events == 0 { 87 continue 88 } 89 var mode int32 90 if ev.events&(_EPOLLIN|_EPOLLRDHUP|_EPOLLHUP|_EPOLLERR) != 0 { 91 mode += 'r' 92 } 93 if ev.events&(_EPOLLOUT|_EPOLLHUP|_EPOLLERR) != 0 { 94 mode += 'w' 95 } 96 if mode != 0 { 97 pd := *(**pollDesc)(unsafe.Pointer(&ev.data)) 98 99 netpollready(&gp, pd, mode) 100 } 101 } 102 if block && gp == 0 { 103 goto retry 104 } 105 return gp.ptr() 106 }