mirror of
https://github.com/golang/go
synced 2024-11-19 13:04:45 -07:00
8693b4f095
Change-Id: Id057dcc85d64e5c670710fbab6cacd4b906cf594 Reviewed-on: https://go-review.googlesource.com/93655 Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
497 lines
9.4 KiB
Go
497 lines
9.4 KiB
Go
// Copyright 2010 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package runtime
|
|
|
|
import (
|
|
"runtime/internal/atomic"
|
|
"unsafe"
|
|
)
|
|
|
|
type mOS struct {
|
|
waitsemacount uint32
|
|
notesig *int8
|
|
errstr *byte
|
|
ignoreHangup bool
|
|
}
|
|
|
|
func closefd(fd int32) int32
|
|
|
|
//go:noescape
|
|
func open(name *byte, mode, perm int32) int32
|
|
|
|
//go:noescape
|
|
func pread(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32
|
|
|
|
//go:noescape
|
|
func pwrite(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32
|
|
|
|
func seek(fd int32, offset int64, whence int32) int64
|
|
|
|
//go:noescape
|
|
func exits(msg *byte)
|
|
|
|
//go:noescape
|
|
func brk_(addr unsafe.Pointer) int32
|
|
|
|
func sleep(ms int32) int32
|
|
|
|
func rfork(flags int32) int32
|
|
|
|
//go:noescape
|
|
func plan9_semacquire(addr *uint32, block int32) int32
|
|
|
|
//go:noescape
|
|
func plan9_tsemacquire(addr *uint32, ms int32) int32
|
|
|
|
//go:noescape
|
|
func plan9_semrelease(addr *uint32, count int32) int32
|
|
|
|
//go:noescape
|
|
func notify(fn unsafe.Pointer) int32
|
|
|
|
func noted(mode int32) int32
|
|
|
|
//go:noescape
|
|
func nsec(*int64) int64
|
|
|
|
//go:noescape
|
|
func sigtramp(ureg, note unsafe.Pointer)
|
|
|
|
func setfpmasks()
|
|
|
|
//go:noescape
|
|
func tstart_plan9(newm *m)
|
|
|
|
func errstr() string
|
|
|
|
type _Plink uintptr
|
|
|
|
//go:linkname os_sigpipe os.sigpipe
|
|
func os_sigpipe() {
|
|
throw("too many writes on closed pipe")
|
|
}
|
|
|
|
func sigpanic() {
|
|
g := getg()
|
|
if !canpanic(g) {
|
|
throw("unexpected signal during runtime execution")
|
|
}
|
|
|
|
note := gostringnocopy((*byte)(unsafe.Pointer(g.m.notesig)))
|
|
switch g.sig {
|
|
case _SIGRFAULT, _SIGWFAULT:
|
|
i := index(note, "addr=")
|
|
if i >= 0 {
|
|
i += 5
|
|
} else if i = index(note, "va="); i >= 0 {
|
|
i += 3
|
|
} else {
|
|
panicmem()
|
|
}
|
|
addr := note[i:]
|
|
g.sigcode1 = uintptr(atolwhex(addr))
|
|
if g.sigcode1 < 0x1000 || g.paniconfault {
|
|
panicmem()
|
|
}
|
|
print("unexpected fault address ", hex(g.sigcode1), "\n")
|
|
throw("fault")
|
|
case _SIGTRAP:
|
|
if g.paniconfault {
|
|
panicmem()
|
|
}
|
|
throw(note)
|
|
case _SIGINTDIV:
|
|
panicdivide()
|
|
case _SIGFLOAT:
|
|
panicfloat()
|
|
default:
|
|
panic(errorString(note))
|
|
}
|
|
}
|
|
|
|
func atolwhex(p string) int64 {
|
|
for hasprefix(p, " ") || hasprefix(p, "\t") {
|
|
p = p[1:]
|
|
}
|
|
neg := false
|
|
if hasprefix(p, "-") || hasprefix(p, "+") {
|
|
neg = p[0] == '-'
|
|
p = p[1:]
|
|
for hasprefix(p, " ") || hasprefix(p, "\t") {
|
|
p = p[1:]
|
|
}
|
|
}
|
|
var n int64
|
|
switch {
|
|
case hasprefix(p, "0x"), hasprefix(p, "0X"):
|
|
p = p[2:]
|
|
for ; len(p) > 0; p = p[1:] {
|
|
if '0' <= p[0] && p[0] <= '9' {
|
|
n = n*16 + int64(p[0]-'0')
|
|
} else if 'a' <= p[0] && p[0] <= 'f' {
|
|
n = n*16 + int64(p[0]-'a'+10)
|
|
} else if 'A' <= p[0] && p[0] <= 'F' {
|
|
n = n*16 + int64(p[0]-'A'+10)
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
case hasprefix(p, "0"):
|
|
for ; len(p) > 0 && '0' <= p[0] && p[0] <= '7'; p = p[1:] {
|
|
n = n*8 + int64(p[0]-'0')
|
|
}
|
|
default:
|
|
for ; len(p) > 0 && '0' <= p[0] && p[0] <= '9'; p = p[1:] {
|
|
n = n*10 + int64(p[0]-'0')
|
|
}
|
|
}
|
|
if neg {
|
|
n = -n
|
|
}
|
|
return n
|
|
}
|
|
|
|
type sigset struct{}
|
|
|
|
// Called to initialize a new m (including the bootstrap m).
|
|
// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
|
|
func mpreinit(mp *m) {
|
|
// Initialize stack and goroutine for note handling.
|
|
mp.gsignal = malg(32 * 1024)
|
|
mp.gsignal.m = mp
|
|
mp.notesig = (*int8)(mallocgc(_ERRMAX, nil, true))
|
|
// Initialize stack for handling strings from the
|
|
// errstr system call, as used in package syscall.
|
|
mp.errstr = (*byte)(mallocgc(_ERRMAX, nil, true))
|
|
}
|
|
|
|
func msigsave(mp *m) {
|
|
}
|
|
|
|
func msigrestore(sigmask sigset) {
|
|
}
|
|
|
|
//go:nosplit
|
|
//go:nowritebarrierrec
|
|
func clearSignalHandlers() {
|
|
}
|
|
|
|
func sigblock() {
|
|
}
|
|
|
|
// Called to initialize a new m (including the bootstrap m).
|
|
// Called on the new thread, cannot allocate memory.
|
|
func minit() {
|
|
if atomic.Load(&exiting) != 0 {
|
|
exits(&emptystatus[0])
|
|
}
|
|
// Mask all SSE floating-point exceptions
|
|
// when running on the 64-bit kernel.
|
|
setfpmasks()
|
|
}
|
|
|
|
// Called from dropm to undo the effect of an minit.
|
|
func unminit() {
|
|
}
|
|
|
|
var sysstat = []byte("/dev/sysstat\x00")
|
|
|
|
func getproccount() int32 {
|
|
var buf [2048]byte
|
|
fd := open(&sysstat[0], _OREAD, 0)
|
|
if fd < 0 {
|
|
return 1
|
|
}
|
|
ncpu := int32(0)
|
|
for {
|
|
n := read(fd, unsafe.Pointer(&buf), int32(len(buf)))
|
|
if n <= 0 {
|
|
break
|
|
}
|
|
for i := int32(0); i < n; i++ {
|
|
if buf[i] == '\n' {
|
|
ncpu++
|
|
}
|
|
}
|
|
}
|
|
closefd(fd)
|
|
if ncpu == 0 {
|
|
ncpu = 1
|
|
}
|
|
return ncpu
|
|
}
|
|
|
|
var devswap = []byte("/dev/swap\x00")
|
|
var pagesize = []byte(" pagesize\n")
|
|
|
|
func getPageSize() uintptr {
|
|
var buf [2048]byte
|
|
var pos int
|
|
fd := open(&devswap[0], _OREAD, 0)
|
|
if fd < 0 {
|
|
// There's not much we can do if /dev/swap doesn't
|
|
// exist. However, nothing in the memory manager uses
|
|
// this on Plan 9, so it also doesn't really matter.
|
|
return minPhysPageSize
|
|
}
|
|
for pos < len(buf) {
|
|
n := read(fd, unsafe.Pointer(&buf[pos]), int32(len(buf)-pos))
|
|
if n <= 0 {
|
|
break
|
|
}
|
|
pos += int(n)
|
|
}
|
|
closefd(fd)
|
|
text := buf[:pos]
|
|
// Find "<n> pagesize" line.
|
|
bol := 0
|
|
for i, c := range text {
|
|
if c == '\n' {
|
|
bol = i + 1
|
|
}
|
|
if bytesHasPrefix(text[i:], pagesize) {
|
|
// Parse number at the beginning of this line.
|
|
return uintptr(_atoi(text[bol:]))
|
|
}
|
|
}
|
|
// Again, the page size doesn't really matter, so use a fallback.
|
|
return minPhysPageSize
|
|
}
|
|
|
|
func bytesHasPrefix(s, prefix []byte) bool {
|
|
if len(s) < len(prefix) {
|
|
return false
|
|
}
|
|
for i, p := range prefix {
|
|
if s[i] != p {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
var pid = []byte("#c/pid\x00")
|
|
|
|
func getpid() uint64 {
|
|
var b [20]byte
|
|
fd := open(&pid[0], 0, 0)
|
|
if fd >= 0 {
|
|
read(fd, unsafe.Pointer(&b), int32(len(b)))
|
|
closefd(fd)
|
|
}
|
|
c := b[:]
|
|
for c[0] == ' ' || c[0] == '\t' {
|
|
c = c[1:]
|
|
}
|
|
return uint64(_atoi(c))
|
|
}
|
|
|
|
func osinit() {
|
|
initBloc()
|
|
ncpu = getproccount()
|
|
physPageSize = getPageSize()
|
|
getg().m.procid = getpid()
|
|
notify(unsafe.Pointer(funcPC(sigtramp)))
|
|
}
|
|
|
|
func crash() {
|
|
notify(nil)
|
|
*(*int)(nil) = 0
|
|
}
|
|
|
|
//go:nosplit
|
|
func getRandomData(r []byte) {
|
|
extendRandom(r, 0)
|
|
}
|
|
|
|
func goenvs() {
|
|
}
|
|
|
|
func initsig(preinit bool) {
|
|
}
|
|
|
|
//go:nosplit
|
|
func osyield() {
|
|
sleep(0)
|
|
}
|
|
|
|
//go:nosplit
|
|
func usleep(µs uint32) {
|
|
ms := int32(µs / 1000)
|
|
if ms == 0 {
|
|
ms = 1
|
|
}
|
|
sleep(ms)
|
|
}
|
|
|
|
//go:nosplit
|
|
func nanotime() int64 {
|
|
var scratch int64
|
|
ns := nsec(&scratch)
|
|
// TODO(aram): remove hack after I fix _nsec in the pc64 kernel.
|
|
if ns == 0 {
|
|
return scratch
|
|
}
|
|
return ns
|
|
}
|
|
|
|
//go:nosplit
|
|
func itoa(buf []byte, val uint64) []byte {
|
|
i := len(buf) - 1
|
|
for val >= 10 {
|
|
buf[i] = byte(val%10 + '0')
|
|
i--
|
|
val /= 10
|
|
}
|
|
buf[i] = byte(val + '0')
|
|
return buf[i:]
|
|
}
|
|
|
|
var goexits = []byte("go: exit ")
|
|
var emptystatus = []byte("\x00")
|
|
var exiting uint32
|
|
|
|
func goexitsall(status *byte) {
|
|
var buf [_ERRMAX]byte
|
|
if !atomic.Cas(&exiting, 0, 1) {
|
|
return
|
|
}
|
|
getg().m.locks++
|
|
n := copy(buf[:], goexits)
|
|
n = copy(buf[n:], gostringnocopy(status))
|
|
pid := getpid()
|
|
for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink {
|
|
if mp.procid != 0 && mp.procid != pid {
|
|
postnote(mp.procid, buf[:])
|
|
}
|
|
}
|
|
getg().m.locks--
|
|
}
|
|
|
|
var procdir = []byte("/proc/")
|
|
var notefile = []byte("/note\x00")
|
|
|
|
func postnote(pid uint64, msg []byte) int {
|
|
var buf [128]byte
|
|
var tmp [32]byte
|
|
n := copy(buf[:], procdir)
|
|
n += copy(buf[n:], itoa(tmp[:], pid))
|
|
copy(buf[n:], notefile)
|
|
fd := open(&buf[0], _OWRITE, 0)
|
|
if fd < 0 {
|
|
return -1
|
|
}
|
|
len := findnull(&msg[0])
|
|
if write(uintptr(fd), unsafe.Pointer(&msg[0]), int32(len)) != int64(len) {
|
|
closefd(fd)
|
|
return -1
|
|
}
|
|
closefd(fd)
|
|
return 0
|
|
}
|
|
|
|
//go:nosplit
|
|
func exit(e int32) {
|
|
var status []byte
|
|
if e == 0 {
|
|
status = emptystatus
|
|
} else {
|
|
// build error string
|
|
var tmp [32]byte
|
|
status = append(itoa(tmp[:len(tmp)-1], uint64(e)), 0)
|
|
}
|
|
goexitsall(&status[0])
|
|
exits(&status[0])
|
|
}
|
|
|
|
// May run with m.p==nil, so write barriers are not allowed.
|
|
//go:nowritebarrier
|
|
func newosproc(mp *m, stk unsafe.Pointer) {
|
|
if false {
|
|
print("newosproc mp=", mp, " ostk=", &mp, "\n")
|
|
}
|
|
pid := rfork(_RFPROC | _RFMEM | _RFNOWAIT)
|
|
if pid < 0 {
|
|
throw("newosproc: rfork failed")
|
|
}
|
|
if pid == 0 {
|
|
tstart_plan9(mp)
|
|
}
|
|
}
|
|
|
|
func exitThread(wait *uint32) {
|
|
// We should never reach exitThread on Plan 9 because we let
|
|
// the OS clean up threads.
|
|
throw("exitThread")
|
|
}
|
|
|
|
//go:nosplit
|
|
func semacreate(mp *m) {
|
|
}
|
|
|
|
//go:nosplit
|
|
func semasleep(ns int64) int {
|
|
_g_ := getg()
|
|
if ns >= 0 {
|
|
ms := timediv(ns, 1000000, nil)
|
|
if ms == 0 {
|
|
ms = 1
|
|
}
|
|
ret := plan9_tsemacquire(&_g_.m.waitsemacount, ms)
|
|
if ret == 1 {
|
|
return 0 // success
|
|
}
|
|
return -1 // timeout or interrupted
|
|
}
|
|
for plan9_semacquire(&_g_.m.waitsemacount, 1) < 0 {
|
|
// interrupted; try again (c.f. lock_sema.go)
|
|
}
|
|
return 0 // success
|
|
}
|
|
|
|
//go:nosplit
|
|
func semawakeup(mp *m) {
|
|
plan9_semrelease(&mp.waitsemacount, 1)
|
|
}
|
|
|
|
//go:nosplit
|
|
func read(fd int32, buf unsafe.Pointer, n int32) int32 {
|
|
return pread(fd, buf, n, -1)
|
|
}
|
|
|
|
//go:nosplit
|
|
func write(fd uintptr, buf unsafe.Pointer, n int32) int64 {
|
|
return int64(pwrite(int32(fd), buf, n, -1))
|
|
}
|
|
|
|
var _badsignal = []byte("runtime: signal received on thread not created by Go.\n")
|
|
|
|
// This runs on a foreign stack, without an m or a g. No stack split.
|
|
//go:nosplit
|
|
func badsignal2() {
|
|
pwrite(2, unsafe.Pointer(&_badsignal[0]), int32(len(_badsignal)), -1)
|
|
exits(&_badsignal[0])
|
|
}
|
|
|
|
func raisebadsignal(sig uint32) {
|
|
badsignal2()
|
|
}
|
|
|
|
func _atoi(b []byte) int {
|
|
n := 0
|
|
for len(b) > 0 && '0' <= b[0] && b[0] <= '9' {
|
|
n = n*10 + int(b[0]) - '0'
|
|
b = b[1:]
|
|
}
|
|
return n
|
|
}
|
|
|
|
func signame(sig uint32) string {
|
|
if sig >= uint32(len(sigtable)) {
|
|
return ""
|
|
}
|
|
return sigtable[sig].name
|
|
}
|