// Copyright 2018 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 aix package runtime import ( "internal/abi" "runtime/internal/atomic" "unsafe" ) const ( threadStackSize = 0x100000 // size of a thread stack allocated by OS ) // funcDescriptor is a structure representing a function descriptor // A variable with this type is always created in assembler type funcDescriptor struct { fn uintptr toc uintptr envPointer uintptr // unused in Golang } type mOS struct { waitsema uintptr // semaphore for parking on locks perrno uintptr // pointer to tls errno } //go:nosplit func semacreate(mp *m) { if mp.waitsema != 0 { return } var sem *semt // Call libc's malloc rather than malloc. This will // allocate space on the C heap. We can't call mallocgc // here because it could cause a deadlock. sem = (*semt)(malloc(unsafe.Sizeof(*sem))) if sem_init(sem, 0, 0) != 0 { throw("sem_init") } mp.waitsema = uintptr(unsafe.Pointer(sem)) } //go:nosplit func semasleep(ns int64) int32 { mp := getg().m if ns >= 0 { var ts timespec if clock_gettime(_CLOCK_REALTIME, &ts) != 0 { throw("clock_gettime") } ts.tv_sec += ns / 1e9 ts.tv_nsec += ns % 1e9 if ts.tv_nsec >= 1e9 { ts.tv_sec++ ts.tv_nsec -= 1e9 } if r, err := sem_timedwait((*semt)(unsafe.Pointer(mp.waitsema)), &ts); r != 0 { if err == _ETIMEDOUT || err == _EAGAIN || err == _EINTR { return -1 } println("sem_timedwait err ", err, " ts.tv_sec ", ts.tv_sec, " ts.tv_nsec ", ts.tv_nsec, " ns ", ns, " id ", mp.id) throw("sem_timedwait") } return 0 } for { r1, err := sem_wait((*semt)(unsafe.Pointer(mp.waitsema))) if r1 == 0 { break } if err == _EINTR { continue } throw("sem_wait") } return 0 } //go:nosplit func semawakeup(mp *m) { if sem_post((*semt)(unsafe.Pointer(mp.waitsema))) != 0 { throw("sem_post") } } func osinit() { ncpu = int32(sysconf(__SC_NPROCESSORS_ONLN)) physPageSize = sysconf(__SC_PAGE_SIZE) } // newosproc0 is a version of newosproc that can be called before the runtime // is initialized. // // This function is not safe to use after initialization as it does not pass an M as fnarg. // //go:nosplit func newosproc0(stacksize uintptr, fn *funcDescriptor) { var ( attr pthread_attr oset sigset tid pthread ) if pthread_attr_init(&attr) != 0 { writeErrStr(failthreadcreate) exit(1) } if pthread_attr_setstacksize(&attr, threadStackSize) != 0 { writeErrStr(failthreadcreate) exit(1) } if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 { writeErrStr(failthreadcreate) exit(1) } // Disable signals during create, so that the new thread starts // with signals disabled. It will enable them in minit. sigprocmask(_SIG_SETMASK, &sigset_all, &oset) var ret int32 for tries := 0; tries < 20; tries++ { // pthread_create can fail with EAGAIN for no reasons // but it will be ok if it retries. ret = pthread_create(&tid, &attr, fn, nil) if ret != _EAGAIN { break } usleep(uint32(tries+1) * 1000) // Milliseconds. } sigprocmask(_SIG_SETMASK, &oset, nil) if ret != 0 { writeErrStr(failthreadcreate) exit(1) } } // Called to do synchronous initialization of Go code built with // -buildmode=c-archive or -buildmode=c-shared. // None of the Go runtime is initialized. // //go:nosplit //go:nowritebarrierrec func libpreinit() { initsig(true) } // Ms related functions func mpreinit(mp *m) { mp.gsignal = malg(32 * 1024) // AIX wants >= 8K mp.gsignal.m = mp } // errno address must be retrieved by calling _Errno libc function. // This will return a pointer to errno. func miniterrno() { mp := getg().m r, _ := syscall0(&libc__Errno) mp.perrno = r } func minit() { miniterrno() minitSignals() getg().m.procid = uint64(pthread_self()) } func unminit() { unminitSignals() } // Called from exitm, but not from drop, to undo the effect of thread-owned // resources in minit, semacreate, or elsewhere. Do not take locks after calling this. func mdestroy(mp *m) { } // tstart is a function descriptor to _tstart defined in assembly. var tstart funcDescriptor func newosproc(mp *m) { var ( attr pthread_attr oset sigset tid pthread ) if pthread_attr_init(&attr) != 0 { throw("pthread_attr_init") } if pthread_attr_setstacksize(&attr, threadStackSize) != 0 { throw("pthread_attr_getstacksize") } if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 { throw("pthread_attr_setdetachstate") } // Disable signals during create, so that the new thread starts // with signals disabled. It will enable them in minit. sigprocmask(_SIG_SETMASK, &sigset_all, &oset) ret := retryOnEAGAIN(func() int32 { return pthread_create(&tid, &attr, &tstart, unsafe.Pointer(mp)) }) sigprocmask(_SIG_SETMASK, &oset, nil) if ret != 0 { print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", ret, ")\n") if ret == _EAGAIN { println("runtime: may need to increase max user processes (ulimit -u)") } throw("newosproc") } } func exitThread(wait *atomic.Uint32) { // We should never reach exitThread on AIX because we let // libc clean up threads. throw("exitThread") } var urandom_dev = []byte("/dev/urandom\x00") //go:nosplit func getRandomData(r []byte) { fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0) n := read(fd, unsafe.Pointer(&r[0]), int32(len(r))) closefd(fd) extendRandom(r, int(n)) } func goenvs() { goenvs_unix() } /* SIGNAL */ const ( _NSIG = 256 ) // sigtramp is a function descriptor to _sigtramp defined in assembly var sigtramp funcDescriptor //go:nosplit //go:nowritebarrierrec func setsig(i uint32, fn uintptr) { var sa sigactiont sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART sa.sa_mask = sigset_all if fn == abi.FuncPCABIInternal(sighandler) { // abi.FuncPCABIInternal(sighandler) matches the callers in signal_unix.go fn = uintptr(unsafe.Pointer(&sigtramp)) } sa.sa_handler = fn sigaction(uintptr(i), &sa, nil) } //go:nosplit //go:nowritebarrierrec func setsigstack(i uint32) { var sa sigactiont sigaction(uintptr(i), nil, &sa) if sa.sa_flags&_SA_ONSTACK != 0 { return } sa.sa_flags |= _SA_ONSTACK sigaction(uintptr(i), &sa, nil) } //go:nosplit //go:nowritebarrierrec func getsig(i uint32) uintptr { var sa sigactiont sigaction(uintptr(i), nil, &sa) return sa.sa_handler } // setSignalstackSP sets the ss_sp field of a stackt. // //go:nosplit func setSignalstackSP(s *stackt, sp uintptr) { *(*uintptr)(unsafe.Pointer(&s.ss_sp)) = sp } //go:nosplit func (c *sigctxt) fixsigcode(sig uint32) { switch sig { case _SIGPIPE: // For SIGPIPE, c.sigcode() isn't set to _SI_USER as on Linux. // Therefore, raisebadsignal won't raise SIGPIPE again if // it was deliver in a non-Go thread. c.set_sigcode(_SI_USER) } } //go:nosplit //go:nowritebarrierrec func sigaddset(mask *sigset, i int) { (*mask)[(i-1)/64] |= 1 << ((uint32(i) - 1) & 63) } func sigdelset(mask *sigset, i int) { (*mask)[(i-1)/64] &^= 1 << ((uint32(i) - 1) & 63) } func setProcessCPUProfiler(hz int32) { setProcessCPUProfilerTimer(hz) } func setThreadCPUProfiler(hz int32) { setThreadCPUProfilerHz(hz) } //go:nosplit func validSIGPROF(mp *m, c *sigctxt) bool { return true } const ( _CLOCK_REALTIME = 9 _CLOCK_MONOTONIC = 10 ) //go:nosplit func nanotime1() int64 { tp := ×pec{} if clock_gettime(_CLOCK_REALTIME, tp) != 0 { throw("syscall clock_gettime failed") } return tp.tv_sec*1000000000 + tp.tv_nsec } func walltime() (sec int64, nsec int32) { ts := ×pec{} if clock_gettime(_CLOCK_REALTIME, ts) != 0 { throw("syscall clock_gettime failed") } return ts.tv_sec, int32(ts.tv_nsec) } //go:nosplit func fcntl(fd, cmd, arg int32) (int32, int32) { r, errno := syscall3(&libc_fcntl, uintptr(fd), uintptr(cmd), uintptr(arg)) return int32(r), int32(errno) } //go:nosplit func closeonexec(fd int32) { fcntl(fd, _F_SETFD, _FD_CLOEXEC) } //go:nosplit func setNonblock(fd int32) { flags, _ := fcntl(fd, _F_GETFL, 0) if flags != -1 { fcntl(fd, _F_SETFL, flags|_O_NONBLOCK) } } // sigPerThreadSyscall is only used on linux, so we assign a bogus signal // number. const sigPerThreadSyscall = 1 << 31 //go:nosplit func runPerThreadSyscall() { throw("runPerThreadSyscall only valid on linux") } //go:nosplit func getuid() int32 { r, errno := syscall0(&libc_getuid) if errno != 0 { print("getuid failed ", errno) throw("getuid") } return int32(r) } //go:nosplit func geteuid() int32 { r, errno := syscall0(&libc_geteuid) if errno != 0 { print("geteuid failed ", errno) throw("geteuid") } return int32(r) } //go:nosplit func getgid() int32 { r, errno := syscall0(&libc_getgid) if errno != 0 { print("getgid failed ", errno) throw("getgid") } return int32(r) } //go:nosplit func getegid() int32 { r, errno := syscall0(&libc_getegid) if errno != 0 { print("getegid failed ", errno) throw("getegid") } return int32(r) }