github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/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("netpollinit: kqueue failed with", -kq) 27 throw("netpollinit: kqueue 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("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("kevent 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 if ev.filter == _EVFILT_READ { 92 mode += 'r' 93 } 94 if ev.filter == _EVFILT_WRITE { 95 mode += 'w' 96 } 97 if mode != 0 { 98 netpollready(&gp, (*pollDesc)(unsafe.Pointer(ev.udata)), mode) 99 } 100 } 101 if block && gp == 0 { 102 goto retry 103 } 104 return gp.ptr() 105 }