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