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