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