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
7package runtime
8
9import (
10	"internal/abi"
11	"internal/runtime/atomic"
12	"unsafe"
13)
14
15const (
16	threadStackSize = 0x100000 // size of a thread stack allocated by OS
17)
18
19// funcDescriptor is a structure representing a function descriptor
20// A variable with this type is always created in assembler
21type funcDescriptor struct {
22	fn         uintptr
23	toc        uintptr
24	envPointer uintptr // unused in Golang
25}
26
27type mOS struct {
28	waitsema uintptr // semaphore for parking on locks
29	perrno   uintptr // pointer to tls errno
30}
31
32//go:nosplit
33func semacreate(mp *m) {
34	if mp.waitsema != 0 {
35		return
36	}
37
38	var sem *semt
39
40	// Call libc's malloc rather than malloc. This will
41	// allocate space on the C heap. We can't call mallocgc
42	// here because it could cause a deadlock.
43	sem = (*semt)(malloc(unsafe.Sizeof(*sem)))
44	if sem_init(sem, 0, 0) != 0 {
45		throw("sem_init")
46	}
47	mp.waitsema = uintptr(unsafe.Pointer(sem))
48}
49
50//go:nosplit
51func semasleep(ns int64) int32 {
52	mp := getg().m
53	if ns >= 0 {
54		var ts timespec
55
56		if clock_gettime(_CLOCK_REALTIME, &ts) != 0 {
57			throw("clock_gettime")
58		}
59		ts.tv_sec += ns / 1e9
60		ts.tv_nsec += ns % 1e9
61		if ts.tv_nsec >= 1e9 {
62			ts.tv_sec++
63			ts.tv_nsec -= 1e9
64		}
65
66		if r, err := sem_timedwait((*semt)(unsafe.Pointer(mp.waitsema)), &ts); r != 0 {
67			if err == _ETIMEDOUT || err == _EAGAIN || err == _EINTR {
68				return -1
69			}
70			println("sem_timedwait err ", err, " ts.tv_sec ", ts.tv_sec, " ts.tv_nsec ", ts.tv_nsec, " ns ", ns, " id ", mp.id)
71			throw("sem_timedwait")
72		}
73		return 0
74	}
75	for {
76		r1, err := sem_wait((*semt)(unsafe.Pointer(mp.waitsema)))
77		if r1 == 0 {
78			break
79		}
80		if err == _EINTR {
81			continue
82		}
83		throw("sem_wait")
84	}
85	return 0
86}
87
88//go:nosplit
89func semawakeup(mp *m) {
90	if sem_post((*semt)(unsafe.Pointer(mp.waitsema))) != 0 {
91		throw("sem_post")
92	}
93}
94
95func osinit() {
96	// Call miniterrno so that we can safely make system calls
97	// before calling minit on m0.
98	miniterrno()
99
100	ncpu = int32(sysconf(__SC_NPROCESSORS_ONLN))
101	physPageSize = sysconf(__SC_PAGE_SIZE)
102}
103
104// newosproc0 is a version of newosproc that can be called before the runtime
105// is initialized.
106//
107// This function is not safe to use after initialization as it does not pass an M as fnarg.
108//
109//go:nosplit
110func newosproc0(stacksize uintptr, fn *funcDescriptor) {
111	var (
112		attr pthread_attr
113		oset sigset
114		tid  pthread
115	)
116
117	if pthread_attr_init(&attr) != 0 {
118		writeErrStr(failthreadcreate)
119		exit(1)
120	}
121
122	if pthread_attr_setstacksize(&attr, threadStackSize) != 0 {
123		writeErrStr(failthreadcreate)
124		exit(1)
125	}
126
127	if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 {
128		writeErrStr(failthreadcreate)
129		exit(1)
130	}
131
132	// Disable signals during create, so that the new thread starts
133	// with signals disabled. It will enable them in minit.
134	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
135	var ret int32
136	for tries := 0; tries < 20; tries++ {
137		// pthread_create can fail with EAGAIN for no reasons
138		// but it will be ok if it retries.
139		ret = pthread_create(&tid, &attr, fn, nil)
140		if ret != _EAGAIN {
141			break
142		}
143		usleep(uint32(tries+1) * 1000) // Milliseconds.
144	}
145	sigprocmask(_SIG_SETMASK, &oset, nil)
146	if ret != 0 {
147		writeErrStr(failthreadcreate)
148		exit(1)
149	}
150
151}
152
153// Called to do synchronous initialization of Go code built with
154// -buildmode=c-archive or -buildmode=c-shared.
155// None of the Go runtime is initialized.
156//
157//go:nosplit
158//go:nowritebarrierrec
159func libpreinit() {
160	initsig(true)
161}
162
163// Ms related functions
164func mpreinit(mp *m) {
165	mp.gsignal = malg(32 * 1024) // AIX wants >= 8K
166	mp.gsignal.m = mp
167}
168
169// errno address must be retrieved by calling _Errno libc function.
170// This will return a pointer to errno.
171func miniterrno() {
172	mp := getg().m
173	r, _ := syscall0(&libc__Errno)
174	mp.perrno = r
175
176}
177
178func minit() {
179	miniterrno()
180	minitSignals()
181	getg().m.procid = uint64(pthread_self())
182}
183
184func unminit() {
185	unminitSignals()
186	getg().m.procid = 0
187}
188
189// Called from exitm, but not from drop, to undo the effect of thread-owned
190// resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
191func mdestroy(mp *m) {
192}
193
194// tstart is a function descriptor to _tstart defined in assembly.
195var tstart funcDescriptor
196
197func newosproc(mp *m) {
198	var (
199		attr pthread_attr
200		oset sigset
201		tid  pthread
202	)
203
204	if pthread_attr_init(&attr) != 0 {
205		throw("pthread_attr_init")
206	}
207
208	if pthread_attr_setstacksize(&attr, threadStackSize) != 0 {
209		throw("pthread_attr_getstacksize")
210	}
211
212	if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 {
213		throw("pthread_attr_setdetachstate")
214	}
215
216	// Disable signals during create, so that the new thread starts
217	// with signals disabled. It will enable them in minit.
218	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
219	ret := retryOnEAGAIN(func() int32 {
220		return pthread_create(&tid, &attr, &tstart, unsafe.Pointer(mp))
221	})
222	sigprocmask(_SIG_SETMASK, &oset, nil)
223	if ret != 0 {
224		print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", ret, ")\n")
225		if ret == _EAGAIN {
226			println("runtime: may need to increase max user processes (ulimit -u)")
227		}
228		throw("newosproc")
229	}
230
231}
232
233func exitThread(wait *atomic.Uint32) {
234	// We should never reach exitThread on AIX because we let
235	// libc clean up threads.
236	throw("exitThread")
237}
238
239var urandom_dev = []byte("/dev/urandom\x00")
240
241//go:nosplit
242func readRandom(r []byte) int {
243	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
244	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
245	closefd(fd)
246	return int(n)
247}
248
249func goenvs() {
250	goenvs_unix()
251}
252
253/* SIGNAL */
254
255const (
256	_NSIG = 256
257)
258
259// sigtramp is a function descriptor to _sigtramp defined in assembly
260var sigtramp funcDescriptor
261
262//go:nosplit
263//go:nowritebarrierrec
264func setsig(i uint32, fn uintptr) {
265	var sa sigactiont
266	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
267	sa.sa_mask = sigset_all
268	if fn == abi.FuncPCABIInternal(sighandler) { // abi.FuncPCABIInternal(sighandler) matches the callers in signal_unix.go
269		fn = uintptr(unsafe.Pointer(&sigtramp))
270	}
271	sa.sa_handler = fn
272	sigaction(uintptr(i), &sa, nil)
273
274}
275
276//go:nosplit
277//go:nowritebarrierrec
278func setsigstack(i uint32) {
279	var sa sigactiont
280	sigaction(uintptr(i), nil, &sa)
281	if sa.sa_flags&_SA_ONSTACK != 0 {
282		return
283	}
284	sa.sa_flags |= _SA_ONSTACK
285	sigaction(uintptr(i), &sa, nil)
286}
287
288//go:nosplit
289//go:nowritebarrierrec
290func getsig(i uint32) uintptr {
291	var sa sigactiont
292	sigaction(uintptr(i), nil, &sa)
293	return sa.sa_handler
294}
295
296// setSignalstackSP sets the ss_sp field of a stackt.
297//
298//go:nosplit
299func setSignalstackSP(s *stackt, sp uintptr) {
300	*(*uintptr)(unsafe.Pointer(&s.ss_sp)) = sp
301}
302
303//go:nosplit
304func (c *sigctxt) fixsigcode(sig uint32) {
305	switch sig {
306	case _SIGPIPE:
307		// For SIGPIPE, c.sigcode() isn't set to _SI_USER as on Linux.
308		// Therefore, raisebadsignal won't raise SIGPIPE again if
309		// it was deliver in a non-Go thread.
310		c.set_sigcode(_SI_USER)
311	}
312}
313
314//go:nosplit
315//go:nowritebarrierrec
316func sigaddset(mask *sigset, i int) {
317	(*mask)[(i-1)/64] |= 1 << ((uint32(i) - 1) & 63)
318}
319
320func sigdelset(mask *sigset, i int) {
321	(*mask)[(i-1)/64] &^= 1 << ((uint32(i) - 1) & 63)
322}
323
324func setProcessCPUProfiler(hz int32) {
325	setProcessCPUProfilerTimer(hz)
326}
327
328func setThreadCPUProfiler(hz int32) {
329	setThreadCPUProfilerHz(hz)
330}
331
332//go:nosplit
333func validSIGPROF(mp *m, c *sigctxt) bool {
334	return true
335}
336
337const (
338	_CLOCK_REALTIME  = 9
339	_CLOCK_MONOTONIC = 10
340)
341
342//go:nosplit
343func nanotime1() int64 {
344	tp := &timespec{}
345	if clock_gettime(_CLOCK_REALTIME, tp) != 0 {
346		throw("syscall clock_gettime failed")
347	}
348	return tp.tv_sec*1000000000 + tp.tv_nsec
349}
350
351func walltime() (sec int64, nsec int32) {
352	ts := &timespec{}
353	if clock_gettime(_CLOCK_REALTIME, ts) != 0 {
354		throw("syscall clock_gettime failed")
355	}
356	return ts.tv_sec, int32(ts.tv_nsec)
357}
358
359//go:nosplit
360func fcntl(fd, cmd, arg int32) (int32, int32) {
361	r, errno := syscall3(&libc_fcntl, uintptr(fd), uintptr(cmd), uintptr(arg))
362	return int32(r), int32(errno)
363}
364
365//go:nosplit
366func setNonblock(fd int32) {
367	flags, _ := fcntl(fd, _F_GETFL, 0)
368	if flags != -1 {
369		fcntl(fd, _F_SETFL, flags|_O_NONBLOCK)
370	}
371}
372
373// sigPerThreadSyscall is only used on linux, so we assign a bogus signal
374// number.
375const sigPerThreadSyscall = 1 << 31
376
377//go:nosplit
378func runPerThreadSyscall() {
379	throw("runPerThreadSyscall only valid on linux")
380}
381
382//go:nosplit
383func getuid() int32 {
384	r, errno := syscall0(&libc_getuid)
385	if errno != 0 {
386		print("getuid failed ", errno)
387		throw("getuid")
388	}
389	return int32(r)
390}
391
392//go:nosplit
393func geteuid() int32 {
394	r, errno := syscall0(&libc_geteuid)
395	if errno != 0 {
396		print("geteuid failed ", errno)
397		throw("geteuid")
398	}
399	return int32(r)
400}
401
402//go:nosplit
403func getgid() int32 {
404	r, errno := syscall0(&libc_getgid)
405	if errno != 0 {
406		print("getgid failed ", errno)
407		throw("getgid")
408	}
409	return int32(r)
410}
411
412//go:nosplit
413func getegid() int32 {
414	r, errno := syscall0(&libc_getegid)
415	if errno != 0 {
416		print("getegid failed ", errno)
417		throw("getegid")
418	}
419	return int32(r)
420}
421