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  }