summaryrefslogtreecommitdiffstats
path: root/contrib/go/_std_1.24/src/runtime/netpoll_kqueue_pipe.go
blob: cf1e2afa8371d4d6d4d4e0b41edbee0087b4d6f2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
// Copyright 2024 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.

//go:build netbsd || openbsd

package runtime

import "unsafe"

// TODO(panjf2000): NetBSD didn't implement EVFILT_USER for user-established events
// until NetBSD 10.0, check out https://www.netbsd.org/releases/formal-10/NetBSD-10.0.html
// Therefore we use the pipe to wake up the kevent on NetBSD at this point. Get back here
// and switch to EVFILT_USER when we bump up the minimal requirement of NetBSD to 10.0.
// Alternatively, maybe we can use EVFILT_USER on the NetBSD by checking the kernel version
// via uname(3) and fall back to the pipe if the kernel version is older than 10.0.

var netpollBreakRd, netpollBreakWr uintptr // for netpollBreak

func addWakeupEvent(kq int32) {
	r, w, errno := nonblockingPipe()
	if errno != 0 {
		println("runtime: pipe failed with", -errno)
		throw("runtime: pipe failed")
	}
	ev := keventt{
		filter: _EVFILT_READ,
		flags:  _EV_ADD,
	}
	*(*uintptr)(unsafe.Pointer(&ev.ident)) = uintptr(r)
	n := kevent(kq, &ev, 1, nil, 0, nil)
	if n < 0 {
		println("runtime: kevent failed with", -n)
		throw("runtime: kevent failed")
	}
	netpollBreakRd = uintptr(r)
	netpollBreakWr = uintptr(w)
}

func wakeNetpoll(_ int32) {
	for {
		var b byte
		n := write(netpollBreakWr, unsafe.Pointer(&b), 1)
		if n == 1 || n == -_EAGAIN {
			break
		}
		if n == -_EINTR {
			continue
		}
		println("runtime: netpollBreak write failed with", -n)
		throw("runtime: netpollBreak write failed")
	}
}

func isWakeup(ev *keventt) bool {
	if uintptr(ev.ident) == netpollBreakRd {
		if ev.filter == _EVFILT_READ {
			return true
		}
		println("runtime: netpoll: break fd ready for", ev.filter)
		throw("runtime: netpoll: break fd ready for something unexpected")
	}
	return false
}

func processWakeupEvent(_ int32, isBlocking bool) {
	// Only drain if blocking.
	if !isBlocking {
		return
	}
	var buf [16]byte
	read(int32(netpollBreakRd), noescape(unsafe.Pointer(&buf[0])), int32(len(buf)))
}

func netpollIsPollDescriptor(fd uintptr) bool {
	return fd == uintptr(kq) || fd == netpollBreakRd || fd == netpollBreakWr
}