Source file src/runtime/os_plan9.go

     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  	"internal/abi"
     9  	"runtime/internal/atomic"
    10  	"unsafe"
    11  )
    12  
    13  type mOS struct {
    14  	waitsemacount uint32
    15  	notesig       *int8
    16  	errstr        *byte
    17  	ignoreHangup  bool
    18  }
    19  
    20  func closefd(fd int32) int32
    21  
    22  //go:noescape
    23  func open(name *byte, mode, perm int32) int32
    24  
    25  //go:noescape
    26  func pread(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32
    27  
    28  //go:noescape
    29  func pwrite(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32
    30  
    31  func seek(fd int32, offset int64, whence int32) int64
    32  
    33  //go:noescape
    34  func exits(msg *byte)
    35  
    36  //go:noescape
    37  func brk_(addr unsafe.Pointer) int32
    38  
    39  func sleep(ms int32) int32
    40  
    41  func rfork(flags int32) int32
    42  
    43  //go:noescape
    44  func plan9_semacquire(addr *uint32, block int32) int32
    45  
    46  //go:noescape
    47  func plan9_tsemacquire(addr *uint32, ms int32) int32
    48  
    49  //go:noescape
    50  func plan9_semrelease(addr *uint32, count int32) int32
    51  
    52  //go:noescape
    53  func notify(fn unsafe.Pointer) int32
    54  
    55  func noted(mode int32) int32
    56  
    57  //go:noescape
    58  func nsec(*int64) int64
    59  
    60  //go:noescape
    61  func sigtramp(ureg, note unsafe.Pointer)
    62  
    63  func setfpmasks()
    64  
    65  //go:noescape
    66  func tstart_plan9(newm *m)
    67  
    68  func errstr() string
    69  
    70  type _Plink uintptr
    71  
    72  //go:linkname os_sigpipe os.sigpipe
    73  func os_sigpipe() {
    74  	throw("too many writes on closed pipe")
    75  }
    76  
    77  func sigpanic() {
    78  	g := getg()
    79  	if !canpanic(g) {
    80  		throw("unexpected signal during runtime execution")
    81  	}
    82  
    83  	note := gostringnocopy((*byte)(unsafe.Pointer(g.m.notesig)))
    84  	switch g.sig {
    85  	case _SIGRFAULT, _SIGWFAULT:
    86  		i := indexNoFloat(note, "addr=")
    87  		if i >= 0 {
    88  			i += 5
    89  		} else if i = indexNoFloat(note, "va="); i >= 0 {
    90  			i += 3
    91  		} else {
    92  			panicmem()
    93  		}
    94  		addr := note[i:]
    95  		g.sigcode1 = uintptr(atolwhex(addr))
    96  		if g.sigcode1 < 0x1000 {
    97  			panicmem()
    98  		}
    99  		if g.paniconfault {
   100  			panicmemAddr(g.sigcode1)
   101  		}
   102  		print("unexpected fault address ", hex(g.sigcode1), "\n")
   103  		throw("fault")
   104  	case _SIGTRAP:
   105  		if g.paniconfault {
   106  			panicmem()
   107  		}
   108  		throw(note)
   109  	case _SIGINTDIV:
   110  		panicdivide()
   111  	case _SIGFLOAT:
   112  		panicfloat()
   113  	default:
   114  		panic(errorString(note))
   115  	}
   116  }
   117  
   118  // indexNoFloat is bytealg.IndexString but safe to use in a note
   119  // handler.
   120  func indexNoFloat(s, t string) int {
   121  	if len(t) == 0 {
   122  		return 0
   123  	}
   124  	for i := 0; i < len(s); i++ {
   125  		if s[i] == t[0] && hasPrefix(s[i:], t) {
   126  			return i
   127  		}
   128  	}
   129  	return -1
   130  }
   131  
   132  func atolwhex(p string) int64 {
   133  	for hasPrefix(p, " ") || hasPrefix(p, "\t") {
   134  		p = p[1:]
   135  	}
   136  	neg := false
   137  	if hasPrefix(p, "-") || hasPrefix(p, "+") {
   138  		neg = p[0] == '-'
   139  		p = p[1:]
   140  		for hasPrefix(p, " ") || hasPrefix(p, "\t") {
   141  			p = p[1:]
   142  		}
   143  	}
   144  	var n int64
   145  	switch {
   146  	case hasPrefix(p, "0x"), hasPrefix(p, "0X"):
   147  		p = p[2:]
   148  		for ; len(p) > 0; p = p[1:] {
   149  			if '0' <= p[0] && p[0] <= '9' {
   150  				n = n*16 + int64(p[0]-'0')
   151  			} else if 'a' <= p[0] && p[0] <= 'f' {
   152  				n = n*16 + int64(p[0]-'a'+10)
   153  			} else if 'A' <= p[0] && p[0] <= 'F' {
   154  				n = n*16 + int64(p[0]-'A'+10)
   155  			} else {
   156  				break
   157  			}
   158  		}
   159  	case hasPrefix(p, "0"):
   160  		for ; len(p) > 0 && '0' <= p[0] && p[0] <= '7'; p = p[1:] {
   161  			n = n*8 + int64(p[0]-'0')
   162  		}
   163  	default:
   164  		for ; len(p) > 0 && '0' <= p[0] && p[0] <= '9'; p = p[1:] {
   165  			n = n*10 + int64(p[0]-'0')
   166  		}
   167  	}
   168  	if neg {
   169  		n = -n
   170  	}
   171  	return n
   172  }
   173  
   174  type sigset struct{}
   175  
   176  // Called to initialize a new m (including the bootstrap m).
   177  // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   178  func mpreinit(mp *m) {
   179  	// Initialize stack and goroutine for note handling.
   180  	mp.gsignal = malg(32 * 1024)
   181  	mp.gsignal.m = mp
   182  	mp.notesig = (*int8)(mallocgc(_ERRMAX, nil, true))
   183  	// Initialize stack for handling strings from the
   184  	// errstr system call, as used in package syscall.
   185  	mp.errstr = (*byte)(mallocgc(_ERRMAX, nil, true))
   186  }
   187  
   188  func sigsave(p *sigset) {
   189  }
   190  
   191  func msigrestore(sigmask sigset) {
   192  }
   193  
   194  //go:nosplit
   195  //go:nowritebarrierrec
   196  func clearSignalHandlers() {
   197  }
   198  
   199  func sigblock(exiting bool) {
   200  }
   201  
   202  // Called to initialize a new m (including the bootstrap m).
   203  // Called on the new thread, cannot allocate memory.
   204  func minit() {
   205  	if atomic.Load(&exiting) != 0 {
   206  		exits(&emptystatus[0])
   207  	}
   208  	// Mask all SSE floating-point exceptions
   209  	// when running on the 64-bit kernel.
   210  	setfpmasks()
   211  }
   212  
   213  // Called from dropm to undo the effect of an minit.
   214  func unminit() {
   215  }
   216  
   217  // Called from exitm, but not from drop, to undo the effect of thread-owned
   218  // resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
   219  func mdestroy(mp *m) {
   220  }
   221  
   222  var sysstat = []byte("/dev/sysstat\x00")
   223  
   224  func getproccount() int32 {
   225  	var buf [2048]byte
   226  	fd := open(&sysstat[0], _OREAD, 0)
   227  	if fd < 0 {
   228  		return 1
   229  	}
   230  	ncpu := int32(0)
   231  	for {
   232  		n := read(fd, unsafe.Pointer(&buf), int32(len(buf)))
   233  		if n <= 0 {
   234  			break
   235  		}
   236  		for i := int32(0); i < n; i++ {
   237  			if buf[i] == '\n' {
   238  				ncpu++
   239  			}
   240  		}
   241  	}
   242  	closefd(fd)
   243  	if ncpu == 0 {
   244  		ncpu = 1
   245  	}
   246  	return ncpu
   247  }
   248  
   249  var devswap = []byte("/dev/swap\x00")
   250  var pagesize = []byte(" pagesize\n")
   251  
   252  func getPageSize() uintptr {
   253  	var buf [2048]byte
   254  	var pos int
   255  	fd := open(&devswap[0], _OREAD, 0)
   256  	if fd < 0 {
   257  		// There's not much we can do if /dev/swap doesn't
   258  		// exist. However, nothing in the memory manager uses
   259  		// this on Plan 9, so it also doesn't really matter.
   260  		return minPhysPageSize
   261  	}
   262  	for pos < len(buf) {
   263  		n := read(fd, unsafe.Pointer(&buf[pos]), int32(len(buf)-pos))
   264  		if n <= 0 {
   265  			break
   266  		}
   267  		pos += int(n)
   268  	}
   269  	closefd(fd)
   270  	text := buf[:pos]
   271  	// Find "<n> pagesize" line.
   272  	bol := 0
   273  	for i, c := range text {
   274  		if c == '\n' {
   275  			bol = i + 1
   276  		}
   277  		if bytesHasPrefix(text[i:], pagesize) {
   278  			// Parse number at the beginning of this line.
   279  			return uintptr(_atoi(text[bol:]))
   280  		}
   281  	}
   282  	// Again, the page size doesn't really matter, so use a fallback.
   283  	return minPhysPageSize
   284  }
   285  
   286  func bytesHasPrefix(s, prefix []byte) bool {
   287  	if len(s) < len(prefix) {
   288  		return false
   289  	}
   290  	for i, p := range prefix {
   291  		if s[i] != p {
   292  			return false
   293  		}
   294  	}
   295  	return true
   296  }
   297  
   298  var pid = []byte("#c/pid\x00")
   299  
   300  func getpid() uint64 {
   301  	var b [20]byte
   302  	fd := open(&pid[0], 0, 0)
   303  	if fd >= 0 {
   304  		read(fd, unsafe.Pointer(&b), int32(len(b)))
   305  		closefd(fd)
   306  	}
   307  	c := b[:]
   308  	for c[0] == ' ' || c[0] == '\t' {
   309  		c = c[1:]
   310  	}
   311  	return uint64(_atoi(c))
   312  }
   313  
   314  func osinit() {
   315  	initBloc()
   316  	ncpu = getproccount()
   317  	physPageSize = getPageSize()
   318  	getg().m.procid = getpid()
   319  }
   320  
   321  //go:nosplit
   322  func crash() {
   323  	notify(nil)
   324  	*(*int)(nil) = 0
   325  }
   326  
   327  //go:nosplit
   328  func getRandomData(r []byte) {
   329  	// inspired by wyrand see hash32.go for detail
   330  	t := nanotime()
   331  	v := getg().m.procid ^ uint64(t)
   332  
   333  	for len(r) > 0 {
   334  		v ^= 0xa0761d6478bd642f
   335  		v *= 0xe7037ed1a0b428db
   336  		size := 8
   337  		if len(r) < 8 {
   338  			size = len(r)
   339  		}
   340  		for i := 0; i < size; i++ {
   341  			r[i] = byte(v >> (8 * i))
   342  		}
   343  		r = r[size:]
   344  		v = v>>32 | v<<32
   345  	}
   346  }
   347  
   348  func initsig(preinit bool) {
   349  	if !preinit {
   350  		notify(unsafe.Pointer(abi.FuncPCABI0(sigtramp)))
   351  	}
   352  }
   353  
   354  //go:nosplit
   355  func osyield() {
   356  	sleep(0)
   357  }
   358  
   359  //go:nosplit
   360  func osyield_no_g() {
   361  	osyield()
   362  }
   363  
   364  //go:nosplit
   365  func usleep(µs uint32) {
   366  	ms := int32(µs / 1000)
   367  	if ms == 0 {
   368  		ms = 1
   369  	}
   370  	sleep(ms)
   371  }
   372  
   373  //go:nosplit
   374  func usleep_no_g(usec uint32) {
   375  	usleep(usec)
   376  }
   377  
   378  //go:nosplit
   379  func nanotime1() int64 {
   380  	var scratch int64
   381  	ns := nsec(&scratch)
   382  	// TODO(aram): remove hack after I fix _nsec in the pc64 kernel.
   383  	if ns == 0 {
   384  		return scratch
   385  	}
   386  	return ns
   387  }
   388  
   389  var goexits = []byte("go: exit ")
   390  var emptystatus = []byte("\x00")
   391  var exiting uint32
   392  
   393  func goexitsall(status *byte) {
   394  	var buf [_ERRMAX]byte
   395  	if !atomic.Cas(&exiting, 0, 1) {
   396  		return
   397  	}
   398  	getg().m.locks++
   399  	n := copy(buf[:], goexits)
   400  	n = copy(buf[n:], gostringnocopy(status))
   401  	pid := getpid()
   402  	for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink {
   403  		if mp.procid != 0 && mp.procid != pid {
   404  			postnote(mp.procid, buf[:])
   405  		}
   406  	}
   407  	getg().m.locks--
   408  }
   409  
   410  var procdir = []byte("/proc/")
   411  var notefile = []byte("/note\x00")
   412  
   413  func postnote(pid uint64, msg []byte) int {
   414  	var buf [128]byte
   415  	var tmp [32]byte
   416  	n := copy(buf[:], procdir)
   417  	n += copy(buf[n:], itoa(tmp[:], pid))
   418  	copy(buf[n:], notefile)
   419  	fd := open(&buf[0], _OWRITE, 0)
   420  	if fd < 0 {
   421  		return -1
   422  	}
   423  	len := findnull(&msg[0])
   424  	if write1(uintptr(fd), unsafe.Pointer(&msg[0]), int32(len)) != int32(len) {
   425  		closefd(fd)
   426  		return -1
   427  	}
   428  	closefd(fd)
   429  	return 0
   430  }
   431  
   432  //go:nosplit
   433  func exit(e int32) {
   434  	var status []byte
   435  	if e == 0 {
   436  		status = emptystatus
   437  	} else {
   438  		// build error string
   439  		var tmp [32]byte
   440  		status = append(itoa(tmp[:len(tmp)-1], uint64(e)), 0)
   441  	}
   442  	goexitsall(&status[0])
   443  	exits(&status[0])
   444  }
   445  
   446  // May run with m.p==nil, so write barriers are not allowed.
   447  //go:nowritebarrier
   448  func newosproc(mp *m) {
   449  	if false {
   450  		print("newosproc mp=", mp, " ostk=", &mp, "\n")
   451  	}
   452  	pid := rfork(_RFPROC | _RFMEM | _RFNOWAIT)
   453  	if pid < 0 {
   454  		throw("newosproc: rfork failed")
   455  	}
   456  	if pid == 0 {
   457  		tstart_plan9(mp)
   458  	}
   459  }
   460  
   461  func exitThread(wait *uint32) {
   462  	// We should never reach exitThread on Plan 9 because we let
   463  	// the OS clean up threads.
   464  	throw("exitThread")
   465  }
   466  
   467  //go:nosplit
   468  func semacreate(mp *m) {
   469  }
   470  
   471  //go:nosplit
   472  func semasleep(ns int64) int {
   473  	_g_ := getg()
   474  	if ns >= 0 {
   475  		ms := timediv(ns, 1000000, nil)
   476  		if ms == 0 {
   477  			ms = 1
   478  		}
   479  		ret := plan9_tsemacquire(&_g_.m.waitsemacount, ms)
   480  		if ret == 1 {
   481  			return 0 // success
   482  		}
   483  		return -1 // timeout or interrupted
   484  	}
   485  	for plan9_semacquire(&_g_.m.waitsemacount, 1) < 0 {
   486  		// interrupted; try again (c.f. lock_sema.go)
   487  	}
   488  	return 0 // success
   489  }
   490  
   491  //go:nosplit
   492  func semawakeup(mp *m) {
   493  	plan9_semrelease(&mp.waitsemacount, 1)
   494  }
   495  
   496  //go:nosplit
   497  func read(fd int32, buf unsafe.Pointer, n int32) int32 {
   498  	return pread(fd, buf, n, -1)
   499  }
   500  
   501  //go:nosplit
   502  func write1(fd uintptr, buf unsafe.Pointer, n int32) int32 {
   503  	return pwrite(int32(fd), buf, n, -1)
   504  }
   505  
   506  var _badsignal = []byte("runtime: signal received on thread not created by Go.\n")
   507  
   508  // This runs on a foreign stack, without an m or a g. No stack split.
   509  //go:nosplit
   510  func badsignal2() {
   511  	pwrite(2, unsafe.Pointer(&_badsignal[0]), int32(len(_badsignal)), -1)
   512  	exits(&_badsignal[0])
   513  }
   514  
   515  func raisebadsignal(sig uint32) {
   516  	badsignal2()
   517  }
   518  
   519  func _atoi(b []byte) int {
   520  	n := 0
   521  	for len(b) > 0 && '0' <= b[0] && b[0] <= '9' {
   522  		n = n*10 + int(b[0]) - '0'
   523  		b = b[1:]
   524  	}
   525  	return n
   526  }
   527  
   528  func signame(sig uint32) string {
   529  	if sig >= uint32(len(sigtable)) {
   530  		return ""
   531  	}
   532  	return sigtable[sig].name
   533  }
   534  
   535  const preemptMSupported = false
   536  
   537  func preemptM(mp *m) {
   538  	// Not currently supported.
   539  	//
   540  	// TODO: Use a note like we use signals on POSIX OSes
   541  }
   542  

View as plain text