github.com/hlts2/go@v0.0.0-20170904000733-812b34efaed8/src/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 := 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 //go:nosplit 177 //go:nowritebarrierrec 178 func clearSignalHandlers() { 179 } 180 181 func sigblock() { 182 } 183 184 // Called to initialize a new m (including the bootstrap m). 185 // Called on the new thread, cannot allocate memory. 186 func minit() { 187 if atomic.Load(&exiting) != 0 { 188 exits(&emptystatus[0]) 189 } 190 // Mask all SSE floating-point exceptions 191 // when running on the 64-bit kernel. 192 setfpmasks() 193 } 194 195 // Called from dropm to undo the effect of an minit. 196 func unminit() { 197 } 198 199 var sysstat = []byte("/dev/sysstat\x00") 200 201 func getproccount() int32 { 202 var buf [2048]byte 203 fd := open(&sysstat[0], _OREAD, 0) 204 if fd < 0 { 205 return 1 206 } 207 ncpu := int32(0) 208 for { 209 n := read(fd, unsafe.Pointer(&buf), int32(len(buf))) 210 if n <= 0 { 211 break 212 } 213 for i := int32(0); i < n; i++ { 214 if buf[i] == '\n' { 215 ncpu++ 216 } 217 } 218 } 219 closefd(fd) 220 if ncpu == 0 { 221 ncpu = 1 222 } 223 return ncpu 224 } 225 226 var devswap = []byte("/dev/swap\x00") 227 var pagesize = []byte(" pagesize\n") 228 229 func getPageSize() uintptr { 230 var buf [2048]byte 231 var pos int 232 fd := open(&devswap[0], _OREAD, 0) 233 if fd < 0 { 234 // There's not much we can do if /dev/swap doesn't 235 // exist. However, nothing in the memory manager uses 236 // this on Plan 9, so it also doesn't really matter. 237 return minPhysPageSize 238 } 239 for pos < len(buf) { 240 n := read(fd, unsafe.Pointer(&buf[pos]), int32(len(buf)-pos)) 241 if n <= 0 { 242 break 243 } 244 pos += int(n) 245 } 246 closefd(fd) 247 text := buf[:pos] 248 // Find "<n> pagesize" line. 249 bol := 0 250 for i, c := range text { 251 if c == '\n' { 252 bol = i + 1 253 } 254 if bytesHasPrefix(text[i:], pagesize) { 255 // Parse number at the beginning of this line. 256 return uintptr(_atoi(text[bol:])) 257 } 258 } 259 // Again, the page size doesn't really matter, so use a fallback. 260 return minPhysPageSize 261 } 262 263 func bytesHasPrefix(s, prefix []byte) bool { 264 if len(s) < len(prefix) { 265 return false 266 } 267 for i, p := range prefix { 268 if s[i] != p { 269 return false 270 } 271 } 272 return true 273 } 274 275 var pid = []byte("#c/pid\x00") 276 277 func getpid() uint64 { 278 var b [20]byte 279 fd := open(&pid[0], 0, 0) 280 if fd >= 0 { 281 read(fd, unsafe.Pointer(&b), int32(len(b))) 282 closefd(fd) 283 } 284 c := b[:] 285 for c[0] == ' ' || c[0] == '\t' { 286 c = c[1:] 287 } 288 return uint64(_atoi(c)) 289 } 290 291 func osinit() { 292 initBloc() 293 ncpu = getproccount() 294 physPageSize = getPageSize() 295 getg().m.procid = getpid() 296 notify(unsafe.Pointer(funcPC(sigtramp))) 297 } 298 299 func crash() { 300 notify(nil) 301 *(*int)(nil) = 0 302 } 303 304 //go:nosplit 305 func getRandomData(r []byte) { 306 extendRandom(r, 0) 307 } 308 309 func goenvs() { 310 } 311 312 func initsig(preinit bool) { 313 } 314 315 //go:nosplit 316 func osyield() { 317 sleep(0) 318 } 319 320 //go:nosplit 321 func usleep(µs uint32) { 322 ms := int32(µs / 1000) 323 if ms == 0 { 324 ms = 1 325 } 326 sleep(ms) 327 } 328 329 //go:nosplit 330 func nanotime() int64 { 331 var scratch int64 332 ns := nsec(&scratch) 333 // TODO(aram): remove hack after I fix _nsec in the pc64 kernel. 334 if ns == 0 { 335 return scratch 336 } 337 return ns 338 } 339 340 //go:nosplit 341 func itoa(buf []byte, val uint64) []byte { 342 i := len(buf) - 1 343 for val >= 10 { 344 buf[i] = byte(val%10 + '0') 345 i-- 346 val /= 10 347 } 348 buf[i] = byte(val + '0') 349 return buf[i:] 350 } 351 352 var goexits = []byte("go: exit ") 353 var emptystatus = []byte("\x00") 354 var exiting uint32 355 356 func goexitsall(status *byte) { 357 var buf [_ERRMAX]byte 358 if !atomic.Cas(&exiting, 0, 1) { 359 return 360 } 361 getg().m.locks++ 362 n := copy(buf[:], goexits) 363 n = copy(buf[n:], gostringnocopy(status)) 364 pid := getpid() 365 for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink { 366 if mp.procid != 0 && mp.procid != pid { 367 postnote(mp.procid, buf[:]) 368 } 369 } 370 getg().m.locks-- 371 } 372 373 var procdir = []byte("/proc/") 374 var notefile = []byte("/note\x00") 375 376 func postnote(pid uint64, msg []byte) int { 377 var buf [128]byte 378 var tmp [32]byte 379 n := copy(buf[:], procdir) 380 n += copy(buf[n:], itoa(tmp[:], pid)) 381 copy(buf[n:], notefile) 382 fd := open(&buf[0], _OWRITE, 0) 383 if fd < 0 { 384 return -1 385 } 386 len := findnull(&msg[0]) 387 if write(uintptr(fd), unsafe.Pointer(&msg[0]), int32(len)) != int64(len) { 388 closefd(fd) 389 return -1 390 } 391 closefd(fd) 392 return 0 393 } 394 395 //go:nosplit 396 func exit(e int) { 397 var status []byte 398 if e == 0 { 399 status = emptystatus 400 } else { 401 // build error string 402 var tmp [32]byte 403 status = append(itoa(tmp[:len(tmp)-1], uint64(e)), 0) 404 } 405 goexitsall(&status[0]) 406 exits(&status[0]) 407 } 408 409 // May run with m.p==nil, so write barriers are not allowed. 410 //go:nowritebarrier 411 func newosproc(mp *m, stk unsafe.Pointer) { 412 if false { 413 print("newosproc mp=", mp, " ostk=", &mp, "\n") 414 } 415 pid := rfork(_RFPROC | _RFMEM | _RFNOWAIT) 416 if pid < 0 { 417 throw("newosproc: rfork failed") 418 } 419 if pid == 0 { 420 tstart_plan9(mp) 421 } 422 } 423 424 //go:nosplit 425 func semacreate(mp *m) { 426 } 427 428 //go:nosplit 429 func semasleep(ns int64) int { 430 _g_ := getg() 431 if ns >= 0 { 432 ms := timediv(ns, 1000000, nil) 433 if ms == 0 { 434 ms = 1 435 } 436 ret := plan9_tsemacquire(&_g_.m.waitsemacount, ms) 437 if ret == 1 { 438 return 0 // success 439 } 440 return -1 // timeout or interrupted 441 } 442 for plan9_semacquire(&_g_.m.waitsemacount, 1) < 0 { 443 // interrupted; try again (c.f. lock_sema.go) 444 } 445 return 0 // success 446 } 447 448 //go:nosplit 449 func semawakeup(mp *m) { 450 plan9_semrelease(&mp.waitsemacount, 1) 451 } 452 453 //go:nosplit 454 func read(fd int32, buf unsafe.Pointer, n int32) int32 { 455 return pread(fd, buf, n, -1) 456 } 457 458 //go:nosplit 459 func write(fd uintptr, buf unsafe.Pointer, n int32) int64 { 460 return int64(pwrite(int32(fd), buf, n, -1)) 461 } 462 463 func memlimit() uint64 { 464 return 0 465 } 466 467 var _badsignal = []byte("runtime: signal received on thread not created by Go.\n") 468 469 // This runs on a foreign stack, without an m or a g. No stack split. 470 //go:nosplit 471 func badsignal2() { 472 pwrite(2, unsafe.Pointer(&_badsignal[0]), int32(len(_badsignal)), -1) 473 exits(&_badsignal[0]) 474 } 475 476 func raisebadsignal(sig uint32) { 477 badsignal2() 478 } 479 480 func _atoi(b []byte) int { 481 n := 0 482 for len(b) > 0 && '0' <= b[0] && b[0] <= '9' { 483 n = n*10 + int(b[0]) - '0' 484 b = b[1:] 485 } 486 return n 487 } 488 489 func signame(sig uint32) string { 490 if sig >= uint32(len(sigtable)) { 491 return "" 492 } 493 return sigtable[sig].name 494 }