Source file src/runtime/netpoll_kqueue_pipe.go

     1  // Copyright 2024 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  //go:build netbsd || openbsd
     6  
     7  package runtime
     8  
     9  import "unsafe"
    10  
    11  // TODO(panjf2000): NetBSD didn't implement EVFILT_USER for user-established events
    12  // until NetBSD 10.0, check out https://www.netbsd.org/releases/formal-10/NetBSD-10.0.html
    13  // Therefore we use the pipe to wake up the kevent on NetBSD at this point. Get back here
    14  // and switch to EVFILT_USER when we bump up the minimal requirement of NetBSD to 10.0.
    15  // Alternatively, maybe we can use EVFILT_USER on the NetBSD by checking the kernel version
    16  // via uname(3) and fall back to the pipe if the kernel version is older than 10.0.
    17  
    18  var netpollBreakRd, netpollBreakWr uintptr // for netpollBreak
    19  
    20  func addWakeupEvent(kq int32) {
    21  	r, w, errno := nonblockingPipe()
    22  	if errno != 0 {
    23  		println("runtime: pipe failed with", -errno)
    24  		throw("runtime: pipe failed")
    25  	}
    26  	ev := keventt{
    27  		filter: _EVFILT_READ,
    28  		flags:  _EV_ADD,
    29  	}
    30  	*(*uintptr)(unsafe.Pointer(&ev.ident)) = uintptr(r)
    31  	n := kevent(kq, &ev, 1, nil, 0, nil)
    32  	if n < 0 {
    33  		println("runtime: kevent failed with", -n)
    34  		throw("runtime: kevent failed")
    35  	}
    36  	netpollBreakRd = uintptr(r)
    37  	netpollBreakWr = uintptr(w)
    38  }
    39  
    40  func wakeNetpoll(_ int32) {
    41  	for {
    42  		var b byte
    43  		n := write(netpollBreakWr, unsafe.Pointer(&b), 1)
    44  		if n == 1 || n == -_EAGAIN {
    45  			break
    46  		}
    47  		if n == -_EINTR {
    48  			continue
    49  		}
    50  		println("runtime: netpollBreak write failed with", -n)
    51  		throw("runtime: netpollBreak write failed")
    52  	}
    53  }
    54  
    55  func isWakeup(ev *keventt) bool {
    56  	if uintptr(ev.ident) == netpollBreakRd {
    57  		if ev.filter == _EVFILT_READ {
    58  			return true
    59  		}
    60  		println("runtime: netpoll: break fd ready for", ev.filter)
    61  		throw("runtime: netpoll: break fd ready for something unexpected")
    62  	}
    63  	return false
    64  }
    65  
    66  func drainWakeupEvent(_ int32) {
    67  	var buf [16]byte
    68  	read(int32(netpollBreakRd), noescape(unsafe.Pointer(&buf[0])), int32(len(buf)))
    69  }
    70  
    71  func netpollIsPollDescriptor(fd uintptr) bool {
    72  	return fd == uintptr(kq) || fd == netpollBreakRd || fd == netpollBreakWr
    73  }
    74  

View as plain text