github.com/AESNooper/go/src@v0.0.0-20220218095104-b56a4ab1bbbb/runtime/os_plan9.go (about) 1 // Copyright 2010 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 package runtime 6 7 import ( 8 "internal/abi" 9 "runtime/internal/atomic" 10 "unsafe" 11 ) 12 13 type mOS struct { 14 waitsemacount uint32 15 notesig *int8 16 errstr *byte 17 ignoreHangup bool 18 } 19 20 func closefd(fd int32) int32 21 22 //go:noescape 23 func open(name *byte, mode, perm int32) int32 24 25 //go:noescape 26 func pread(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32 27 28 //go:noescape 29 func pwrite(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32 30 31 func seek(fd int32, offset int64, whence int32) int64 32 33 //go:noescape 34 func exits(msg *byte) 35 36 //go:noescape 37 func brk_(addr unsafe.Pointer) int32 38 39 func sleep(ms int32) int32 40 41 func rfork(flags int32) int32 42 43 //go:noescape 44 func plan9_semacquire(addr *uint32, block int32) int32 45 46 //go:noescape 47 func plan9_tsemacquire(addr *uint32, ms int32) int32 48 49 //go:noescape 50 func plan9_semrelease(addr *uint32, count int32) int32 51 52 //go:noescape 53 func notify(fn unsafe.Pointer) int32 54 55 func noted(mode int32) int32 56 57 //go:noescape 58 func nsec(*int64) int64 59 60 //go:noescape 61 func sigtramp(ureg, note unsafe.Pointer) 62 63 func setfpmasks() 64 65 //go:noescape 66 func tstart_plan9(newm *m) 67 68 func errstr() string 69 70 type _Plink uintptr 71 72 //go:linkname os_sigpipe os.sigpipe 73 func os_sigpipe() { 74 throw("too many writes on closed pipe") 75 } 76 77 func sigpanic() { 78 g := getg() 79 if !canpanic(g) { 80 throw("unexpected signal during runtime execution") 81 } 82 83 note := gostringnocopy((*byte)(unsafe.Pointer(g.m.notesig))) 84 switch g.sig { 85 case _SIGRFAULT, _SIGWFAULT: 86 i := indexNoFloat(note, "addr=") 87 if i >= 0 { 88 i += 5 89 } else if i = indexNoFloat(note, "va="); i >= 0 { 90 i += 3 91 } else { 92 panicmem() 93 } 94 addr := note[i:] 95 g.sigcode1 = uintptr(atolwhex(addr)) 96 if g.sigcode1 < 0x1000 { 97 panicmem() 98 } 99 if g.paniconfault { 100 panicmemAddr(g.sigcode1) 101 } 102 print("unexpected fault address ", hex(g.sigcode1), "\n") 103 throw("fault") 104 case _SIGTRAP: 105 if g.paniconfault { 106 panicmem() 107 } 108 throw(note) 109 case _SIGINTDIV: 110 panicdivide() 111 case _SIGFLOAT: 112 panicfloat() 113 default: 114 panic(errorString(note)) 115 } 116 } 117 118 // indexNoFloat is bytealg.IndexString but safe to use in a note 119 // handler. 120 func indexNoFloat(s, t string) int { 121 if len(t) == 0 { 122 return 0 123 } 124 for i := 0; i < len(s); i++ { 125 if s[i] == t[0] && hasPrefix(s[i:], t) { 126 return i 127 } 128 } 129 return -1 130 } 131 132 func atolwhex(p string) int64 { 133 for hasPrefix(p, " ") || hasPrefix(p, "\t") { 134 p = p[1:] 135 } 136 neg := false 137 if hasPrefix(p, "-") || hasPrefix(p, "+") { 138 neg = p[0] == '-' 139 p = p[1:] 140 for hasPrefix(p, " ") || hasPrefix(p, "\t") { 141 p = p[1:] 142 } 143 } 144 var n int64 145 switch { 146 case hasPrefix(p, "0x"), hasPrefix(p, "0X"): 147 p = p[2:] 148 for ; len(p) > 0; p = p[1:] { 149 if '0' <= p[0] && p[0] <= '9' { 150 n = n*16 + int64(p[0]-'0') 151 } else if 'a' <= p[0] && p[0] <= 'f' { 152 n = n*16 + int64(p[0]-'a'+10) 153 } else if 'A' <= p[0] && p[0] <= 'F' { 154 n = n*16 + int64(p[0]-'A'+10) 155 } else { 156 break 157 } 158 } 159 case hasPrefix(p, "0"): 160 for ; len(p) > 0 && '0' <= p[0] && p[0] <= '7'; p = p[1:] { 161 n = n*8 + int64(p[0]-'0') 162 } 163 default: 164 for ; len(p) > 0 && '0' <= p[0] && p[0] <= '9'; p = p[1:] { 165 n = n*10 + int64(p[0]-'0') 166 } 167 } 168 if neg { 169 n = -n 170 } 171 return n 172 } 173 174 type sigset struct{} 175 176 // Called to initialize a new m (including the bootstrap m). 177 // Called on the parent thread (main thread in case of bootstrap), can allocate memory. 178 func mpreinit(mp *m) { 179 // Initialize stack and goroutine for note handling. 180 mp.gsignal = malg(32 * 1024) 181 mp.gsignal.m = mp 182 mp.notesig = (*int8)(mallocgc(_ERRMAX, nil, true)) 183 // Initialize stack for handling strings from the 184 // errstr system call, as used in package syscall. 185 mp.errstr = (*byte)(mallocgc(_ERRMAX, nil, true)) 186 } 187 188 func sigsave(p *sigset) { 189 } 190 191 func msigrestore(sigmask sigset) { 192 } 193 194 //go:nosplit 195 //go:nowritebarrierrec 196 func clearSignalHandlers() { 197 } 198 199 func sigblock(exiting bool) { 200 } 201 202 // Called to initialize a new m (including the bootstrap m). 203 // Called on the new thread, cannot allocate memory. 204 func minit() { 205 if atomic.Load(&exiting) != 0 { 206 exits(&emptystatus[0]) 207 } 208 // Mask all SSE floating-point exceptions 209 // when running on the 64-bit kernel. 210 setfpmasks() 211 } 212 213 // Called from dropm to undo the effect of an minit. 214 func unminit() { 215 } 216 217 // Called from exitm, but not from drop, to undo the effect of thread-owned 218 // resources in minit, semacreate, or elsewhere. Do not take locks after calling this. 219 func mdestroy(mp *m) { 220 } 221 222 var sysstat = []byte("/dev/sysstat\x00") 223 224 func getproccount() int32 { 225 var buf [2048]byte 226 fd := open(&sysstat[0], _OREAD, 0) 227 if fd < 0 { 228 return 1 229 } 230 ncpu := int32(0) 231 for { 232 n := read(fd, unsafe.Pointer(&buf), int32(len(buf))) 233 if n <= 0 { 234 break 235 } 236 for i := int32(0); i < n; i++ { 237 if buf[i] == '\n' { 238 ncpu++ 239 } 240 } 241 } 242 closefd(fd) 243 if ncpu == 0 { 244 ncpu = 1 245 } 246 return ncpu 247 } 248 249 var devswap = []byte("/dev/swap\x00") 250 var pagesize = []byte(" pagesize\n") 251 252 func getPageSize() uintptr { 253 var buf [2048]byte 254 var pos int 255 fd := open(&devswap[0], _OREAD, 0) 256 if fd < 0 { 257 // There's not much we can do if /dev/swap doesn't 258 // exist. However, nothing in the memory manager uses 259 // this on Plan 9, so it also doesn't really matter. 260 return minPhysPageSize 261 } 262 for pos < len(buf) { 263 n := read(fd, unsafe.Pointer(&buf[pos]), int32(len(buf)-pos)) 264 if n <= 0 { 265 break 266 } 267 pos += int(n) 268 } 269 closefd(fd) 270 text := buf[:pos] 271 // Find "<n> pagesize" line. 272 bol := 0 273 for i, c := range text { 274 if c == '\n' { 275 bol = i + 1 276 } 277 if bytesHasPrefix(text[i:], pagesize) { 278 // Parse number at the beginning of this line. 279 return uintptr(_atoi(text[bol:])) 280 } 281 } 282 // Again, the page size doesn't really matter, so use a fallback. 283 return minPhysPageSize 284 } 285 286 func bytesHasPrefix(s, prefix []byte) bool { 287 if len(s) < len(prefix) { 288 return false 289 } 290 for i, p := range prefix { 291 if s[i] != p { 292 return false 293 } 294 } 295 return true 296 } 297 298 var pid = []byte("#c/pid\x00") 299 300 func getpid() uint64 { 301 var b [20]byte 302 fd := open(&pid[0], 0, 0) 303 if fd >= 0 { 304 read(fd, unsafe.Pointer(&b), int32(len(b))) 305 closefd(fd) 306 } 307 c := b[:] 308 for c[0] == ' ' || c[0] == '\t' { 309 c = c[1:] 310 } 311 return uint64(_atoi(c)) 312 } 313 314 func osinit() { 315 initBloc() 316 ncpu = getproccount() 317 physPageSize = getPageSize() 318 getg().m.procid = getpid() 319 } 320 321 //go:nosplit 322 func crash() { 323 notify(nil) 324 *(*int)(nil) = 0 325 } 326 327 //go:nosplit 328 func getRandomData(r []byte) { 329 // inspired by wyrand see hash32.go for detail 330 t := nanotime() 331 v := getg().m.procid ^ uint64(t) 332 333 for len(r) > 0 { 334 v ^= 0xa0761d6478bd642f 335 v *= 0xe7037ed1a0b428db 336 size := 8 337 if len(r) < 8 { 338 size = len(r) 339 } 340 for i := 0; i < size; i++ { 341 r[i] = byte(v >> (8 * i)) 342 } 343 r = r[size:] 344 v = v>>32 | v<<32 345 } 346 } 347 348 func initsig(preinit bool) { 349 if !preinit { 350 notify(unsafe.Pointer(abi.FuncPCABI0(sigtramp))) 351 } 352 } 353 354 //go:nosplit 355 func osyield() { 356 sleep(0) 357 } 358 359 //go:nosplit 360 func osyield_no_g() { 361 osyield() 362 } 363 364 //go:nosplit 365 func usleep(µs uint32) { 366 ms := int32(µs / 1000) 367 if ms == 0 { 368 ms = 1 369 } 370 sleep(ms) 371 } 372 373 //go:nosplit 374 func usleep_no_g(usec uint32) { 375 usleep(usec) 376 } 377 378 //go:nosplit 379 func nanotime1() int64 { 380 var scratch int64 381 ns := nsec(&scratch) 382 // TODO(aram): remove hack after I fix _nsec in the pc64 kernel. 383 if ns == 0 { 384 return scratch 385 } 386 return ns 387 } 388 389 var goexits = []byte("go: exit ") 390 var emptystatus = []byte("\x00") 391 var exiting uint32 392 393 func goexitsall(status *byte) { 394 var buf [_ERRMAX]byte 395 if !atomic.Cas(&exiting, 0, 1) { 396 return 397 } 398 getg().m.locks++ 399 n := copy(buf[:], goexits) 400 n = copy(buf[n:], gostringnocopy(status)) 401 pid := getpid() 402 for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink { 403 if mp.procid != 0 && mp.procid != pid { 404 postnote(mp.procid, buf[:]) 405 } 406 } 407 getg().m.locks-- 408 } 409 410 var procdir = []byte("/proc/") 411 var notefile = []byte("/note\x00") 412 413 func postnote(pid uint64, msg []byte) int { 414 var buf [128]byte 415 var tmp [32]byte 416 n := copy(buf[:], procdir) 417 n += copy(buf[n:], itoa(tmp[:], pid)) 418 copy(buf[n:], notefile) 419 fd := open(&buf[0], _OWRITE, 0) 420 if fd < 0 { 421 return -1 422 } 423 len := findnull(&msg[0]) 424 if write1(uintptr(fd), unsafe.Pointer(&msg[0]), int32(len)) != int32(len) { 425 closefd(fd) 426 return -1 427 } 428 closefd(fd) 429 return 0 430 } 431 432 //go:nosplit 433 func exit(e int32) { 434 var status []byte 435 if e == 0 { 436 status = emptystatus 437 } else { 438 // build error string 439 var tmp [32]byte 440 status = append(itoa(tmp[:len(tmp)-1], uint64(e)), 0) 441 } 442 goexitsall(&status[0]) 443 exits(&status[0]) 444 } 445 446 // May run with m.p==nil, so write barriers are not allowed. 447 //go:nowritebarrier 448 func newosproc(mp *m) { 449 if false { 450 print("newosproc mp=", mp, " ostk=", &mp, "\n") 451 } 452 pid := rfork(_RFPROC | _RFMEM | _RFNOWAIT) 453 if pid < 0 { 454 throw("newosproc: rfork failed") 455 } 456 if pid == 0 { 457 tstart_plan9(mp) 458 } 459 } 460 461 func exitThread(wait *uint32) { 462 // We should never reach exitThread on Plan 9 because we let 463 // the OS clean up threads. 464 throw("exitThread") 465 } 466 467 //go:nosplit 468 func semacreate(mp *m) { 469 } 470 471 //go:nosplit 472 func semasleep(ns int64) int { 473 _g_ := getg() 474 if ns >= 0 { 475 ms := timediv(ns, 1000000, nil) 476 if ms == 0 { 477 ms = 1 478 } 479 ret := plan9_tsemacquire(&_g_.m.waitsemacount, ms) 480 if ret == 1 { 481 return 0 // success 482 } 483 return -1 // timeout or interrupted 484 } 485 for plan9_semacquire(&_g_.m.waitsemacount, 1) < 0 { 486 // interrupted; try again (c.f. lock_sema.go) 487 } 488 return 0 // success 489 } 490 491 //go:nosplit 492 func semawakeup(mp *m) { 493 plan9_semrelease(&mp.waitsemacount, 1) 494 } 495 496 //go:nosplit 497 func read(fd int32, buf unsafe.Pointer, n int32) int32 { 498 return pread(fd, buf, n, -1) 499 } 500 501 //go:nosplit 502 func write1(fd uintptr, buf unsafe.Pointer, n int32) int32 { 503 return pwrite(int32(fd), buf, n, -1) 504 } 505 506 var _badsignal = []byte("runtime: signal received on thread not created by Go.\n") 507 508 // This runs on a foreign stack, without an m or a g. No stack split. 509 //go:nosplit 510 func badsignal2() { 511 pwrite(2, unsafe.Pointer(&_badsignal[0]), int32(len(_badsignal)), -1) 512 exits(&_badsignal[0]) 513 } 514 515 func raisebadsignal(sig uint32) { 516 badsignal2() 517 } 518 519 func _atoi(b []byte) int { 520 n := 0 521 for len(b) > 0 && '0' <= b[0] && b[0] <= '9' { 522 n = n*10 + int(b[0]) - '0' 523 b = b[1:] 524 } 525 return n 526 } 527 528 func signame(sig uint32) string { 529 if sig >= uint32(len(sigtable)) { 530 return "" 531 } 532 return sigtable[sig].name 533 } 534 535 const preemptMSupported = false 536 537 func preemptM(mp *m) { 538 // Not currently supported. 539 // 540 // TODO: Use a note like we use signals on POSIX OSes 541 }