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