| // 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))) | 
 | } | 
 |  | 
 | //go:nosplit | 
 | 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) { | 
 | 	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 | 
 | } |