github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/src/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  	"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  }