Black Lives Matter. Support the Equal Justice Initiative.

Source file src/runtime/os_plan9.go

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

View as plain text