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 }