github.com/ltltlt/go-source-code@v0.0.0-20190830023027-95be009773aa/runtime/print.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 // 此文件实现了一些println这样的内置函数 14 // 编译器发现println这样的语句时,会将其变为调用printlock, print*, printsp, printnl, printunlock这些调用 15 16 // The compiler knows that a print of a value of this type 17 // should use printhex instead of printuint (decimal). 18 type hex uint64 19 20 func bytes(s string) (ret []byte) { 21 rp := (*slice)(unsafe.Pointer(&ret)) 22 sp := stringStructOf(&s) 23 rp.array = sp.str 24 rp.len = sp.len 25 rp.cap = sp.len 26 return 27 } 28 29 var ( 30 // printBacklog is a circular buffer of messages written with the builtin 31 // print* functions, for use in postmortem analysis of core dumps. 32 printBacklog [512]byte 33 printBacklogIndex int 34 ) 35 36 // recordForPanic maintains a circular buffer of messages written by the 37 // runtime leading up to a process crash, allowing the messages to be 38 // extracted from a core dump. 39 // 40 // The text written during a process crash (following "panic" or "fatal 41 // error") is not saved, since the goroutine stacks will generally be readable 42 // from the runtime datastructures in the core file. 43 func recordForPanic(b []byte) { 44 printlock() 45 46 if atomic.Load(&panicking) == 0 { 47 // Not actively crashing: maintain circular buffer of print output. 48 for i := 0; i < len(b); { 49 n := copy(printBacklog[printBacklogIndex:], b[i:]) 50 i += n 51 printBacklogIndex += n 52 printBacklogIndex %= len(printBacklog) 53 } 54 } 55 56 printunlock() 57 } 58 59 var debuglock mutex 60 61 // The compiler emits calls to printlock and printunlock around 62 // the multiple calls that implement a single Go print or println 63 // statement. Some of the print helpers (printslice, for example) 64 // call print recursively. There is also the problem of a crash 65 // happening during the print routines and needing to acquire 66 // the print lock to print information about the crash. 67 // For both these reasons, let a thread acquire the printlock 'recursively'. 68 69 func printlock() { 70 mp := getg().m 71 mp.locks++ // do not reschedule between printlock++ and lock(&debuglock). 72 mp.printlock++ 73 if mp.printlock == 1 { 74 lock(&debuglock) 75 } 76 mp.locks-- // now we know debuglock is held and holding up mp.locks for us. 77 } 78 79 func printunlock() { 80 mp := getg().m 81 mp.printlock-- 82 if mp.printlock == 0 { 83 unlock(&debuglock) 84 } 85 } 86 87 // write to goroutine-local buffer if diverting output, 88 // or else standard error. 89 func gwrite(b []byte) { 90 if len(b) == 0 { 91 return 92 } 93 recordForPanic(b) 94 gp := getg() 95 if gp == nil || gp.writebuf == nil { 96 writeErr(b) 97 return 98 } 99 100 n := copy(gp.writebuf[len(gp.writebuf):cap(gp.writebuf)], b) 101 gp.writebuf = gp.writebuf[:len(gp.writebuf)+n] 102 } 103 104 func printsp() { 105 printstring(" ") 106 } 107 108 func printnl() { 109 printstring("\n") 110 } 111 112 func printbool(v bool) { 113 if v { 114 printstring("true") 115 } else { 116 printstring("false") 117 } 118 } 119 120 func printfloat(v float64) { 121 switch { 122 case v != v: 123 printstring("NaN") 124 return 125 case v+v == v && v > 0: 126 printstring("+Inf") 127 return 128 case v+v == v && v < 0: 129 printstring("-Inf") 130 return 131 } 132 133 const n = 7 // digits printed 134 var buf [n + 7]byte 135 buf[0] = '+' 136 e := 0 // exp 137 if v == 0 { 138 if 1/v < 0 { 139 buf[0] = '-' 140 } 141 } else { 142 if v < 0 { 143 v = -v 144 buf[0] = '-' 145 } 146 147 // normalize 148 for v >= 10 { 149 e++ 150 v /= 10 151 } 152 for v < 1 { 153 e-- 154 v *= 10 155 } 156 157 // round 158 h := 5.0 159 for i := 0; i < n; i++ { 160 h /= 10 161 } 162 v += h 163 if v >= 10 { 164 e++ 165 v /= 10 166 } 167 } 168 169 // format +d.dddd+edd 170 for i := 0; i < n; i++ { 171 s := int(v) 172 buf[i+2] = byte(s + '0') 173 v -= float64(s) 174 v *= 10 175 } 176 buf[1] = buf[2] 177 buf[2] = '.' 178 179 buf[n+2] = 'e' 180 buf[n+3] = '+' 181 if e < 0 { 182 e = -e 183 buf[n+3] = '-' 184 } 185 186 buf[n+4] = byte(e/100) + '0' 187 buf[n+5] = byte(e/10)%10 + '0' 188 buf[n+6] = byte(e%10) + '0' 189 gwrite(buf[:]) 190 } 191 192 func printcomplex(c complex128) { 193 print("(", real(c), imag(c), "i)") 194 } 195 196 func printuint(v uint64) { 197 var buf [100]byte 198 i := len(buf) 199 for i--; i > 0; i-- { 200 buf[i] = byte(v%10 + '0') 201 if v < 10 { 202 break 203 } 204 v /= 10 205 } 206 gwrite(buf[i:]) 207 } 208 209 func printint(v int64) { 210 if v < 0 { 211 printstring("-") 212 v = -v 213 } 214 printuint(uint64(v)) 215 } 216 217 func printhex(v uint64) { 218 const dig = "0123456789abcdef" 219 var buf [100]byte 220 i := len(buf) 221 for i--; i > 0; i-- { 222 buf[i] = dig[v%16] 223 if v < 16 { 224 break 225 } 226 v /= 16 227 } 228 i-- 229 buf[i] = 'x' 230 i-- 231 buf[i] = '0' 232 gwrite(buf[i:]) 233 } 234 235 func printpointer(p unsafe.Pointer) { 236 printhex(uint64(uintptr(p))) 237 } 238 239 func printstring(s string) { 240 gwrite(bytes(s)) 241 } 242 243 func printslice(s []byte) { 244 sp := (*slice)(unsafe.Pointer(&s)) 245 print("[", len(s), "/", cap(s), "]") 246 printpointer(sp.array) 247 } 248 249 func printeface(e eface) { 250 print("(", e._type, ",", e.data, ")") 251 } 252 253 func printiface(i iface) { 254 print("(", i.tab, ",", i.data, ")") 255 } 256 257 // hexdumpWords prints a word-oriented hex dump of [p, end). 258 // 259 // If mark != nil, it will be called with each printed word's address 260 // and should return a character mark to appear just before that 261 // word's value. It can return 0 to indicate no mark. 262 func hexdumpWords(p, end uintptr, mark func(uintptr) byte) { 263 p1 := func(x uintptr) { 264 var buf [2 * sys.PtrSize]byte 265 for i := len(buf) - 1; i >= 0; i-- { 266 if x&0xF < 10 { 267 buf[i] = byte(x&0xF) + '0' 268 } else { 269 buf[i] = byte(x&0xF) - 10 + 'a' 270 } 271 x >>= 4 272 } 273 gwrite(buf[:]) 274 } 275 276 printlock() 277 var markbuf [1]byte 278 markbuf[0] = ' ' 279 for i := uintptr(0); p+i < end; i += sys.PtrSize { 280 if i%16 == 0 { 281 if i != 0 { 282 println() 283 } 284 p1(p + i) 285 print(": ") 286 } 287 288 if mark != nil { 289 markbuf[0] = mark(p + i) 290 if markbuf[0] == 0 { 291 markbuf[0] = ' ' 292 } 293 } 294 gwrite(markbuf[:]) 295 val := *(*uintptr)(unsafe.Pointer(p + i)) 296 p1(val) 297 print(" ") 298 299 // Can we symbolize val? 300 fn := findfunc(val) 301 if fn.valid() { 302 print("<", funcname(fn), "+", val-fn.entry, "> ") 303 } 304 } 305 println() 306 printunlock() 307 }