Home | History | Annotate | Download | only in runtime
      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 	"unsafe"
     10 )
     11 
     12 // The compiler knows that a print of a value of this type
     13 // should use printhex instead of printuint (decimal).
     14 type hex uint64
     15 
     16 func bytes(s string) (ret []byte) {
     17 	rp := (*slice)(unsafe.Pointer(&ret))
     18 	sp := stringStructOf(&s)
     19 	rp.array = sp.str
     20 	rp.len = sp.len
     21 	rp.cap = sp.len
     22 	return
     23 }
     24 
     25 var (
     26 	// printBacklog is a circular buffer of messages written with the builtin
     27 	// print* functions, for use in postmortem analysis of core dumps.
     28 	printBacklog      [512]byte
     29 	printBacklogIndex int
     30 )
     31 
     32 // recordForPanic maintains a circular buffer of messages written by the
     33 // runtime leading up to a process crash, allowing the messages to be
     34 // extracted from a core dump.
     35 //
     36 // The text written during a process crash (following "panic" or "fatal
     37 // error") is not saved, since the goroutine stacks will generally be readable
     38 // from the runtime datastructures in the core file.
     39 func recordForPanic(b []byte) {
     40 	printlock()
     41 
     42 	if atomic.Load(&panicking) == 0 {
     43 		// Not actively crashing: maintain circular buffer of print output.
     44 		for i := 0; i < len(b); {
     45 			n := copy(printBacklog[printBacklogIndex:], b[i:])
     46 			i += n
     47 			printBacklogIndex += n
     48 			printBacklogIndex %= len(printBacklog)
     49 		}
     50 	}
     51 
     52 	printunlock()
     53 }
     54 
     55 var debuglock mutex
     56 
     57 // The compiler emits calls to printlock and printunlock around
     58 // the multiple calls that implement a single Go print or println
     59 // statement. Some of the print helpers (printsp, for example)
     60 // call print recursively. There is also the problem of a crash
     61 // happening during the print routines and needing to acquire
     62 // the print lock to print information about the crash.
     63 // For both these reasons, let a thread acquire the printlock 'recursively'.
     64 
     65 func printlock() {
     66 	mp := getg().m
     67 	mp.locks++ // do not reschedule between printlock++ and lock(&debuglock).
     68 	mp.printlock++
     69 	if mp.printlock == 1 {
     70 		lock(&debuglock)
     71 	}
     72 	mp.locks-- // now we know debuglock is held and holding up mp.locks for us.
     73 }
     74 
     75 func printunlock() {
     76 	mp := getg().m
     77 	mp.printlock--
     78 	if mp.printlock == 0 {
     79 		unlock(&debuglock)
     80 	}
     81 }
     82 
     83 // write to goroutine-local buffer if diverting output,
     84 // or else standard error.
     85 func gwrite(b []byte) {
     86 	if len(b) == 0 {
     87 		return
     88 	}
     89 	recordForPanic(b)
     90 	gp := getg()
     91 	if gp == nil || gp.writebuf == nil {
     92 		writeErr(b)
     93 		return
     94 	}
     95 
     96 	n := copy(gp.writebuf[len(gp.writebuf):cap(gp.writebuf)], b)
     97 	gp.writebuf = gp.writebuf[:len(gp.writebuf)+n]
     98 }
     99 
    100 func printsp() {
    101 	print(" ")
    102 }
    103 
    104 func printnl() {
    105 	print("\n")
    106 }
    107 
    108 func printbool(v bool) {
    109 	if v {
    110 		print("true")
    111 	} else {
    112 		print("false")
    113 	}
    114 }
    115 
    116 func printfloat(v float64) {
    117 	switch {
    118 	case v != v:
    119 		print("NaN")
    120 		return
    121 	case v+v == v && v > 0:
    122 		print("+Inf")
    123 		return
    124 	case v+v == v && v < 0:
    125 		print("-Inf")
    126 		return
    127 	}
    128 
    129 	const n = 7 // digits printed
    130 	var buf [n + 7]byte
    131 	buf[0] = '+'
    132 	e := 0 // exp
    133 	if v == 0 {
    134 		if 1/v < 0 {
    135 			buf[0] = '-'
    136 		}
    137 	} else {
    138 		if v < 0 {
    139 			v = -v
    140 			buf[0] = '-'
    141 		}
    142 
    143 		// normalize
    144 		for v >= 10 {
    145 			e++
    146 			v /= 10
    147 		}
    148 		for v < 1 {
    149 			e--
    150 			v *= 10
    151 		}
    152 
    153 		// round
    154 		h := 5.0
    155 		for i := 0; i < n; i++ {
    156 			h /= 10
    157 		}
    158 		v += h
    159 		if v >= 10 {
    160 			e++
    161 			v /= 10
    162 		}
    163 	}
    164 
    165 	// format +d.dddd+edd
    166 	for i := 0; i < n; i++ {
    167 		s := int(v)
    168 		buf[i+2] = byte(s + '0')
    169 		v -= float64(s)
    170 		v *= 10
    171 	}
    172 	buf[1] = buf[2]
    173 	buf[2] = '.'
    174 
    175 	buf[n+2] = 'e'
    176 	buf[n+3] = '+'
    177 	if e < 0 {
    178 		e = -e
    179 		buf[n+3] = '-'
    180 	}
    181 
    182 	buf[n+4] = byte(e/100) + '0'
    183 	buf[n+5] = byte(e/10)%10 + '0'
    184 	buf[n+6] = byte(e%10) + '0'
    185 	gwrite(buf[:])
    186 }
    187 
    188 func printcomplex(c complex128) {
    189 	print("(", real(c), imag(c), "i)")
    190 }
    191 
    192 func printuint(v uint64) {
    193 	var buf [100]byte
    194 	i := len(buf)
    195 	for i--; i > 0; i-- {
    196 		buf[i] = byte(v%10 + '0')
    197 		if v < 10 {
    198 			break
    199 		}
    200 		v /= 10
    201 	}
    202 	gwrite(buf[i:])
    203 }
    204 
    205 func printint(v int64) {
    206 	if v < 0 {
    207 		print("-")
    208 		v = -v
    209 	}
    210 	printuint(uint64(v))
    211 }
    212 
    213 func printhex(v uint64) {
    214 	const dig = "0123456789abcdef"
    215 	var buf [100]byte
    216 	i := len(buf)
    217 	for i--; i > 0; i-- {
    218 		buf[i] = dig[v%16]
    219 		if v < 16 {
    220 			break
    221 		}
    222 		v /= 16
    223 	}
    224 	i--
    225 	buf[i] = 'x'
    226 	i--
    227 	buf[i] = '0'
    228 	gwrite(buf[i:])
    229 }
    230 
    231 func printpointer(p unsafe.Pointer) {
    232 	printhex(uint64(uintptr(p)))
    233 }
    234 
    235 func printstring(s string) {
    236 	gwrite(bytes(s))
    237 }
    238 
    239 func printslice(s []byte) {
    240 	sp := (*slice)(unsafe.Pointer(&s))
    241 	print("[", len(s), "/", cap(s), "]")
    242 	printpointer(sp.array)
    243 }
    244 
    245 func printeface(e eface) {
    246 	print("(", e._type, ",", e.data, ")")
    247 }
    248 
    249 func printiface(i iface) {
    250 	print("(", i.tab, ",", i.data, ")")
    251 }
    252