github.com/m10x/go/src@v0.0.0-20220112094212-ba61592315da/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 "unsafe" 12 ) 13 14 const ( 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 20 type funcDescriptor struct { 21 fn uintptr 22 toc uintptr 23 envPointer uintptr // unused in Golang 24 } 25 26 type mOS struct { 27 waitsema uintptr // semaphore for parking on locks 28 perrno uintptr // pointer to tls errno 29 } 30 31 //go:nosplit 32 func 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 50 func semasleep(ns int64) int32 { 51 mp := 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(mp.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 ", mp.id) 70 throw("sem_timedwait") 71 } 72 return 0 73 } 74 for { 75 r1, err := sem_wait((*semt)(unsafe.Pointer(mp.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 88 func semawakeup(mp *m) { 89 if sem_post((*semt)(unsafe.Pointer(mp.waitsema))) != 0 { 90 throw("sem_post") 91 } 92 } 93 94 func osinit() { 95 ncpu = int32(sysconf(__SC_NPROCESSORS_ONLN)) 96 physPageSize = sysconf(__SC_PAGE_SIZE) 97 } 98 99 // newosproc0 is a version of newosproc that can be called before the runtime 100 // is initialized. 101 // 102 // This function is not safe to use after initialization as it does not pass an M as fnarg. 103 // 104 //go:nosplit 105 func newosproc0(stacksize uintptr, fn *funcDescriptor) { 106 var ( 107 attr pthread_attr 108 oset sigset 109 tid pthread 110 ) 111 112 if pthread_attr_init(&attr) != 0 { 113 write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate))) 114 exit(1) 115 } 116 117 if pthread_attr_setstacksize(&attr, threadStackSize) != 0 { 118 write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate))) 119 exit(1) 120 } 121 122 if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 { 123 write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate))) 124 exit(1) 125 } 126 127 // Disable signals during create, so that the new thread starts 128 // with signals disabled. It will enable them in minit. 129 sigprocmask(_SIG_SETMASK, &sigset_all, &oset) 130 var ret int32 131 for tries := 0; tries < 20; tries++ { 132 // pthread_create can fail with EAGAIN for no reasons 133 // but it will be ok if it retries. 134 ret = pthread_create(&tid, &attr, fn, nil) 135 if ret != _EAGAIN { 136 break 137 } 138 usleep(uint32(tries+1) * 1000) // Milliseconds. 139 } 140 sigprocmask(_SIG_SETMASK, &oset, nil) 141 if ret != 0 { 142 write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate))) 143 exit(1) 144 } 145 146 } 147 148 var failthreadcreate = []byte("runtime: failed to create new OS thread\n") 149 150 // Called to do synchronous initialization of Go code built with 151 // -buildmode=c-archive or -buildmode=c-shared. 152 // None of the Go runtime is initialized. 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 var ret int32 215 for tries := 0; tries < 20; tries++ { 216 // pthread_create can fail with EAGAIN for no reasons 217 // but it will be ok if it retries. 218 ret = pthread_create(&tid, &attr, &tstart, unsafe.Pointer(mp)) 219 if ret != _EAGAIN { 220 break 221 } 222 usleep(uint32(tries+1) * 1000) // Milliseconds. 223 } 224 sigprocmask(_SIG_SETMASK, &oset, nil) 225 if ret != 0 { 226 print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", ret, ")\n") 227 if ret == _EAGAIN { 228 println("runtime: may need to increase max user processes (ulimit -u)") 229 } 230 throw("newosproc") 231 } 232 233 } 234 235 func exitThread(wait *uint32) { 236 // We should never reach exitThread on AIX because we let 237 // libc clean up threads. 238 throw("exitThread") 239 } 240 241 var urandom_dev = []byte("/dev/urandom\x00") 242 243 //go:nosplit 244 func getRandomData(r []byte) { 245 fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0) 246 n := read(fd, unsafe.Pointer(&r[0]), int32(len(r))) 247 closefd(fd) 248 extendRandom(r, int(n)) 249 } 250 251 func goenvs() { 252 goenvs_unix() 253 } 254 255 /* SIGNAL */ 256 257 const ( 258 _NSIG = 256 259 ) 260 261 // sigtramp is a function descriptor to _sigtramp defined in assembly 262 var sigtramp funcDescriptor 263 264 //go:nosplit 265 //go:nowritebarrierrec 266 func setsig(i uint32, fn uintptr) { 267 var sa sigactiont 268 sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART 269 sa.sa_mask = sigset_all 270 if fn == abi.FuncPCABIInternal(sighandler) { // abi.FuncPCABIInternal(sighandler) matches the callers in signal_unix.go 271 fn = uintptr(unsafe.Pointer(&sigtramp)) 272 } 273 sa.sa_handler = fn 274 sigaction(uintptr(i), &sa, nil) 275 276 } 277 278 //go:nosplit 279 //go:nowritebarrierrec 280 func setsigstack(i uint32) { 281 var sa sigactiont 282 sigaction(uintptr(i), nil, &sa) 283 if sa.sa_flags&_SA_ONSTACK != 0 { 284 return 285 } 286 sa.sa_flags |= _SA_ONSTACK 287 sigaction(uintptr(i), &sa, nil) 288 } 289 290 //go:nosplit 291 //go:nowritebarrierrec 292 func getsig(i uint32) uintptr { 293 var sa sigactiont 294 sigaction(uintptr(i), nil, &sa) 295 return sa.sa_handler 296 } 297 298 // setSignaltstackSP sets the ss_sp field of a stackt. 299 //go:nosplit 300 func setSignalstackSP(s *stackt, sp uintptr) { 301 *(*uintptr)(unsafe.Pointer(&s.ss_sp)) = sp 302 } 303 304 //go:nosplit 305 func (c *sigctxt) fixsigcode(sig uint32) { 306 switch sig { 307 case _SIGPIPE: 308 // For SIGPIPE, c.sigcode() isn't set to _SI_USER as on Linux. 309 // Therefore, raisebadsignal won't raise SIGPIPE again if 310 // it was deliver in a non-Go thread. 311 c.set_sigcode(_SI_USER) 312 } 313 } 314 315 //go:nosplit 316 //go:nowritebarrierrec 317 func sigaddset(mask *sigset, i int) { 318 (*mask)[(i-1)/64] |= 1 << ((uint32(i) - 1) & 63) 319 } 320 321 func sigdelset(mask *sigset, i int) { 322 (*mask)[(i-1)/64] &^= 1 << ((uint32(i) - 1) & 63) 323 } 324 325 func setProcessCPUProfiler(hz int32) { 326 setProcessCPUProfilerTimer(hz) 327 } 328 329 func setThreadCPUProfiler(hz int32) { 330 setThreadCPUProfilerHz(hz) 331 } 332 333 //go:nosplit 334 func validSIGPROF(mp *m, c *sigctxt) bool { 335 return true 336 } 337 338 const ( 339 _CLOCK_REALTIME = 9 340 _CLOCK_MONOTONIC = 10 341 ) 342 343 //go:nosplit 344 func nanotime1() int64 { 345 tp := ×pec{} 346 if clock_gettime(_CLOCK_REALTIME, tp) != 0 { 347 throw("syscall clock_gettime failed") 348 } 349 return tp.tv_sec*1000000000 + tp.tv_nsec 350 } 351 352 func walltime() (sec int64, nsec int32) { 353 ts := ×pec{} 354 if clock_gettime(_CLOCK_REALTIME, ts) != 0 { 355 throw("syscall clock_gettime failed") 356 } 357 return ts.tv_sec, int32(ts.tv_nsec) 358 } 359 360 //go:nosplit 361 func fcntl(fd, cmd, arg int32) int32 { 362 r, _ := syscall3(&libc_fcntl, uintptr(fd), uintptr(cmd), uintptr(arg)) 363 return int32(r) 364 } 365 366 //go:nosplit 367 func closeonexec(fd int32) { 368 fcntl(fd, _F_SETFD, _FD_CLOEXEC) 369 } 370 371 //go:nosplit 372 func setNonblock(fd int32) { 373 flags := fcntl(fd, _F_GETFL, 0) 374 fcntl(fd, _F_SETFL, flags|_O_NONBLOCK) 375 }