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