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