github.com/c0deoo1/golang1.5@v0.0.0-20220525150107-c87c805d4593/src/runtime/runtime1.go (about)

     1  // Copyright 2009 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 "unsafe"
     8  
     9  // Keep a cached value to make gotraceback fast,
    10  // since we call it on every call to gentraceback.
    11  // The cached value is a uint32 in which the low bit
    12  // is the "crash" setting and the top 31 bits are the
    13  // gotraceback value.
    14  var traceback_cache uint32 = 2 << 1
    15  
    16  // The GOTRACEBACK environment variable controls the
    17  // behavior of a Go program that is crashing and exiting.
    18  //	GOTRACEBACK=0   suppress all tracebacks
    19  //	GOTRACEBACK=1   default behavior - show tracebacks but exclude runtime frames
    20  //	GOTRACEBACK=2   show tracebacks including runtime frames
    21  //	GOTRACEBACK=crash   show tracebacks including runtime frames, then crash (core dump etc)
    22  //go:nosplit
    23  func gotraceback(crash *bool) int32 {
    24  	_g_ := getg()
    25  	if crash != nil {
    26  		*crash = false
    27  	}
    28  	if _g_.m.traceback != 0 {
    29  		return int32(_g_.m.traceback)
    30  	}
    31  	if crash != nil {
    32  		*crash = traceback_cache&1 != 0
    33  	}
    34  	return int32(traceback_cache >> 1)
    35  }
    36  
    37  var (
    38  	argc int32
    39  	argv **byte
    40  )
    41  
    42  // nosplit for use in linux/386 startup linux_setup_vdso
    43  //go:nosplit
    44  func argv_index(argv **byte, i int32) *byte {
    45  	return *(**byte)(add(unsafe.Pointer(argv), uintptr(i)*ptrSize))
    46  }
    47  
    48  // 将参数保留在变量中
    49  func args(c int32, v **byte) {
    50  	argc = c
    51  	argv = v
    52  	// 这里会解析vDSO中的时间函数,后续可以高效的获取时间信息,参考vdso_linux_amd64.go
    53  	sysargs(c, v)
    54  }
    55  
    56  var (
    57  	// TODO: Retire in favor of GOOS== checks.
    58  	isplan9   int32
    59  	issolaris int32
    60  	iswindows int32
    61  )
    62  
    63  func goargs() {
    64  	if GOOS == "windows" {
    65  		return
    66  	}
    67  
    68  	argslice = make([]string, argc)
    69  	for i := int32(0); i < argc; i++ {
    70  		argslice[i] = gostringnocopy(argv_index(argv, i))
    71  	}
    72  }
    73  
    74  func goenvs_unix() {
    75  	// TODO(austin): ppc64 in dynamic linking mode doesn't
    76  	// guarantee env[] will immediately follow argv.  Might cause
    77  	// problems.
    78  	n := int32(0)
    79  	for argv_index(argv, argc+1+n) != nil {
    80  		n++
    81  	}
    82  
    83  	envs = make([]string, n)
    84  	for i := int32(0); i < n; i++ {
    85  		envs[i] = gostring(argv_index(argv, argc+1+i))
    86  	}
    87  }
    88  
    89  func environ() []string {
    90  	return envs
    91  }
    92  
    93  // TODO: These should be locals in testAtomic64, but we don't 8-byte
    94  // align stack variables on 386.
    95  var test_z64, test_x64 uint64
    96  
    97  func testAtomic64() {
    98  	test_z64 = 42
    99  	test_x64 = 0
   100  	prefetcht0(uintptr(unsafe.Pointer(&test_z64)))
   101  	prefetcht1(uintptr(unsafe.Pointer(&test_z64)))
   102  	prefetcht2(uintptr(unsafe.Pointer(&test_z64)))
   103  	prefetchnta(uintptr(unsafe.Pointer(&test_z64)))
   104  	if cas64(&test_z64, test_x64, 1) {
   105  		throw("cas64 failed")
   106  	}
   107  	if test_x64 != 0 {
   108  		throw("cas64 failed")
   109  	}
   110  	test_x64 = 42
   111  	if !cas64(&test_z64, test_x64, 1) {
   112  		throw("cas64 failed")
   113  	}
   114  	if test_x64 != 42 || test_z64 != 1 {
   115  		throw("cas64 failed")
   116  	}
   117  	if atomicload64(&test_z64) != 1 {
   118  		throw("load64 failed")
   119  	}
   120  	atomicstore64(&test_z64, (1<<40)+1)
   121  	if atomicload64(&test_z64) != (1<<40)+1 {
   122  		throw("store64 failed")
   123  	}
   124  	if xadd64(&test_z64, (1<<40)+1) != (2<<40)+2 {
   125  		throw("xadd64 failed")
   126  	}
   127  	if atomicload64(&test_z64) != (2<<40)+2 {
   128  		throw("xadd64 failed")
   129  	}
   130  	if xchg64(&test_z64, (3<<40)+3) != (2<<40)+2 {
   131  		throw("xchg64 failed")
   132  	}
   133  	if atomicload64(&test_z64) != (3<<40)+3 {
   134  		throw("xchg64 failed")
   135  	}
   136  }
   137  // 做一些基础的运行校对
   138  func check() {
   139  	var (
   140  		a     int8
   141  		b     uint8
   142  		c     int16
   143  		d     uint16
   144  		e     int32
   145  		f     uint32
   146  		g     int64
   147  		h     uint64
   148  		i, i1 float32
   149  		j, j1 float64
   150  		k, k1 unsafe.Pointer
   151  		l     *uint16
   152  		m     [4]byte
   153  	)
   154  	type x1t struct {
   155  		x uint8
   156  	}
   157  	type y1t struct {
   158  		x1 x1t
   159  		y  uint8
   160  	}
   161  	var x1 x1t
   162  	var y1 y1t
   163  
   164  	if unsafe.Sizeof(a) != 1 {
   165  		throw("bad a")
   166  	}
   167  	if unsafe.Sizeof(b) != 1 {
   168  		throw("bad b")
   169  	}
   170  	if unsafe.Sizeof(c) != 2 {
   171  		throw("bad c")
   172  	}
   173  	if unsafe.Sizeof(d) != 2 {
   174  		throw("bad d")
   175  	}
   176  	if unsafe.Sizeof(e) != 4 {
   177  		throw("bad e")
   178  	}
   179  	if unsafe.Sizeof(f) != 4 {
   180  		throw("bad f")
   181  	}
   182  	if unsafe.Sizeof(g) != 8 {
   183  		throw("bad g")
   184  	}
   185  	if unsafe.Sizeof(h) != 8 {
   186  		throw("bad h")
   187  	}
   188  	if unsafe.Sizeof(i) != 4 {
   189  		throw("bad i")
   190  	}
   191  	if unsafe.Sizeof(j) != 8 {
   192  		throw("bad j")
   193  	}
   194  	if unsafe.Sizeof(k) != ptrSize {
   195  		throw("bad k")
   196  	}
   197  	if unsafe.Sizeof(l) != ptrSize {
   198  		throw("bad l")
   199  	}
   200  	if unsafe.Sizeof(x1) != 1 {
   201  		throw("bad unsafe.Sizeof x1")
   202  	}
   203  	if unsafe.Offsetof(y1.y) != 1 {
   204  		throw("bad offsetof y1.y")
   205  	}
   206  	if unsafe.Sizeof(y1) != 2 {
   207  		throw("bad unsafe.Sizeof y1")
   208  	}
   209  
   210  	if timediv(12345*1000000000+54321, 1000000000, &e) != 12345 || e != 54321 {
   211  		throw("bad timediv")
   212  	}
   213  
   214  	var z uint32
   215  	z = 1
   216  	if !cas(&z, 1, 2) {
   217  		throw("cas1")
   218  	}
   219  	if z != 2 {
   220  		throw("cas2")
   221  	}
   222  
   223  	z = 4
   224  	if cas(&z, 5, 6) {
   225  		throw("cas3")
   226  	}
   227  	if z != 4 {
   228  		throw("cas4")
   229  	}
   230  
   231  	z = 0xffffffff
   232  	if !cas(&z, 0xffffffff, 0xfffffffe) {
   233  		throw("cas5")
   234  	}
   235  	if z != 0xfffffffe {
   236  		throw("cas6")
   237  	}
   238  
   239  	k = unsafe.Pointer(uintptr(0xfedcb123))
   240  	if ptrSize == 8 {
   241  		k = unsafe.Pointer(uintptr(unsafe.Pointer(k)) << 10)
   242  	}
   243  	if casp(&k, nil, nil) {
   244  		throw("casp1")
   245  	}
   246  	k1 = add(k, 1)
   247  	if !casp(&k, k, k1) {
   248  		throw("casp2")
   249  	}
   250  	if k != k1 {
   251  		throw("casp3")
   252  	}
   253  
   254  	m = [4]byte{1, 1, 1, 1}
   255  	atomicor8(&m[1], 0xf0)
   256  	if m[0] != 1 || m[1] != 0xf1 || m[2] != 1 || m[3] != 1 {
   257  		throw("atomicor8")
   258  	}
   259  
   260  	*(*uint64)(unsafe.Pointer(&j)) = ^uint64(0)
   261  	if j == j {
   262  		throw("float64nan")
   263  	}
   264  	if !(j != j) {
   265  		throw("float64nan1")
   266  	}
   267  
   268  	*(*uint64)(unsafe.Pointer(&j1)) = ^uint64(1)
   269  	if j == j1 {
   270  		throw("float64nan2")
   271  	}
   272  	if !(j != j1) {
   273  		throw("float64nan3")
   274  	}
   275  
   276  	*(*uint32)(unsafe.Pointer(&i)) = ^uint32(0)
   277  	if i == i {
   278  		throw("float32nan")
   279  	}
   280  	if i == i {
   281  		throw("float32nan1")
   282  	}
   283  
   284  	*(*uint32)(unsafe.Pointer(&i1)) = ^uint32(1)
   285  	if i == i1 {
   286  		throw("float32nan2")
   287  	}
   288  	if i == i1 {
   289  		throw("float32nan3")
   290  	}
   291  
   292  	testAtomic64()
   293  
   294  	if _FixedStack != round2(_FixedStack) {
   295  		throw("FixedStack is not power-of-2")
   296  	}
   297  }
   298  
   299  type dbgVar struct {
   300  	name  string
   301  	value *int32
   302  }
   303  
   304  // Holds variables parsed from GODEBUG env var,
   305  // except for "memprofilerate" since there is an
   306  // existing int var for that value, which may
   307  // already have an initial value.
   308  var debug struct {
   309  	allocfreetrace    int32
   310  	efence            int32
   311  	gccheckmark       int32
   312  	gcpacertrace      int32
   313  	gcshrinkstackoff  int32
   314  	gcstackbarrieroff int32
   315  	gcstoptheworld    int32
   316  	gctrace           int32
   317  	invalidptr        int32
   318  	sbrk              int32
   319  	scavenge          int32
   320  	scheddetail       int32
   321  	schedtrace        int32
   322  	wbshadow          int32
   323  }
   324  
   325  var dbgvars = []dbgVar{
   326  	{"allocfreetrace", &debug.allocfreetrace},
   327  	{"efence", &debug.efence},
   328  	{"gccheckmark", &debug.gccheckmark},
   329  	{"gcpacertrace", &debug.gcpacertrace},
   330  	{"gcshrinkstackoff", &debug.gcshrinkstackoff},
   331  	{"gcstackbarrieroff", &debug.gcstackbarrieroff},
   332  	{"gcstoptheworld", &debug.gcstoptheworld},
   333  	{"gctrace", &debug.gctrace},
   334  	{"invalidptr", &debug.invalidptr},
   335  	{"sbrk", &debug.sbrk},
   336  	{"scavenge", &debug.scavenge},
   337  	{"scheddetail", &debug.scheddetail},
   338  	{"schedtrace", &debug.schedtrace},
   339  	{"wbshadow", &debug.wbshadow},
   340  }
   341  
   342  func parsedebugvars() {
   343  	// defaults
   344  	debug.invalidptr = 1
   345  
   346  	for p := gogetenv("GODEBUG"); p != ""; {
   347  		field := ""
   348  		i := index(p, ",")
   349  		if i < 0 {
   350  			field, p = p, ""
   351  		} else {
   352  			field, p = p[:i], p[i+1:]
   353  		}
   354  		i = index(field, "=")
   355  		if i < 0 {
   356  			continue
   357  		}
   358  		key, value := field[:i], field[i+1:]
   359  
   360  		// Update MemProfileRate directly here since it
   361  		// is int, not int32, and should only be updated
   362  		// if specified in GODEBUG.
   363  		if key == "memprofilerate" {
   364  			MemProfileRate = atoi(value)
   365  		} else {
   366  			for _, v := range dbgvars {
   367  				if v.name == key {
   368  					*v.value = int32(atoi(value))
   369  				}
   370  			}
   371  		}
   372  	}
   373  
   374  	switch p := gogetenv("GOTRACEBACK"); p {
   375  	case "":
   376  		traceback_cache = 1 << 1
   377  	case "crash":
   378  		traceback_cache = 2<<1 | 1
   379  	default:
   380  		traceback_cache = uint32(atoi(p)) << 1
   381  	}
   382  	// when C owns the process, simply exit'ing the process on fatal errors
   383  	// and panics is surprising. Be louder and abort instead.
   384  	if islibrary || isarchive {
   385  		traceback_cache |= 1
   386  	}
   387  }
   388  
   389  // Poor mans 64-bit division.
   390  // This is a very special function, do not use it if you are not sure what you are doing.
   391  // int64 division is lowered into _divv() call on 386, which does not fit into nosplit functions.
   392  // Handles overflow in a time-specific manner.
   393  //go:nosplit
   394  func timediv(v int64, div int32, rem *int32) int32 {
   395  	res := int32(0)
   396  	for bit := 30; bit >= 0; bit-- {
   397  		if v >= int64(div)<<uint(bit) {
   398  			v = v - (int64(div) << uint(bit))
   399  			res += 1 << uint(bit)
   400  		}
   401  	}
   402  	if v >= int64(div) {
   403  		if rem != nil {
   404  			*rem = 0
   405  		}
   406  		return 0x7fffffff
   407  	}
   408  	if rem != nil {
   409  		*rem = int32(v)
   410  	}
   411  	return res
   412  }
   413  
   414  // Helpers for Go. Must be NOSPLIT, must only call NOSPLIT functions, and must not block.
   415  
   416  //go:nosplit
   417  func acquirem() *m {
   418  	_g_ := getg()
   419  	_g_.m.locks++
   420  	return _g_.m
   421  }
   422  
   423  //go:nosplit
   424  func releasem(mp *m) {
   425  	_g_ := getg()
   426  	mp.locks--
   427  	if mp.locks == 0 && _g_.preempt {
   428  		// restore the preemption request in case we've cleared it in newstack
   429  		_g_.stackguard0 = stackPreempt
   430  	}
   431  }
   432  
   433  //go:nosplit
   434  func gomcache() *mcache {
   435  	return getg().m.mcache
   436  }
   437  
   438  //go:linkname reflect_typelinks reflect.typelinks
   439  //go:nosplit
   440  func reflect_typelinks() [][]*_type {
   441  	ret := [][]*_type{firstmoduledata.typelinks}
   442  	for datap := firstmoduledata.next; datap != nil; datap = datap.next {
   443  		ret = append(ret, datap.typelinks)
   444  	}
   445  	return ret
   446  }