Dmitriy Vyukov | 91a670d | 2014-09-04 10:04:04 +0400 | [diff] [blame] | 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 | netpolllasterr int32 |
| 22 | ) |
| 23 | |
| 24 | func netpollinit() { |
| 25 | kq = kqueue() |
| 26 | if kq < 0 { |
| 27 | println("netpollinit: kqueue failed with", -kq) |
Keith Randall | b2a950b | 2014-12-27 20:58:00 -0800 | [diff] [blame] | 28 | throw("netpollinit: kqueue failed") |
Dmitriy Vyukov | 91a670d | 2014-09-04 10:04:04 +0400 | [diff] [blame] | 29 | } |
| 30 | closeonexec(kq) |
| 31 | } |
| 32 | |
| 33 | func netpollopen(fd uintptr, pd *pollDesc) int32 { |
| 34 | // Arm both EVFILT_READ and EVFILT_WRITE in edge-triggered mode (EV_CLEAR) |
| 35 | // for the whole fd lifetime. The notifications are automatically unregistered |
| 36 | // when fd is closed. |
| 37 | var ev [2]keventt |
| 38 | *(*uintptr)(unsafe.Pointer(&ev[0].ident)) = fd |
| 39 | ev[0].filter = _EVFILT_READ |
| 40 | ev[0].flags = _EV_ADD | _EV_CLEAR |
| 41 | ev[0].fflags = 0 |
| 42 | ev[0].data = 0 |
| 43 | ev[0].udata = (*byte)(unsafe.Pointer(pd)) |
| 44 | ev[1] = ev[0] |
| 45 | ev[1].filter = _EVFILT_WRITE |
| 46 | n := kevent(kq, &ev[0], 2, nil, 0, nil) |
| 47 | if n < 0 { |
| 48 | return -n |
| 49 | } |
| 50 | return 0 |
| 51 | } |
| 52 | |
| 53 | func netpollclose(fd uintptr) int32 { |
| 54 | // Don't need to unregister because calling close() |
| 55 | // on fd will remove any kevents that reference the descriptor. |
| 56 | return 0 |
| 57 | } |
| 58 | |
| 59 | func netpollarm(pd *pollDesc, mode int) { |
Keith Randall | b2a950b | 2014-12-27 20:58:00 -0800 | [diff] [blame] | 60 | throw("unused") |
Dmitriy Vyukov | 91a670d | 2014-09-04 10:04:04 +0400 | [diff] [blame] | 61 | } |
| 62 | |
| 63 | // Polls for ready network connections. |
| 64 | // Returns list of goroutines that become runnable. |
Russ Cox | 181e26b | 2015-04-17 00:21:30 -0400 | [diff] [blame] | 65 | func netpoll(block bool) *g { |
Dmitriy Vyukov | 91a670d | 2014-09-04 10:04:04 +0400 | [diff] [blame] | 66 | if kq == -1 { |
Russ Cox | 181e26b | 2015-04-17 00:21:30 -0400 | [diff] [blame] | 67 | return nil |
Dmitriy Vyukov | 91a670d | 2014-09-04 10:04:04 +0400 | [diff] [blame] | 68 | } |
| 69 | var tp *timespec |
| 70 | var ts timespec |
| 71 | if !block { |
| 72 | tp = &ts |
| 73 | } |
| 74 | var events [64]keventt |
| 75 | retry: |
| 76 | n := kevent(kq, nil, 0, &events[0], int32(len(events)), tp) |
| 77 | if n < 0 { |
| 78 | if n != -_EINTR && n != netpolllasterr { |
| 79 | netpolllasterr = n |
| 80 | println("runtime: kevent on fd", kq, "failed with", -n) |
| 81 | } |
| 82 | goto retry |
| 83 | } |
Russ Cox | 181e26b | 2015-04-17 00:21:30 -0400 | [diff] [blame] | 84 | var gp guintptr |
Dmitriy Vyukov | 91a670d | 2014-09-04 10:04:04 +0400 | [diff] [blame] | 85 | for i := 0; i < int(n); i++ { |
| 86 | ev := &events[i] |
| 87 | var mode int32 |
| 88 | if ev.filter == _EVFILT_READ { |
| 89 | mode += 'r' |
| 90 | } |
| 91 | if ev.filter == _EVFILT_WRITE { |
| 92 | mode += 'w' |
| 93 | } |
| 94 | if mode != 0 { |
Russ Cox | 181e26b | 2015-04-17 00:21:30 -0400 | [diff] [blame] | 95 | netpollready(&gp, (*pollDesc)(unsafe.Pointer(ev.udata)), mode) |
Dmitriy Vyukov | 91a670d | 2014-09-04 10:04:04 +0400 | [diff] [blame] | 96 | } |
| 97 | } |
Russ Cox | 181e26b | 2015-04-17 00:21:30 -0400 | [diff] [blame] | 98 | if block && gp == 0 { |
Dmitriy Vyukov | 91a670d | 2014-09-04 10:04:04 +0400 | [diff] [blame] | 99 | goto retry |
| 100 | } |
Russ Cox | 181e26b | 2015-04-17 00:21:30 -0400 | [diff] [blame] | 101 | return gp.ptr() |
Dmitriy Vyukov | 91a670d | 2014-09-04 10:04:04 +0400 | [diff] [blame] | 102 | } |