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  }