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 := index(note, "addr=") 86 if i >= 0 { 87 i += 5 88 } else if i = index(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 || g.paniconfault { 96 panicmem() 97 } 98 print("unexpected fault address ", hex(g.sigcode1), "\n") 99 throw("fault") 100 case _SIGTRAP: 101 if g.paniconfault { 102 panicmem() 103 } 104 throw(note) 105 case _SIGINTDIV: 106 panicdivide() 107 case _SIGFLOAT: 108 panicfloat() 109 default: 110 panic(errorString(note)) 111 } 112 } 113 114 func atolwhex(p string) int64 { 115 for hasprefix(p, " ") || hasprefix(p, "\t") { 116 p = p[1:] 117 } 118 neg := false 119 if hasprefix(p, "-") || hasprefix(p, "+") { 120 neg = p[0] == '-' 121 p = p[1:] 122 for hasprefix(p, " ") || hasprefix(p, "\t") { 123 p = p[1:] 124 } 125 } 126 var n int64 127 switch { 128 case hasprefix(p, "0x"), hasprefix(p, "0X"): 129 p = p[2:] 130 for ; len(p) > 0; p = p[1:] { 131 if '0' <= p[0] && p[0] <= '9' { 132 n = n*16 + int64(p[0]-'0') 133 } else if 'a' <= p[0] && p[0] <= 'f' { 134 n = n*16 + int64(p[0]-'a'+10) 135 } else if 'A' <= p[0] && p[0] <= 'F' { 136 n = n*16 + int64(p[0]-'A'+10) 137 } else { 138 break 139 } 140 } 141 case hasprefix(p, "0"): 142 for ; len(p) > 0 && '0' <= p[0] && p[0] <= '7'; p = p[1:] { 143 n = n*8 + int64(p[0]-'0') 144 } 145 default: 146 for ; len(p) > 0 && '0' <= p[0] && p[0] <= '9'; p = p[1:] { 147 n = n*10 + int64(p[0]-'0') 148 } 149 } 150 if neg { 151 n = -n 152 } 153 return n 154 } 155 156 type sigset struct{} 157 158 // Called to initialize a new m (including the bootstrap m). 159 // Called on the parent thread (main thread in case of bootstrap), can allocate memory. 160 func mpreinit(mp *m) { 161 // Initialize stack and goroutine for note handling. 162 mp.gsignal = malg(32 * 1024) 163 mp.gsignal.m = mp 164 mp.notesig = (*int8)(mallocgc(_ERRMAX, nil, true)) 165 // Initialize stack for handling strings from the 166 // errstr system call, as used in package syscall. 167 mp.errstr = (*byte)(mallocgc(_ERRMAX, nil, true)) 168 } 169 170 func msigsave(mp *m) { 171 } 172 173 func msigrestore(sigmask sigset) { 174 } 175 176 func sigblock() { 177 } 178 179 // Called to initialize a new m (including the bootstrap m). 180 // Called on the new thread, cannot allocate memory. 181 func minit() { 182 if atomic.Load(&exiting) != 0 { 183 exits(&emptystatus[0]) 184 } 185 // Mask all SSE floating-point exceptions 186 // when running on the 64-bit kernel. 187 setfpmasks() 188 } 189 190 // Called from dropm to undo the effect of an minit. 191 func unminit() { 192 } 193 194 var sysstat = []byte("/dev/sysstat\x00") 195 196 func getproccount() int32 { 197 var buf [2048]byte 198 fd := open(&sysstat[0], _OREAD, 0) 199 if fd < 0 { 200 return 1 201 } 202 ncpu := int32(0) 203 for { 204 n := read(fd, unsafe.Pointer(&buf), int32(len(buf))) 205 if n <= 0 { 206 break 207 } 208 for i := int32(0); i < n; i++ { 209 if buf[i] == '\n' { 210 ncpu++ 211 } 212 } 213 } 214 closefd(fd) 215 if ncpu == 0 { 216 ncpu = 1 217 } 218 return ncpu 219 } 220 221 var devswap = []byte("/dev/swap\x00") 222 var pagesize = []byte(" pagesize\n") 223 224 func getPageSize() uintptr { 225 var buf [2048]byte 226 var pos int 227 fd := open(&devswap[0], _OREAD, 0) 228 if fd < 0 { 229 // There's not much we can do if /dev/swap doesn't 230 // exist. However, nothing in the memory manager uses 231 // this on Plan 9, so it also doesn't really matter. 232 return minPhysPageSize 233 } 234 for pos < len(buf) { 235 n := read(fd, unsafe.Pointer(&buf[pos]), int32(len(buf)-pos)) 236 if n <= 0 { 237 break 238 } 239 pos += int(n) 240 } 241 closefd(fd) 242 text := buf[:pos] 243 // Find "<n> pagesize" line. 244 bol := 0 245 for i, c := range text { 246 if c == '\n' { 247 bol = i + 1 248 } 249 if bytesHasPrefix(text[i:], pagesize) { 250 // Parse number at the beginning of this line. 251 return uintptr(_atoi(text[bol:])) 252 } 253 } 254 // Again, the page size doesn't really matter, so use a fallback. 255 return minPhysPageSize 256 } 257 258 func bytesHasPrefix(s, prefix []byte) bool { 259 if len(s) < len(prefix) { 260 return false 261 } 262 for i, p := range prefix { 263 if s[i] != p { 264 return false 265 } 266 } 267 return true 268 } 269 270 var pid = []byte("#c/pid\x00") 271 272 func getpid() uint64 { 273 var b [20]byte 274 fd := open(&pid[0], 0, 0) 275 if fd >= 0 { 276 read(fd, unsafe.Pointer(&b), int32(len(b))) 277 closefd(fd) 278 } 279 c := b[:] 280 for c[0] == ' ' || c[0] == '\t' { 281 c = c[1:] 282 } 283 return uint64(_atoi(c)) 284 } 285 286 func osinit() { 287 initBloc() 288 ncpu = getproccount() 289 physPageSize = getPageSize() 290 getg().m.procid = getpid() 291 notify(unsafe.Pointer(funcPC(sigtramp))) 292 } 293 294 func crash() { 295 notify(nil) 296 *(*int)(nil) = 0 297 } 298 299 //go:nosplit 300 func getRandomData(r []byte) { 301 extendRandom(r, 0) 302 } 303 304 func goenvs() { 305 } 306 307 func initsig(preinit bool) { 308 } 309 310 //go:nosplit 311 func osyield() { 312 sleep(0) 313 } 314 315 //go:nosplit 316 func usleep(s uint32) { 317 ms := int32(s / 1000) 318 if ms == 0 { 319 ms = 1 320 } 321 sleep(ms) 322 } 323 324 //go:nosplit 325 func nanotime() int64 { 326 var scratch int64 327 ns := nsec(&scratch) 328 // TODO(aram): remove hack after I fix _nsec in the pc64 kernel. 329 if ns == 0 { 330 return scratch 331 } 332 return ns 333 } 334 335 //go:nosplit 336 func itoa(buf []byte, val uint64) []byte { 337 i := len(buf) - 1 338 for val >= 10 { 339 buf[i] = byte(val%10 + '0') 340 i-- 341 val /= 10 342 } 343 buf[i] = byte(val + '0') 344 return buf[i:] 345 } 346 347 var goexits = []byte("go: exit ") 348 var emptystatus = []byte("\x00") 349 var exiting uint32 350 351 func goexitsall(status *byte) { 352 var buf [_ERRMAX]byte 353 if !atomic.Cas(&exiting, 0, 1) { 354 return 355 } 356 getg().m.locks++ 357 n := copy(buf[:], goexits) 358 n = copy(buf[n:], gostringnocopy(status)) 359 pid := getpid() 360 for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink { 361 if mp.procid != 0 && mp.procid != pid { 362 postnote(mp.procid, buf[:]) 363 } 364 } 365 getg().m.locks-- 366 } 367 368 var procdir = []byte("/proc/") 369 var notefile = []byte("/note\x00") 370 371 func postnote(pid uint64, msg []byte) int { 372 var buf [128]byte 373 var tmp [32]byte 374 n := copy(buf[:], procdir) 375 n += copy(buf[n:], itoa(tmp[:], pid)) 376 copy(buf[n:], notefile) 377 fd := open(&buf[0], _OWRITE, 0) 378 if fd < 0 { 379 return -1 380 } 381 len := findnull(&msg[0]) 382 if write(uintptr(fd), unsafe.Pointer(&msg[0]), int32(len)) != int64(len) { 383 closefd(fd) 384 return -1 385 } 386 closefd(fd) 387 return 0 388 } 389 390 //go:nosplit 391 func exit(e int) { 392 var status []byte 393 if e == 0 { 394 status = emptystatus 395 } else { 396 // build error string 397 var tmp [32]byte 398 status = append(itoa(tmp[:len(tmp)-1], uint64(e)), 0) 399 } 400 goexitsall(&status[0]) 401 exits(&status[0]) 402 } 403 404 // May run with m.p==nil, so write barriers are not allowed. 405 //go:nowritebarrier 406 func newosproc(mp *m, stk unsafe.Pointer) { 407 if false { 408 print("newosproc mp=", mp, " ostk=", &mp, "\n") 409 } 410 pid := rfork(_RFPROC | _RFMEM | _RFNOWAIT) 411 if pid < 0 { 412 throw("newosproc: rfork failed") 413 } 414 if pid == 0 { 415 tstart_plan9(mp) 416 } 417 } 418 419 //go:nosplit 420 func semacreate(mp *m) { 421 } 422 423 //go:nosplit 424 func semasleep(ns int64) int { 425 _g_ := getg() 426 if ns >= 0 { 427 ms := timediv(ns, 1000000, nil) 428 if ms == 0 { 429 ms = 1 430 } 431 ret := plan9_tsemacquire(&_g_.m.waitsemacount, ms) 432 if ret == 1 { 433 return 0 // success 434 } 435 return -1 // timeout or interrupted 436 } 437 for plan9_semacquire(&_g_.m.waitsemacount, 1) < 0 { 438 // interrupted; try again (c.f. lock_sema.go) 439 } 440 return 0 // success 441 } 442 443 //go:nosplit 444 func semawakeup(mp *m) { 445 plan9_semrelease(&mp.waitsemacount, 1) 446 } 447 448 //go:nosplit 449 func read(fd int32, buf unsafe.Pointer, n int32) int32 { 450 return pread(fd, buf, n, -1) 451 } 452 453 //go:nosplit 454 func write(fd uintptr, buf unsafe.Pointer, n int32) int64 { 455 return int64(pwrite(int32(fd), buf, n, -1)) 456 } 457 458 func memlimit() uint64 { 459 return 0 460 } 461 462 var _badsignal = []byte("runtime: signal received on thread not created by Go.\n") 463 464 // This runs on a foreign stack, without an m or a g. No stack split. 465 //go:nosplit 466 func badsignal2() { 467 pwrite(2, unsafe.Pointer(&_badsignal[0]), int32(len(_badsignal)), -1) 468 exits(&_badsignal[0]) 469 } 470 471 func raisebadsignal(sig uint32) { 472 badsignal2() 473 } 474 475 func _atoi(b []byte) int { 476 n := 0 477 for len(b) > 0 && '0' <= b[0] && b[0] <= '9' { 478 n = n*10 + int(b[0]) - '0' 479 b = b[1:] 480 } 481 return n 482 } 483 484 func signame(sig uint32) string { 485 if sig >= uint32(len(sigtable)) { 486 return "" 487 } 488 return sigtable[sig].name 489 } 490