1// Copyright 2019 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// This file is derived from os_aix.go.
6
7package runtime
8
9import "unsafe"
10
11//extern sysconf
12func sysconf(int32) _C_long
13
14//extern getpagesize
15func getPageSize() int32
16
17type mOS struct {
18	waitsema uintptr // semaphore for parking on locks
19}
20
21//extern malloc
22func libc_malloc(uintptr) unsafe.Pointer
23
24//go:noescape
25//extern sem_init
26func sem_init(sem *_sem_t, pshared int32, value uint32) int32
27
28//go:noescape
29//extern sem_wait
30func sem_wait(sem *_sem_t) int32
31
32//go:noescape
33//extern sem_post
34func sem_post(sem *_sem_t) int32
35
36//go:noescape
37//extern sem_timedwait
38func sem_timedwait(sem *_sem_t, timeout *timespec) int32
39
40//go:noescape
41//extern clock_gettime
42func clock_gettime(clock_id int32, timeout *timespec) int32
43
44//go:nosplit
45func semacreate(mp *m) {
46	if mp.waitsema != 0 {
47		return
48	}
49
50	var sem *_sem_t
51
52	// Call libc's malloc rather than malloc. This will
53	// allocate space on the C heap. We can't call malloc
54	// here because it could cause a deadlock.
55	sem = (*_sem_t)(libc_malloc(unsafe.Sizeof(*sem)))
56	if sem_init(sem, 0, 0) != 0 {
57		throw("sem_init")
58	}
59	mp.waitsema = uintptr(unsafe.Pointer(sem))
60}
61
62//go:nosplit
63func semasleep(ns int64) int32 {
64	_m_ := getg().m
65	if ns >= 0 {
66		var ts timespec
67
68		if clock_gettime(_CLOCK_REALTIME, &ts) != 0 {
69			throw("clock_gettime")
70		}
71
72		sec := int64(ts.tv_sec) + ns/1e9
73		nsec := int64(ts.tv_nsec) + ns%1e9
74		if nsec >= 1e9 {
75			sec++
76			nsec -= 1e9
77		}
78		if sec != int64(timespec_sec_t(sec)) {
79			// Handle overflows (timespec_sec_t is 32-bit in 32-bit applications)
80			sec = 1<<31 - 1
81		}
82		ts.tv_sec = timespec_sec_t(sec)
83		ts.tv_nsec = timespec_nsec_t(nsec)
84
85		if sem_timedwait((*_sem_t)(unsafe.Pointer(_m_.waitsema)), &ts) != 0 {
86			err := errno()
87			if err == _ETIMEDOUT || err == _EAGAIN || err == _EINTR {
88				return -1
89			}
90			throw("sem_timedwait")
91		}
92		return 0
93	}
94	for {
95		r1 := sem_wait((*_sem_t)(unsafe.Pointer(_m_.waitsema)))
96		if r1 == 0 {
97			break
98		}
99		if errno() == _EINTR {
100			continue
101		}
102		throw("sem_wait")
103	}
104	return 0
105}
106
107//go:nosplit
108func semawakeup(mp *m) {
109	if sem_post((*_sem_t)(unsafe.Pointer(mp.waitsema))) != 0 {
110		throw("sem_post")
111	}
112}
113
114func getncpu() int32 {
115	n := int32(sysconf(__SC_NPROCESSORS_ONLN))
116	if n < 1 {
117		return 1
118	}
119	return n
120}
121
122func osinit() {
123	ncpu = getncpu()
124	if physPageSize == 0 {
125		physPageSize = uintptr(getPageSize())
126	}
127}
128