Home | History | Annotate | Download | only in runtime
      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