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