github.com/likebike/go--@v0.0.0-20190911215757-0bd925d16e96/go/src/runtime/netpoll_kqueue.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 darwin dragonfly freebsd netbsd openbsd 6 7 package runtime 8 9 // Integrated network poller (kqueue-based implementation). 10 11 import "unsafe" 12 13 func kqueue() int32 14 15 //go:noescape 16 func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32 17 func closeonexec(fd int32) 18 19 var ( 20 kq int32 = -1 21 ) 22 23 func netpollinit() { 24 kq = kqueue() 25 if kq < 0 { 26 println("runtime: kqueue failed with", -kq) 27 throw("runtime: netpollinit failed") 28 } 29 closeonexec(kq) 30 } 31 32 func netpolldescriptor() uintptr { 33 return uintptr(kq) 34 } 35 36 func netpollopen(fd uintptr, pd *pollDesc) int32 { 37 // Arm both EVFILT_READ and EVFILT_WRITE in edge-triggered mode (EV_CLEAR) 38 // for the whole fd lifetime. The notifications are automatically unregistered 39 // when fd is closed. 40 var ev [2]keventt 41 *(*uintptr)(unsafe.Pointer(&ev[0].ident)) = fd 42 ev[0].filter = _EVFILT_READ 43 ev[0].flags = _EV_ADD | _EV_CLEAR 44 ev[0].fflags = 0 45 ev[0].data = 0 46 ev[0].udata = (*byte)(unsafe.Pointer(pd)) 47 ev[1] = ev[0] 48 ev[1].filter = _EVFILT_WRITE 49 n := kevent(kq, &ev[0], 2, nil, 0, nil) 50 if n < 0 { 51 return -n 52 } 53 return 0 54 } 55 56 func netpollclose(fd uintptr) int32 { 57 // Don't need to unregister because calling close() 58 // on fd will remove any kevents that reference the descriptor. 59 return 0 60 } 61 62 func netpollarm(pd *pollDesc, mode int) { 63 throw("runtime: unused") 64 } 65 66 // Polls for ready network connections. 67 // Returns list of goroutines that become runnable. 68 func netpoll(block bool) *g { 69 if kq == -1 { 70 return nil 71 } 72 var tp *timespec 73 var ts timespec 74 if !block { 75 tp = &ts 76 } 77 var events [64]keventt 78 retry: 79 n := kevent(kq, nil, 0, &events[0], int32(len(events)), tp) 80 if n < 0 { 81 if n != -_EINTR { 82 println("runtime: kevent on fd", kq, "failed with", -n) 83 throw("runtime: netpoll failed") 84 } 85 goto retry 86 } 87 var gp guintptr 88 for i := 0; i < int(n); i++ { 89 ev := &events[i] 90 var mode int32 91 switch ev.filter { 92 case _EVFILT_READ: 93 mode += 'r' 94 95 // On some systems when the read end of a pipe 96 // is closed the write end will not get a 97 // _EVFILT_WRITE event, but will get a 98 // _EVFILT_READ event with EV_EOF set. 99 // Note that setting 'w' here just means that we 100 // will wake up a goroutine waiting to write; 101 // that goroutine will try the write again, 102 // and the appropriate thing will happen based 103 // on what that write returns (success, EPIPE, EAGAIN). 104 if ev.flags&_EV_EOF != 0 { 105 mode += 'w' 106 } 107 case _EVFILT_WRITE: 108 mode += 'w' 109 } 110 if mode != 0 { 111 netpollready(&gp, (*pollDesc)(unsafe.Pointer(ev.udata)), mode) 112 } 113 } 114 if block && gp == 0 { 115 goto retry 116 } 117 return gp.ptr() 118 }