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