|  | // 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. | 
|  |  | 
|  | // +build aix | 
|  |  | 
|  | package runtime | 
|  |  | 
|  | import ( | 
|  | "internal/cpu" | 
|  | "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 { | 
|  | _m_ := 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(_m_.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 ", _m_.id) | 
|  | throw("sem_timedwait") | 
|  | } | 
|  | return 0 | 
|  | } | 
|  | for { | 
|  | r1, err := sem_wait((*semt)(unsafe.Pointer(_m_.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) | 
|  | setupSystemConf() | 
|  | } | 
|  |  | 
|  | // 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() | 
|  | } | 
|  |  | 
|  | func unminit() { | 
|  | unminitSignals() | 
|  | } | 
|  |  | 
|  | // 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) | 
|  | 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, &tstart, unsafe.Pointer(mp)) | 
|  | if ret != _EAGAIN { | 
|  | break | 
|  | } | 
|  | usleep(uint32(tries+1) * 1000) // Milliseconds. | 
|  | } | 
|  | 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 *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 == funcPC(sighandler) { | 
|  | fn = uintptr(unsafe.Pointer(&sigtramp)) | 
|  | } | 
|  | sa.sa_handler = fn | 
|  | sigaction(uintptr(i), &sa, nil) | 
|  |  | 
|  | } | 
|  |  | 
|  | //go:nosplit | 
|  | //go:nowritebarrierrec | 
|  | func setsigstack(i uint32) { | 
|  | throw("Not yet implemented\n") | 
|  | } | 
|  |  | 
|  | //go:nosplit | 
|  | //go:nowritebarrierrec | 
|  | func getsig(i uint32) uintptr { | 
|  | var sa sigactiont | 
|  | sigaction(uintptr(i), nil, &sa) | 
|  | return sa.sa_handler | 
|  | } | 
|  |  | 
|  | // setSignaltstackSP sets the ss_sp field of a stackt. | 
|  | //go:nosplit | 
|  | func setSignalstackSP(s *stackt, sp uintptr) { | 
|  | *(*uintptr)(unsafe.Pointer(&s.ss_sp)) = sp | 
|  | } | 
|  |  | 
|  | func (c *sigctxt) fixsigcode(sig uint32) { | 
|  | } | 
|  |  | 
|  | 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) | 
|  | } | 
|  |  | 
|  | const ( | 
|  | _CLOCK_REALTIME  = 9 | 
|  | _CLOCK_MONOTONIC = 10 | 
|  | ) | 
|  |  | 
|  | //go:nosplit | 
|  | func nanotime() 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) | 
|  | } | 
|  |  | 
|  | const ( | 
|  | // getsystemcfg constants | 
|  | _SC_IMPL     = 2 | 
|  | _IMPL_POWER8 = 0x10000 | 
|  | _IMPL_POWER9 = 0x20000 | 
|  | ) | 
|  |  | 
|  | // setupSystemConf retrieves information about the CPU and updates | 
|  | // cpu.HWCap variables. | 
|  | func setupSystemConf() { | 
|  | impl := getsystemcfg(_SC_IMPL) | 
|  | if impl&_IMPL_POWER8 != 0 { | 
|  | cpu.HWCap2 |= cpu.PPC_FEATURE2_ARCH_2_07 | 
|  | } | 
|  | if impl&_IMPL_POWER9 != 0 { | 
|  | cpu.HWCap2 |= cpu.PPC_FEATURE2_ARCH_3_00 | 
|  | } | 
|  | } |