...
Run Format

Source file src/runtime/print.go

  // Copyright 2009 The Go Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style
  // license that can be found in the LICENSE file.
  
  package runtime
  
  import (
  	"runtime/internal/atomic"
  	"unsafe"
  )
  
  // The compiler knows that a print of a value of this type
  // should use printhex instead of printuint (decimal).
  type hex uint64
  
  func bytes(s string) (ret []byte) {
  	rp := (*slice)(unsafe.Pointer(&ret))
  	sp := stringStructOf(&s)
  	rp.array = sp.str
  	rp.len = sp.len
  	rp.cap = sp.len
  	return
  }
  
  var (
  	// printBacklog is a circular buffer of messages written with the builtin
  	// print* functions, for use in postmortem analysis of core dumps.
  	printBacklog      [512]byte
  	printBacklogIndex int
  )
  
  // recordForPanic maintains a circular buffer of messages written by the
  // runtime leading up to a process crash, allowing the messages to be
  // extracted from a core dump.
  //
  // The text written during a process crash (following "panic" or "fatal
  // error") is not saved, since the goroutine stacks will generally be readable
  // from the runtime datastructures in the core file.
  func recordForPanic(b []byte) {
  	printlock()
  
  	if atomic.Load(&panicking) == 0 {
  		// Not actively crashing: maintain circular buffer of print output.
  		for i := 0; i < len(b); {
  			n := copy(printBacklog[printBacklogIndex:], b[i:])
  			i += n
  			printBacklogIndex += n
  			printBacklogIndex %= len(printBacklog)
  		}
  	}
  
  	printunlock()
  }
  
  var debuglock mutex
  
  // The compiler emits calls to printlock and printunlock around
  // the multiple calls that implement a single Go print or println
  // statement. Some of the print helpers (printsp, for example)
  // call print recursively. There is also the problem of a crash
  // happening during the print routines and needing to acquire
  // the print lock to print information about the crash.
  // For both these reasons, let a thread acquire the printlock 'recursively'.
  
  func printlock() {
  	mp := getg().m
  	mp.locks++ // do not reschedule between printlock++ and lock(&debuglock).
  	mp.printlock++
  	if mp.printlock == 1 {
  		lock(&debuglock)
  	}
  	mp.locks-- // now we know debuglock is held and holding up mp.locks for us.
  }
  
  func printunlock() {
  	mp := getg().m
  	mp.printlock--
  	if mp.printlock == 0 {
  		unlock(&debuglock)
  	}
  }
  
  // write to goroutine-local buffer if diverting output,
  // or else standard error.
  func gwrite(b []byte) {
  	if len(b) == 0 {
  		return
  	}
  	recordForPanic(b)
  	gp := getg()
  	if gp == nil || gp.writebuf == nil {
  		writeErr(b)
  		return
  	}
  
  	n := copy(gp.writebuf[len(gp.writebuf):cap(gp.writebuf)], b)
  	gp.writebuf = gp.writebuf[:len(gp.writebuf)+n]
  }
  
  func printsp() {
  	print(" ")
  }
  
  func printnl() {
  	print("\n")
  }
  
  func printbool(v bool) {
  	if v {
  		print("true")
  	} else {
  		print("false")
  	}
  }
  
  func printfloat(v float64) {
  	switch {
  	case v != v:
  		print("NaN")
  		return
  	case v+v == v && v > 0:
  		print("+Inf")
  		return
  	case v+v == v && v < 0:
  		print("-Inf")
  		return
  	}
  
  	const n = 7 // digits printed
  	var buf [n + 7]byte
  	buf[0] = '+'
  	e := 0 // exp
  	if v == 0 {
  		if 1/v < 0 {
  			buf[0] = '-'
  		}
  	} else {
  		if v < 0 {
  			v = -v
  			buf[0] = '-'
  		}
  
  		// normalize
  		for v >= 10 {
  			e++
  			v /= 10
  		}
  		for v < 1 {
  			e--
  			v *= 10
  		}
  
  		// round
  		h := 5.0
  		for i := 0; i < n; i++ {
  			h /= 10
  		}
  		v += h
  		if v >= 10 {
  			e++
  			v /= 10
  		}
  	}
  
  	// format +d.dddd+edd
  	for i := 0; i < n; i++ {
  		s := int(v)
  		buf[i+2] = byte(s + '0')
  		v -= float64(s)
  		v *= 10
  	}
  	buf[1] = buf[2]
  	buf[2] = '.'
  
  	buf[n+2] = 'e'
  	buf[n+3] = '+'
  	if e < 0 {
  		e = -e
  		buf[n+3] = '-'
  	}
  
  	buf[n+4] = byte(e/100) + '0'
  	buf[n+5] = byte(e/10)%10 + '0'
  	buf[n+6] = byte(e%10) + '0'
  	gwrite(buf[:])
  }
  
  func printcomplex(c complex128) {
  	print("(", real(c), imag(c), "i)")
  }
  
  func printuint(v uint64) {
  	var buf [100]byte
  	i := len(buf)
  	for i--; i > 0; i-- {
  		buf[i] = byte(v%10 + '0')
  		if v < 10 {
  			break
  		}
  		v /= 10
  	}
  	gwrite(buf[i:])
  }
  
  func printint(v int64) {
  	if v < 0 {
  		print("-")
  		v = -v
  	}
  	printuint(uint64(v))
  }
  
  func printhex(v uint64) {
  	const dig = "0123456789abcdef"
  	var buf [100]byte
  	i := len(buf)
  	for i--; i > 0; i-- {
  		buf[i] = dig[v%16]
  		if v < 16 {
  			break
  		}
  		v /= 16
  	}
  	i--
  	buf[i] = 'x'
  	i--
  	buf[i] = '0'
  	gwrite(buf[i:])
  }
  
  func printpointer(p unsafe.Pointer) {
  	printhex(uint64(uintptr(p)))
  }
  
  func printstring(s string) {
  	gwrite(bytes(s))
  }
  
  func printslice(s []byte) {
  	sp := (*slice)(unsafe.Pointer(&s))
  	print("[", len(s), "/", cap(s), "]")
  	printpointer(sp.array)
  }
  
  func printeface(e eface) {
  	print("(", e._type, ",", e.data, ")")
  }
  
  func printiface(i iface) {
  	print("(", i.tab, ",", i.data, ")")
  }
  

View as plain text