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 := ×pec{} 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 := ×pec{} 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