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