github.com/karrick/go@v0.0.0-20170817181416-d5b0ec858b37/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 ( 8 "runtime/internal/atomic" 9 "runtime/internal/sys" 10 "unsafe" 11 ) 12 13 // Keep a cached value to make gotraceback fast, 14 // since we call it on every call to gentraceback. 15 // The cached value is a uint32 in which the low bits 16 // are the "crash" and "all" settings and the remaining 17 // bits are the traceback value (0 off, 1 on, 2 include system). 18 const ( 19 tracebackCrash = 1 << iota 20 tracebackAll 21 tracebackShift = iota 22 ) 23 24 var traceback_cache uint32 = 2 << tracebackShift 25 var traceback_env uint32 26 27 // gotraceback returns the current traceback settings. 28 // 29 // If level is 0, suppress all tracebacks. 30 // If level is 1, show tracebacks, but exclude runtime frames. 31 // If level is 2, show tracebacks including runtime frames. 32 // If all is set, print all goroutine stacks. Otherwise, print just the current goroutine. 33 // If crash is set, crash (core dump, etc) after tracebacking. 34 // 35 //go:nosplit 36 func gotraceback() (level int32, all, crash bool) { 37 _g_ := getg() 38 t := atomic.Load(&traceback_cache) 39 crash = t&tracebackCrash != 0 40 all = _g_.m.throwing > 0 || t&tracebackAll != 0 41 if _g_.m.traceback != 0 { 42 level = int32(_g_.m.traceback) 43 } else { 44 level = int32(t >> tracebackShift) 45 } 46 return 47 } 48 49 var ( 50 argc int32 51 argv **byte 52 ) 53 54 // nosplit for use in linux startup sysargs 55 //go:nosplit 56 func argv_index(argv **byte, i int32) *byte { 57 return *(**byte)(add(unsafe.Pointer(argv), uintptr(i)*sys.PtrSize)) 58 } 59 60 func args(c int32, v **byte) { 61 argc = c 62 argv = v 63 sysargs(c, v) 64 } 65 66 func goargs() { 67 if GOOS == "windows" { 68 return 69 } 70 argslice = make([]string, argc) 71 for i := int32(0); i < argc; i++ { 72 argslice[i] = gostringnocopy(argv_index(argv, i)) 73 } 74 } 75 76 func goenvs_unix() { 77 // TODO(austin): ppc64 in dynamic linking mode doesn't 78 // guarantee env[] will immediately follow argv. Might cause 79 // problems. 80 n := int32(0) 81 for argv_index(argv, argc+1+n) != nil { 82 n++ 83 } 84 85 envs = make([]string, n) 86 for i := int32(0); i < n; i++ { 87 envs[i] = gostring(argv_index(argv, argc+1+i)) 88 } 89 } 90 91 func environ() []string { 92 return envs 93 } 94 95 // TODO: These should be locals in testAtomic64, but we don't 8-byte 96 // align stack variables on 386. 97 var test_z64, test_x64 uint64 98 99 func testAtomic64() { 100 test_z64 = 42 101 test_x64 = 0 102 if atomic.Cas64(&test_z64, test_x64, 1) { 103 throw("cas64 failed") 104 } 105 if test_x64 != 0 { 106 throw("cas64 failed") 107 } 108 test_x64 = 42 109 if !atomic.Cas64(&test_z64, test_x64, 1) { 110 throw("cas64 failed") 111 } 112 if test_x64 != 42 || test_z64 != 1 { 113 throw("cas64 failed") 114 } 115 if atomic.Load64(&test_z64) != 1 { 116 throw("load64 failed") 117 } 118 atomic.Store64(&test_z64, (1<<40)+1) 119 if atomic.Load64(&test_z64) != (1<<40)+1 { 120 throw("store64 failed") 121 } 122 if atomic.Xadd64(&test_z64, (1<<40)+1) != (2<<40)+2 { 123 throw("xadd64 failed") 124 } 125 if atomic.Load64(&test_z64) != (2<<40)+2 { 126 throw("xadd64 failed") 127 } 128 if atomic.Xchg64(&test_z64, (3<<40)+3) != (2<<40)+2 { 129 throw("xchg64 failed") 130 } 131 if atomic.Load64(&test_z64) != (3<<40)+3 { 132 throw("xchg64 failed") 133 } 134 } 135 136 func check() { 137 var ( 138 a int8 139 b uint8 140 c int16 141 d uint16 142 e int32 143 f uint32 144 g int64 145 h uint64 146 i, i1 float32 147 j, j1 float64 148 k, k1 unsafe.Pointer 149 l *uint16 150 m [4]byte 151 ) 152 type x1t struct { 153 x uint8 154 } 155 type y1t struct { 156 x1 x1t 157 y uint8 158 } 159 var x1 x1t 160 var y1 y1t 161 162 if unsafe.Sizeof(a) != 1 { 163 throw("bad a") 164 } 165 if unsafe.Sizeof(b) != 1 { 166 throw("bad b") 167 } 168 if unsafe.Sizeof(c) != 2 { 169 throw("bad c") 170 } 171 if unsafe.Sizeof(d) != 2 { 172 throw("bad d") 173 } 174 if unsafe.Sizeof(e) != 4 { 175 throw("bad e") 176 } 177 if unsafe.Sizeof(f) != 4 { 178 throw("bad f") 179 } 180 if unsafe.Sizeof(g) != 8 { 181 throw("bad g") 182 } 183 if unsafe.Sizeof(h) != 8 { 184 throw("bad h") 185 } 186 if unsafe.Sizeof(i) != 4 { 187 throw("bad i") 188 } 189 if unsafe.Sizeof(j) != 8 { 190 throw("bad j") 191 } 192 if unsafe.Sizeof(k) != sys.PtrSize { 193 throw("bad k") 194 } 195 if unsafe.Sizeof(l) != sys.PtrSize { 196 throw("bad l") 197 } 198 if unsafe.Sizeof(x1) != 1 { 199 throw("bad unsafe.Sizeof x1") 200 } 201 if unsafe.Offsetof(y1.y) != 1 { 202 throw("bad offsetof y1.y") 203 } 204 if unsafe.Sizeof(y1) != 2 { 205 throw("bad unsafe.Sizeof y1") 206 } 207 208 if timediv(12345*1000000000+54321, 1000000000, &e) != 12345 || e != 54321 { 209 throw("bad timediv") 210 } 211 212 var z uint32 213 z = 1 214 if !atomic.Cas(&z, 1, 2) { 215 throw("cas1") 216 } 217 if z != 2 { 218 throw("cas2") 219 } 220 221 z = 4 222 if atomic.Cas(&z, 5, 6) { 223 throw("cas3") 224 } 225 if z != 4 { 226 throw("cas4") 227 } 228 229 z = 0xffffffff 230 if !atomic.Cas(&z, 0xffffffff, 0xfffffffe) { 231 throw("cas5") 232 } 233 if z != 0xfffffffe { 234 throw("cas6") 235 } 236 237 k = unsafe.Pointer(uintptr(0xfedcb123)) 238 if sys.PtrSize == 8 { 239 k = unsafe.Pointer(uintptr(k) << 10) 240 } 241 if casp(&k, nil, nil) { 242 throw("casp1") 243 } 244 k1 = add(k, 1) 245 if !casp(&k, k, k1) { 246 throw("casp2") 247 } 248 if k != k1 { 249 throw("casp3") 250 } 251 252 m = [4]byte{1, 1, 1, 1} 253 atomic.Or8(&m[1], 0xf0) 254 if m[0] != 1 || m[1] != 0xf1 || m[2] != 1 || m[3] != 1 { 255 throw("atomicor8") 256 } 257 258 m = [4]byte{0xff, 0xff, 0xff, 0xff} 259 atomic.And8(&m[1], 0x1) 260 if m[0] != 0xff || m[1] != 0x1 || m[2] != 0xff || m[3] != 0xff { 261 throw("atomicand8") 262 } 263 264 *(*uint64)(unsafe.Pointer(&j)) = ^uint64(0) 265 if j == j { 266 throw("float64nan") 267 } 268 if !(j != j) { 269 throw("float64nan1") 270 } 271 272 *(*uint64)(unsafe.Pointer(&j1)) = ^uint64(1) 273 if j == j1 { 274 throw("float64nan2") 275 } 276 if !(j != j1) { 277 throw("float64nan3") 278 } 279 280 *(*uint32)(unsafe.Pointer(&i)) = ^uint32(0) 281 if i == i { 282 throw("float32nan") 283 } 284 if i == i { 285 throw("float32nan1") 286 } 287 288 *(*uint32)(unsafe.Pointer(&i1)) = ^uint32(1) 289 if i == i1 { 290 throw("float32nan2") 291 } 292 if i == i1 { 293 throw("float32nan3") 294 } 295 296 testAtomic64() 297 298 if _FixedStack != round2(_FixedStack) { 299 throw("FixedStack is not power-of-2") 300 } 301 302 if !checkASM() { 303 throw("assembly checks failed") 304 } 305 } 306 307 type dbgVar struct { 308 name string 309 value *int32 310 } 311 312 // Holds variables parsed from GODEBUG env var, 313 // except for "memprofilerate" since there is an 314 // existing int var for that value, which may 315 // already have an initial value. 316 var debug struct { 317 allocfreetrace int32 318 cgocheck int32 319 efence int32 320 gccheckmark int32 321 gcpacertrace int32 322 gcshrinkstackoff int32 323 gcrescanstacks int32 324 gcstoptheworld int32 325 gctrace int32 326 invalidptr int32 327 sbrk int32 328 scavenge int32 329 scheddetail int32 330 schedtrace int32 331 } 332 333 var dbgvars = []dbgVar{ 334 {"allocfreetrace", &debug.allocfreetrace}, 335 {"cgocheck", &debug.cgocheck}, 336 {"efence", &debug.efence}, 337 {"gccheckmark", &debug.gccheckmark}, 338 {"gcpacertrace", &debug.gcpacertrace}, 339 {"gcshrinkstackoff", &debug.gcshrinkstackoff}, 340 {"gcrescanstacks", &debug.gcrescanstacks}, 341 {"gcstoptheworld", &debug.gcstoptheworld}, 342 {"gctrace", &debug.gctrace}, 343 {"invalidptr", &debug.invalidptr}, 344 {"sbrk", &debug.sbrk}, 345 {"scavenge", &debug.scavenge}, 346 {"scheddetail", &debug.scheddetail}, 347 {"schedtrace", &debug.schedtrace}, 348 } 349 350 func parsedebugvars() { 351 // defaults 352 debug.cgocheck = 1 353 debug.invalidptr = 1 354 355 for p := gogetenv("GODEBUG"); p != ""; { 356 field := "" 357 i := index(p, ",") 358 if i < 0 { 359 field, p = p, "" 360 } else { 361 field, p = p[:i], p[i+1:] 362 } 363 i = index(field, "=") 364 if i < 0 { 365 continue 366 } 367 key, value := field[:i], field[i+1:] 368 369 // Update MemProfileRate directly here since it 370 // is int, not int32, and should only be updated 371 // if specified in GODEBUG. 372 if key == "memprofilerate" { 373 if n, ok := atoi(value); ok { 374 MemProfileRate = n 375 } 376 } else { 377 for _, v := range dbgvars { 378 if v.name == key { 379 if n, ok := atoi32(value); ok { 380 *v.value = n 381 } 382 } 383 } 384 } 385 } 386 387 setTraceback(gogetenv("GOTRACEBACK")) 388 traceback_env = traceback_cache 389 390 // For cgocheck > 1, we turn on the write barrier at all times 391 // and check all pointer writes. 392 if debug.cgocheck > 1 { 393 writeBarrier.cgo = true 394 writeBarrier.enabled = true 395 } 396 } 397 398 //go:linkname setTraceback runtime/debug.SetTraceback 399 func setTraceback(level string) { 400 var t uint32 401 switch level { 402 case "none": 403 t = 0 404 case "single", "": 405 t = 1 << tracebackShift 406 case "all": 407 t = 1<<tracebackShift | tracebackAll 408 case "system": 409 t = 2<<tracebackShift | tracebackAll 410 case "crash": 411 t = 2<<tracebackShift | tracebackAll | tracebackCrash 412 default: 413 t = tracebackAll 414 if n, ok := atoi(level); ok && n == int(uint32(n)) { 415 t |= uint32(n) << tracebackShift 416 } 417 } 418 // when C owns the process, simply exit'ing the process on fatal errors 419 // and panics is surprising. Be louder and abort instead. 420 if islibrary || isarchive { 421 t |= tracebackCrash 422 } 423 424 t |= traceback_env 425 426 atomic.Store(&traceback_cache, t) 427 } 428 429 // Poor mans 64-bit division. 430 // This is a very special function, do not use it if you are not sure what you are doing. 431 // int64 division is lowered into _divv() call on 386, which does not fit into nosplit functions. 432 // Handles overflow in a time-specific manner. 433 //go:nosplit 434 func timediv(v int64, div int32, rem *int32) int32 { 435 res := int32(0) 436 for bit := 30; bit >= 0; bit-- { 437 if v >= int64(div)<<uint(bit) { 438 v = v - (int64(div) << uint(bit)) 439 res += 1 << uint(bit) 440 } 441 } 442 if v >= int64(div) { 443 if rem != nil { 444 *rem = 0 445 } 446 return 0x7fffffff 447 } 448 if rem != nil { 449 *rem = int32(v) 450 } 451 return res 452 } 453 454 // Helpers for Go. Must be NOSPLIT, must only call NOSPLIT functions, and must not block. 455 456 //go:nosplit 457 func acquirem() *m { 458 _g_ := getg() 459 _g_.m.locks++ 460 return _g_.m 461 } 462 463 //go:nosplit 464 func releasem(mp *m) { 465 _g_ := getg() 466 mp.locks-- 467 if mp.locks == 0 && _g_.preempt { 468 // restore the preemption request in case we've cleared it in newstack 469 _g_.stackguard0 = stackPreempt 470 } 471 } 472 473 //go:nosplit 474 func gomcache() *mcache { 475 return getg().m.mcache 476 } 477 478 //go:linkname reflect_typelinks reflect.typelinks 479 func reflect_typelinks() ([]unsafe.Pointer, [][]int32) { 480 modules := activeModules() 481 sections := []unsafe.Pointer{unsafe.Pointer(modules[0].types)} 482 ret := [][]int32{modules[0].typelinks} 483 for _, md := range modules[1:] { 484 sections = append(sections, unsafe.Pointer(md.types)) 485 ret = append(ret, md.typelinks) 486 } 487 return sections, ret 488 } 489 490 // reflect_resolveNameOff resolves a name offset from a base pointer. 491 //go:linkname reflect_resolveNameOff reflect.resolveNameOff 492 func reflect_resolveNameOff(ptrInModule unsafe.Pointer, off int32) unsafe.Pointer { 493 return unsafe.Pointer(resolveNameOff(ptrInModule, nameOff(off)).bytes) 494 } 495 496 // reflect_resolveTypeOff resolves an *rtype offset from a base type. 497 //go:linkname reflect_resolveTypeOff reflect.resolveTypeOff 498 func reflect_resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer { 499 return unsafe.Pointer((*_type)(rtype).typeOff(typeOff(off))) 500 } 501 502 // reflect_resolveTextOff resolves an function pointer offset from a base type. 503 //go:linkname reflect_resolveTextOff reflect.resolveTextOff 504 func reflect_resolveTextOff(rtype unsafe.Pointer, off int32) unsafe.Pointer { 505 return (*_type)(rtype).textOff(textOff(off)) 506 507 } 508 509 // reflect_addReflectOff adds a pointer to the reflection offset lookup map. 510 //go:linkname reflect_addReflectOff reflect.addReflectOff 511 func reflect_addReflectOff(ptr unsafe.Pointer) int32 { 512 reflectOffsLock() 513 if reflectOffs.m == nil { 514 reflectOffs.m = make(map[int32]unsafe.Pointer) 515 reflectOffs.minv = make(map[unsafe.Pointer]int32) 516 reflectOffs.next = -1 517 } 518 id, found := reflectOffs.minv[ptr] 519 if !found { 520 id = reflectOffs.next 521 reflectOffs.next-- // use negative offsets as IDs to aid debugging 522 reflectOffs.m[id] = ptr 523 reflectOffs.minv[ptr] = id 524 } 525 reflectOffsUnlock() 526 return id 527 }