// Copyright 2013 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.// +build darwin dragonfly freebsd netbsd openbsdpackage runtime// Integrated network poller (kqueue-based implementation).import ()var (kqint32 = -1netpollBreakRd, netpollBreakWruintptr// for netpollBreaknetpollWakeSiguint32// used to avoid duplicate calls of netpollBreak)func () {kq = kqueue()ifkq < 0 {println("runtime: kqueue failed with", -kq)throw("runtime: netpollinit failed") }closeonexec(kq) , , := nonblockingPipe()if != 0 {println("runtime: pipe failed with", -)throw("runtime: pipe failed") } := keventt{filter: _EVFILT_READ,flags: _EV_ADD, } *(*uintptr)(unsafe.Pointer(&.ident)) = uintptr() := kevent(kq, &, 1, nil, 0, nil)if < 0 {println("runtime: kevent failed with", -)throw("runtime: kevent failed") }netpollBreakRd = uintptr()netpollBreakWr = uintptr()}func ( uintptr) bool {return == uintptr(kq) || == netpollBreakRd || == netpollBreakWr}func ( uintptr, *pollDesc) int32 {// Arm both EVFILT_READ and EVFILT_WRITE in edge-triggered mode (EV_CLEAR) // for the whole fd lifetime. The notifications are automatically unregistered // when fd is closed.var [2]keventt *(*uintptr)(unsafe.Pointer(&[0].ident)) = [0].filter = _EVFILT_READ [0].flags = _EV_ADD | _EV_CLEAR [0].fflags = 0 [0].data = 0 [0].udata = (*byte)(unsafe.Pointer()) [1] = [0] [1].filter = _EVFILT_WRITE := kevent(kq, &[0], 2, nil, 0, nil)if < 0 {return - }return0}func ( uintptr) int32 {// Don't need to unregister because calling close() // on fd will remove any kevents that reference the descriptor.return0}func ( *pollDesc, int) {throw("runtime: unused")}// netpollBreak interrupts a kevent.func () {ifatomic.Cas(&netpollWakeSig, 0, 1) {for {varbyte := write(netpollBreakWr, unsafe.Pointer(&), 1)if == 1 || == -_EAGAIN {break }if == -_EINTR {continue }println("runtime: netpollBreak write failed with", -)throw("runtime: netpollBreak write failed") } }}// netpoll checks for ready network connections.// Returns list of goroutines that become runnable.// delay < 0: blocks indefinitely// delay == 0: does not block, just polls// delay > 0: block for up to that many nanosecondsfunc ( int64) gList {ifkq == -1 {returngList{} }var *timespecvartimespecif < 0 { = nil } elseif == 0 { = & } else { .setNsec()if .tv_sec > 1e6 {// Darwin returns EINVAL if the sleep time is too long. .tv_sec = 1e6 } = & }var [64]keventt: := kevent(kq, nil, 0, &[0], int32(len()), )if < 0 {if != -_EINTR {println("runtime: kevent on fd", kq, "failed with", -)throw("runtime: netpoll failed") }// If a timed sleep was interrupted, just return to // recalculate how long we should sleep now.if > 0 {returngList{} }goto }vargListfor := 0; < int(); ++ { := &[]ifuintptr(.ident) == netpollBreakRd {if .filter != _EVFILT_READ {println("runtime: netpoll: break fd ready for", .filter)throw("runtime: netpoll: break fd ready for something unexpected") }if != 0 {// netpollBreak could be picked up by a // nonblocking poll. Only read the byte // if blocking.var [16]byteread(int32(netpollBreakRd), noescape(unsafe.Pointer(&[0])), int32(len()))atomic.Store(&netpollWakeSig, 0) }continue }varint32switch .filter {case_EVFILT_READ: += 'r'// On some systems when the read end of a pipe // is closed the write end will not get a // _EVFILT_WRITE event, but will get a // _EVFILT_READ event with EV_EOF set. // Note that setting 'w' here just means that we // will wake up a goroutine waiting to write; // that goroutine will try the write again, // and the appropriate thing will happen based // on what that write returns (success, EPIPE, EAGAIN).if .flags&_EV_EOF != 0 { += 'w' }case_EVFILT_WRITE: += 'w' }if != 0 { := (*pollDesc)(unsafe.Pointer(.udata)) .everr = falseif .flags == _EV_ERROR { .everr = true }netpollready(&, , ) } }return}
The pages are generated with Goldsv0.2.8-preview. (GOOS=darwin GOARCH=arm64)