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
7package runtime
8
9import "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
18var netpollBreakRd, netpollBreakWr uintptr // for netpollBreak
19
20func 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
40func 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
55func 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
66func drainWakeupEvent(_ int32) {
67	var buf [16]byte
68	read(int32(netpollBreakRd), noescape(unsafe.Pointer(&buf[0])), int32(len(buf)))
69}
70
71func netpollIsPollDescriptor(fd uintptr) bool {
72	return fd == uintptr(kq) || fd == netpollBreakRd || fd == netpollBreakWr
73}
74