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  }