1// Copyright 2014 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
5package runtime
6
7import (
8	"runtime/internal/sys"
9	"unsafe"
10)
11
12type mOS struct{}
13
14//go:noescape
15//extern umtx_sleep
16func sys_umtx_sleep(addr *uint32, val, timeout int32) int32
17
18//go:noescape
19//extern umtx_wakeup
20func sys_umtx_wakeup(addr *uint32, val int32) int32
21
22//go:noescape
23//extern sysctl
24func sysctl(*uint32, uint32, *byte, *uintptr, *byte, uintptr) int32
25
26func getncpu() int32 {
27	mib := [2]uint32{_CTL_HW, _HW_NCPU}
28	out := uint32(0)
29	nout := uintptr(unsafe.Sizeof(out))
30	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
31	if ret >= 0 {
32		return int32(out)
33	}
34	return 1
35}
36
37func getPageSize() uintptr {
38	mib := [2]uint32{_CTL_HW, _HW_PAGESIZE}
39	out := uint32(0)
40	nout := uintptr(unsafe.Sizeof(out))
41	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
42	if ret >= 0 {
43		return uintptr(out)
44	}
45	return 0
46}
47
48//go:nosplit
49func futexsleep(addr *uint32, val uint32, ns int64) {
50	systemstack(func() {
51		futexsleep1(addr, val, ns)
52	})
53}
54
55func futexsleep1(addr *uint32, val uint32, ns int64) {
56	var timeout int32
57	if ns >= 0 {
58		// The timeout is specified in microseconds - ensure that we
59		// do not end up dividing to zero, which would put us to sleep
60		// indefinitely...
61		timeout = timediv(ns, 1000, nil)
62		if timeout == 0 {
63			timeout = 1
64		}
65	}
66
67	// sys_umtx_sleep will return EWOULDBLOCK (EAGAIN) when the timeout
68	// expires or EBUSY if the mutex value does not match.
69	ret := sys_umtx_sleep(addr, int32(val), timeout)
70	if ret >= 0 || ret == -_EINTR || ret == -_EAGAIN || ret == -_EBUSY {
71		return
72	}
73
74	print("umtx_sleep addr=", addr, " val=", val, " ret=", ret, "\n")
75	*(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005
76}
77
78//go:nosplit
79func futexwakeup(addr *uint32, cnt uint32) {
80	ret := sys_umtx_wakeup(addr, int32(cnt))
81	if ret >= 0 {
82		return
83	}
84
85	systemstack(func() {
86		print("umtx_wake_addr=", addr, " ret=", ret, "\n")
87		*(*int32)(unsafe.Pointer(uintptr(0x1006))) = 0x1006
88	})
89}
90
91func osinit() {
92	ncpu = getncpu()
93	if physPageSize == 0 {
94		physPageSize = getPageSize()
95	}
96}
97