github.com/sanprasirt/go@v0.0.0-20170607001320-a027466e4b6d/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  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  }