github.com/rafaeltorres324/go/src@v0.0.0-20210519164414-9fdf653a9838/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 := 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  	extendRandom(r, 0)
   329  }
   330  
   331  func initsig(preinit bool) {
   332  	if !preinit {
   333  		notify(unsafe.Pointer(funcPC(sigtramp)))
   334  	}
   335  }
   336  
   337  //go:nosplit
   338  func osyield() {
   339  	sleep(0)
   340  }
   341  
   342  //go:nosplit
   343  func usleep(µs uint32) {
   344  	ms := int32(µs / 1000)
   345  	if ms == 0 {
   346  		ms = 1
   347  	}
   348  	sleep(ms)
   349  }
   350  
   351  //go:nosplit
   352  func nanotime1() int64 {
   353  	var scratch int64
   354  	ns := nsec(&scratch)
   355  	// TODO(aram): remove hack after I fix _nsec in the pc64 kernel.
   356  	if ns == 0 {
   357  		return scratch
   358  	}
   359  	return ns
   360  }
   361  
   362  var goexits = []byte("go: exit ")
   363  var emptystatus = []byte("\x00")
   364  var exiting uint32
   365  
   366  func goexitsall(status *byte) {
   367  	var buf [_ERRMAX]byte
   368  	if !atomic.Cas(&exiting, 0, 1) {
   369  		return
   370  	}
   371  	getg().m.locks++
   372  	n := copy(buf[:], goexits)
   373  	n = copy(buf[n:], gostringnocopy(status))
   374  	pid := getpid()
   375  	for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink {
   376  		if mp.procid != 0 && mp.procid != pid {
   377  			postnote(mp.procid, buf[:])
   378  		}
   379  	}
   380  	getg().m.locks--
   381  }
   382  
   383  var procdir = []byte("/proc/")
   384  var notefile = []byte("/note\x00")
   385  
   386  func postnote(pid uint64, msg []byte) int {
   387  	var buf [128]byte
   388  	var tmp [32]byte
   389  	n := copy(buf[:], procdir)
   390  	n += copy(buf[n:], itoa(tmp[:], pid))
   391  	copy(buf[n:], notefile)
   392  	fd := open(&buf[0], _OWRITE, 0)
   393  	if fd < 0 {
   394  		return -1
   395  	}
   396  	len := findnull(&msg[0])
   397  	if write1(uintptr(fd), unsafe.Pointer(&msg[0]), int32(len)) != int32(len) {
   398  		closefd(fd)
   399  		return -1
   400  	}
   401  	closefd(fd)
   402  	return 0
   403  }
   404  
   405  //go:nosplit
   406  func exit(e int32) {
   407  	var status []byte
   408  	if e == 0 {
   409  		status = emptystatus
   410  	} else {
   411  		// build error string
   412  		var tmp [32]byte
   413  		status = append(itoa(tmp[:len(tmp)-1], uint64(e)), 0)
   414  	}
   415  	goexitsall(&status[0])
   416  	exits(&status[0])
   417  }
   418  
   419  // May run with m.p==nil, so write barriers are not allowed.
   420  //go:nowritebarrier
   421  func newosproc(mp *m) {
   422  	if false {
   423  		print("newosproc mp=", mp, " ostk=", &mp, "\n")
   424  	}
   425  	pid := rfork(_RFPROC | _RFMEM | _RFNOWAIT)
   426  	if pid < 0 {
   427  		throw("newosproc: rfork failed")
   428  	}
   429  	if pid == 0 {
   430  		tstart_plan9(mp)
   431  	}
   432  }
   433  
   434  func exitThread(wait *uint32) {
   435  	// We should never reach exitThread on Plan 9 because we let
   436  	// the OS clean up threads.
   437  	throw("exitThread")
   438  }
   439  
   440  //go:nosplit
   441  func semacreate(mp *m) {
   442  }
   443  
   444  //go:nosplit
   445  func semasleep(ns int64) int {
   446  	_g_ := getg()
   447  	if ns >= 0 {
   448  		ms := timediv(ns, 1000000, nil)
   449  		if ms == 0 {
   450  			ms = 1
   451  		}
   452  		ret := plan9_tsemacquire(&_g_.m.waitsemacount, ms)
   453  		if ret == 1 {
   454  			return 0 // success
   455  		}
   456  		return -1 // timeout or interrupted
   457  	}
   458  	for plan9_semacquire(&_g_.m.waitsemacount, 1) < 0 {
   459  		// interrupted; try again (c.f. lock_sema.go)
   460  	}
   461  	return 0 // success
   462  }
   463  
   464  //go:nosplit
   465  func semawakeup(mp *m) {
   466  	plan9_semrelease(&mp.waitsemacount, 1)
   467  }
   468  
   469  //go:nosplit
   470  func read(fd int32, buf unsafe.Pointer, n int32) int32 {
   471  	return pread(fd, buf, n, -1)
   472  }
   473  
   474  //go:nosplit
   475  func write1(fd uintptr, buf unsafe.Pointer, n int32) int32 {
   476  	return pwrite(int32(fd), buf, n, -1)
   477  }
   478  
   479  var _badsignal = []byte("runtime: signal received on thread not created by Go.\n")
   480  
   481  // This runs on a foreign stack, without an m or a g. No stack split.
   482  //go:nosplit
   483  func badsignal2() {
   484  	pwrite(2, unsafe.Pointer(&_badsignal[0]), int32(len(_badsignal)), -1)
   485  	exits(&_badsignal[0])
   486  }
   487  
   488  func raisebadsignal(sig uint32) {
   489  	badsignal2()
   490  }
   491  
   492  func _atoi(b []byte) int {
   493  	n := 0
   494  	for len(b) > 0 && '0' <= b[0] && b[0] <= '9' {
   495  		n = n*10 + int(b[0]) - '0'
   496  		b = b[1:]
   497  	}
   498  	return n
   499  }
   500  
   501  func signame(sig uint32) string {
   502  	if sig >= uint32(len(sigtable)) {
   503  		return ""
   504  	}
   505  	return sigtable[sig].name
   506  }
   507  
   508  const preemptMSupported = false
   509  
   510  func preemptM(mp *m) {
   511  	// Not currently supported.
   512  	//
   513  	// TODO: Use a note like we use signals on POSIX OSes
   514  }