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