github.com/euank/go@v0.0.0-20160829210321-495514729181/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, msg 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 pid = []byte("#c/pid\x00")
   221  
   222  func getpid() uint64 {
   223  	var b [20]byte
   224  	fd := open(&pid[0], 0, 0)
   225  	if fd >= 0 {
   226  		read(fd, unsafe.Pointer(&b), int32(len(b)))
   227  		closefd(fd)
   228  	}
   229  	c := b[:]
   230  	for c[0] == ' ' || c[0] == '\t' {
   231  		c = c[1:]
   232  	}
   233  	return uint64(_atoi(c))
   234  }
   235  
   236  func osinit() {
   237  	initBloc()
   238  	ncpu = getproccount()
   239  	getg().m.procid = getpid()
   240  	notify(unsafe.Pointer(funcPC(sigtramp)))
   241  }
   242  
   243  func crash() {
   244  	notify(nil)
   245  	*(*int)(nil) = 0
   246  }
   247  
   248  //go:nosplit
   249  func getRandomData(r []byte) {
   250  	extendRandom(r, 0)
   251  }
   252  
   253  func goenvs() {
   254  }
   255  
   256  func initsig(preinit bool) {
   257  }
   258  
   259  //go:nosplit
   260  func osyield() {
   261  	sleep(0)
   262  }
   263  
   264  //go:nosplit
   265  func usleep(µs uint32) {
   266  	ms := int32(µs / 1000)
   267  	if ms == 0 {
   268  		ms = 1
   269  	}
   270  	sleep(ms)
   271  }
   272  
   273  //go:nosplit
   274  func nanotime() int64 {
   275  	var scratch int64
   276  	ns := nsec(&scratch)
   277  	// TODO(aram): remove hack after I fix _nsec in the pc64 kernel.
   278  	if ns == 0 {
   279  		return scratch
   280  	}
   281  	return ns
   282  }
   283  
   284  //go:nosplit
   285  func itoa(buf []byte, val uint64) []byte {
   286  	i := len(buf) - 1
   287  	for val >= 10 {
   288  		buf[i] = byte(val%10 + '0')
   289  		i--
   290  		val /= 10
   291  	}
   292  	buf[i] = byte(val + '0')
   293  	return buf[i:]
   294  }
   295  
   296  var goexits = []byte("go: exit ")
   297  var emptystatus = []byte("\x00")
   298  var exiting uint32
   299  
   300  func goexitsall(status *byte) {
   301  	var buf [_ERRMAX]byte
   302  	if !atomic.Cas(&exiting, 0, 1) {
   303  		return
   304  	}
   305  	getg().m.locks++
   306  	n := copy(buf[:], goexits)
   307  	n = copy(buf[n:], gostringnocopy(status))
   308  	pid := getpid()
   309  	for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink {
   310  		if mp.procid != 0 && mp.procid != pid {
   311  			postnote(mp.procid, buf[:])
   312  		}
   313  	}
   314  	getg().m.locks--
   315  }
   316  
   317  var procdir = []byte("/proc/")
   318  var notefile = []byte("/note\x00")
   319  
   320  func postnote(pid uint64, msg []byte) int {
   321  	var buf [128]byte
   322  	var tmp [32]byte
   323  	n := copy(buf[:], procdir)
   324  	n += copy(buf[n:], itoa(tmp[:], pid))
   325  	copy(buf[n:], notefile)
   326  	fd := open(&buf[0], _OWRITE, 0)
   327  	if fd < 0 {
   328  		return -1
   329  	}
   330  	len := findnull(&msg[0])
   331  	if write(uintptr(fd), unsafe.Pointer(&msg[0]), int32(len)) != int64(len) {
   332  		closefd(fd)
   333  		return -1
   334  	}
   335  	closefd(fd)
   336  	return 0
   337  }
   338  
   339  //go:nosplit
   340  func exit(e int) {
   341  	var status []byte
   342  	if e == 0 {
   343  		status = emptystatus
   344  	} else {
   345  		// build error string
   346  		var tmp [32]byte
   347  		status = append(itoa(tmp[:len(tmp)-1], uint64(e)), 0)
   348  	}
   349  	goexitsall(&status[0])
   350  	exits(&status[0])
   351  }
   352  
   353  // May run with m.p==nil, so write barriers are not allowed.
   354  //go:nowritebarrier
   355  func newosproc(mp *m, stk unsafe.Pointer) {
   356  	if false {
   357  		print("newosproc mp=", mp, " ostk=", &mp, "\n")
   358  	}
   359  	pid := rfork(_RFPROC | _RFMEM | _RFNOWAIT)
   360  	if pid < 0 {
   361  		throw("newosproc: rfork failed")
   362  	}
   363  	if pid == 0 {
   364  		tstart_plan9(mp)
   365  	}
   366  }
   367  
   368  //go:nosplit
   369  func semacreate(mp *m) {
   370  }
   371  
   372  //go:nosplit
   373  func semasleep(ns int64) int {
   374  	_g_ := getg()
   375  	if ns >= 0 {
   376  		ms := timediv(ns, 1000000, nil)
   377  		if ms == 0 {
   378  			ms = 1
   379  		}
   380  		ret := plan9_tsemacquire(&_g_.m.waitsemacount, ms)
   381  		if ret == 1 {
   382  			return 0 // success
   383  		}
   384  		return -1 // timeout or interrupted
   385  	}
   386  	for plan9_semacquire(&_g_.m.waitsemacount, 1) < 0 {
   387  		// interrupted; try again (c.f. lock_sema.go)
   388  	}
   389  	return 0 // success
   390  }
   391  
   392  //go:nosplit
   393  func semawakeup(mp *m) {
   394  	plan9_semrelease(&mp.waitsemacount, 1)
   395  }
   396  
   397  //go:nosplit
   398  func read(fd int32, buf unsafe.Pointer, n int32) int32 {
   399  	return pread(fd, buf, n, -1)
   400  }
   401  
   402  //go:nosplit
   403  func write(fd uintptr, buf unsafe.Pointer, n int32) int64 {
   404  	return int64(pwrite(int32(fd), buf, n, -1))
   405  }
   406  
   407  func memlimit() uint64 {
   408  	return 0
   409  }
   410  
   411  var _badsignal = []byte("runtime: signal received on thread not created by Go.\n")
   412  
   413  // This runs on a foreign stack, without an m or a g. No stack split.
   414  //go:nosplit
   415  func badsignal2() {
   416  	pwrite(2, unsafe.Pointer(&_badsignal[0]), int32(len(_badsignal)), -1)
   417  	exits(&_badsignal[0])
   418  }
   419  
   420  func raisebadsignal(sig int32) {
   421  	badsignal2()
   422  }
   423  
   424  func _atoi(b []byte) int {
   425  	n := 0
   426  	for len(b) > 0 && '0' <= b[0] && b[0] <= '9' {
   427  		n = n*10 + int(b[0]) - '0'
   428  		b = b[1:]
   429  	}
   430  	return n
   431  }
   432  
   433  func signame(sig uint32) string {
   434  	if sig >= uint32(len(sigtable)) {
   435  		return ""
   436  	}
   437  	return sigtable[sig].name
   438  }