github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/runtime/os_aix.go (about) 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 7 package runtime 8 9 import ( 10 "internal/abi" 11 "runtime/internal/atomic" 12 "unsafe" 13 ) 14 15 const ( 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 21 type funcDescriptor struct { 22 fn uintptr 23 toc uintptr 24 envPointer uintptr // unused in Golang 25 } 26 27 type mOS struct { 28 waitsema uintptr // semaphore for parking on locks 29 perrno uintptr // pointer to tls errno 30 } 31 32 //go:nosplit 33 func 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 51 func 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 89 func semawakeup(mp *m) { 90 if sem_post((*semt)(unsafe.Pointer(mp.waitsema))) != 0 { 91 throw("sem_post") 92 } 93 } 94 95 func osinit() { 96 ncpu = int32(sysconf(__SC_NPROCESSORS_ONLN)) 97 physPageSize = sysconf(__SC_PAGE_SIZE) 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 106 func 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 writeErrStr(failthreadcreate) 115 exit(1) 116 } 117 118 if pthread_attr_setstacksize(&attr, threadStackSize) != 0 { 119 writeErrStr(failthreadcreate) 120 exit(1) 121 } 122 123 if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 { 124 writeErrStr(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 writeErrStr(failthreadcreate) 144 exit(1) 145 } 146 147 } 148 149 // Called to do synchronous initialization of Go code built with 150 // -buildmode=c-archive or -buildmode=c-shared. 151 // None of the Go runtime is initialized. 152 // 153 //go:nosplit 154 //go:nowritebarrierrec 155 func libpreinit() { 156 initsig(true) 157 } 158 159 // Ms related functions 160 func mpreinit(mp *m) { 161 mp.gsignal = malg(32 * 1024) // AIX wants >= 8K 162 mp.gsignal.m = mp 163 } 164 165 // errno address must be retrieved by calling _Errno libc function. 166 // This will return a pointer to errno. 167 func miniterrno() { 168 mp := getg().m 169 r, _ := syscall0(&libc__Errno) 170 mp.perrno = r 171 172 } 173 174 func minit() { 175 miniterrno() 176 minitSignals() 177 getg().m.procid = uint64(pthread_self()) 178 } 179 180 func unminit() { 181 unminitSignals() 182 } 183 184 // Called from exitm, but not from drop, to undo the effect of thread-owned 185 // resources in minit, semacreate, or elsewhere. Do not take locks after calling this. 186 func mdestroy(mp *m) { 187 } 188 189 // tstart is a function descriptor to _tstart defined in assembly. 190 var tstart funcDescriptor 191 192 func newosproc(mp *m) { 193 var ( 194 attr pthread_attr 195 oset sigset 196 tid pthread 197 ) 198 199 if pthread_attr_init(&attr) != 0 { 200 throw("pthread_attr_init") 201 } 202 203 if pthread_attr_setstacksize(&attr, threadStackSize) != 0 { 204 throw("pthread_attr_getstacksize") 205 } 206 207 if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 { 208 throw("pthread_attr_setdetachstate") 209 } 210 211 // Disable signals during create, so that the new thread starts 212 // with signals disabled. It will enable them in minit. 213 sigprocmask(_SIG_SETMASK, &sigset_all, &oset) 214 ret := retryOnEAGAIN(func() int32 { 215 return pthread_create(&tid, &attr, &tstart, unsafe.Pointer(mp)) 216 }) 217 sigprocmask(_SIG_SETMASK, &oset, nil) 218 if ret != 0 { 219 print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", ret, ")\n") 220 if ret == _EAGAIN { 221 println("runtime: may need to increase max user processes (ulimit -u)") 222 } 223 throw("newosproc") 224 } 225 226 } 227 228 func exitThread(wait *atomic.Uint32) { 229 // We should never reach exitThread on AIX because we let 230 // libc clean up threads. 231 throw("exitThread") 232 } 233 234 var urandom_dev = []byte("/dev/urandom\x00") 235 236 //go:nosplit 237 func getRandomData(r []byte) { 238 fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0) 239 n := read(fd, unsafe.Pointer(&r[0]), int32(len(r))) 240 closefd(fd) 241 extendRandom(r, int(n)) 242 } 243 244 func goenvs() { 245 goenvs_unix() 246 } 247 248 /* SIGNAL */ 249 250 const ( 251 _NSIG = 256 252 ) 253 254 // sigtramp is a function descriptor to _sigtramp defined in assembly 255 var sigtramp funcDescriptor 256 257 //go:nosplit 258 //go:nowritebarrierrec 259 func setsig(i uint32, fn uintptr) { 260 var sa sigactiont 261 sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART 262 sa.sa_mask = sigset_all 263 if fn == abi.FuncPCABIInternal(sighandler) { // abi.FuncPCABIInternal(sighandler) matches the callers in signal_unix.go 264 fn = uintptr(unsafe.Pointer(&sigtramp)) 265 } 266 sa.sa_handler = fn 267 sigaction(uintptr(i), &sa, nil) 268 269 } 270 271 //go:nosplit 272 //go:nowritebarrierrec 273 func setsigstack(i uint32) { 274 var sa sigactiont 275 sigaction(uintptr(i), nil, &sa) 276 if sa.sa_flags&_SA_ONSTACK != 0 { 277 return 278 } 279 sa.sa_flags |= _SA_ONSTACK 280 sigaction(uintptr(i), &sa, nil) 281 } 282 283 //go:nosplit 284 //go:nowritebarrierrec 285 func getsig(i uint32) uintptr { 286 var sa sigactiont 287 sigaction(uintptr(i), nil, &sa) 288 return sa.sa_handler 289 } 290 291 // setSignalstackSP sets the ss_sp field of a stackt. 292 // 293 //go:nosplit 294 func setSignalstackSP(s *stackt, sp uintptr) { 295 *(*uintptr)(unsafe.Pointer(&s.ss_sp)) = sp 296 } 297 298 //go:nosplit 299 func (c *sigctxt) fixsigcode(sig uint32) { 300 switch sig { 301 case _SIGPIPE: 302 // For SIGPIPE, c.sigcode() isn't set to _SI_USER as on Linux. 303 // Therefore, raisebadsignal won't raise SIGPIPE again if 304 // it was deliver in a non-Go thread. 305 c.set_sigcode(_SI_USER) 306 } 307 } 308 309 //go:nosplit 310 //go:nowritebarrierrec 311 func sigaddset(mask *sigset, i int) { 312 (*mask)[(i-1)/64] |= 1 << ((uint32(i) - 1) & 63) 313 } 314 315 func sigdelset(mask *sigset, i int) { 316 (*mask)[(i-1)/64] &^= 1 << ((uint32(i) - 1) & 63) 317 } 318 319 func setProcessCPUProfiler(hz int32) { 320 setProcessCPUProfilerTimer(hz) 321 } 322 323 func setThreadCPUProfiler(hz int32) { 324 setThreadCPUProfilerHz(hz) 325 } 326 327 //go:nosplit 328 func validSIGPROF(mp *m, c *sigctxt) bool { 329 return true 330 } 331 332 const ( 333 _CLOCK_REALTIME = 9 334 _CLOCK_MONOTONIC = 10 335 ) 336 337 //go:nosplit 338 func nanotime1() int64 { 339 tp := ×pec{} 340 if clock_gettime(_CLOCK_REALTIME, tp) != 0 { 341 throw("syscall clock_gettime failed") 342 } 343 return tp.tv_sec*1000000000 + tp.tv_nsec 344 } 345 346 func walltime() (sec int64, nsec int32) { 347 ts := ×pec{} 348 if clock_gettime(_CLOCK_REALTIME, ts) != 0 { 349 throw("syscall clock_gettime failed") 350 } 351 return ts.tv_sec, int32(ts.tv_nsec) 352 } 353 354 //go:nosplit 355 func fcntl(fd, cmd, arg int32) int32 { 356 r, _ := syscall3(&libc_fcntl, uintptr(fd), uintptr(cmd), uintptr(arg)) 357 return int32(r) 358 } 359 360 //go:nosplit 361 func closeonexec(fd int32) { 362 fcntl(fd, _F_SETFD, _FD_CLOEXEC) 363 } 364 365 //go:nosplit 366 func setNonblock(fd int32) { 367 flags := fcntl(fd, _F_GETFL, 0) 368 fcntl(fd, _F_SETFL, flags|_O_NONBLOCK) 369 } 370 371 // sigPerThreadSyscall is only used on linux, so we assign a bogus signal 372 // number. 373 const sigPerThreadSyscall = 1 << 31 374 375 //go:nosplit 376 func runPerThreadSyscall() { 377 throw("runPerThreadSyscall only valid on linux") 378 }