Commit 75d3f62b authored by Russ Cox's avatar Russ Cox

[dev.garbage] cmd/gc, runtime: add locks around print statements

Now each C printf, Go print, or Go println is guaranteed
not to be interleaved with other calls of those functions.
This should help when debugging concurrent failures.

LGTM=rlh
R=rlh
CC=golang-codereviews
https://golang.org/cl/169120043
parent 91658f93
......@@ -24,6 +24,8 @@ char *runtimeimport =
"func @\"\".printslice (? any)\n"
"func @\"\".printnl ()\n"
"func @\"\".printsp ()\n"
"func @\"\".printlock ()\n"
"func @\"\".printunlock ()\n"
"func @\"\".concatstring2 (? string, ? string) (? string)\n"
"func @\"\".concatstring3 (? string, ? string, ? string) (? string)\n"
"func @\"\".concatstring4 (? string, ? string, ? string, ? string) (? string)\n"
......
......@@ -1464,6 +1464,7 @@ void walk(Node *fn);
void walkexpr(Node **np, NodeList **init);
void walkexprlist(NodeList *l, NodeList **init);
void walkexprlistsafe(NodeList *l, NodeList **init);
void walkexprlistcheap(NodeList *l, NodeList **init);
void walkstmt(Node **np);
void walkstmtlist(NodeList *l);
Node* conv(Node*, Type*);
......
......@@ -36,6 +36,8 @@ func printeface(any)
func printslice(any)
func printnl()
func printsp()
func printlock()
func printunlock()
func concatstring2(string, string) string
func concatstring3(string, string, string) string
......
......@@ -363,6 +363,15 @@ walkexprlistsafe(NodeList *l, NodeList **init)
}
}
void
walkexprlistcheap(NodeList *l, NodeList **init)
{
for(; l; l=l->next) {
l->n = cheapexpr(l->n, init);
walkexpr(&l->n, init);
}
}
void
walkexpr(Node **np, NodeList **init)
{
......@@ -1773,6 +1782,11 @@ walkprint(Node *nn, NodeList **init)
calls = nil;
notfirst = 0;
// Hoist all the argument evaluation up before the lock.
walkexprlistcheap(all, init);
calls = list(calls, mkcall("printlock", T, init));
for(l=all; l; l=l->next) {
if(notfirst) {
calls = list(calls, mkcall("printsp", T, init));
......@@ -1853,6 +1867,9 @@ walkprint(Node *nn, NodeList **init)
if(op == OPRINTN)
calls = list(calls, mkcall("printnl", T, nil));
calls = list(calls, mkcall("printunlock", T, init));
typechecklist(calls, Etop);
walkexprlist(calls, init);
......
......@@ -41,7 +41,31 @@ func snprintf(dst *byte, n int32, s *byte) {
gp.writebuf = nil
}
//var debuglock mutex
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.printlock++
if mp.printlock == 1 {
lock(&debuglock)
}
}
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.
......@@ -80,7 +104,7 @@ func printnl() {
// Very simple printf. Only for debugging prints.
// Do not add to this without checking with Rob.
func vprintf(str string, arg unsafe.Pointer) {
//lock(&debuglock);
printlock()
s := bytes(str)
start := 0
......@@ -160,7 +184,7 @@ func vprintf(str string, arg unsafe.Pointer) {
gwrite(s[start:i])
}
//unlock(&debuglock);
printunlock()
}
func printpc(p unsafe.Pointer) {
......
......@@ -345,6 +345,7 @@ struct M
int32 helpgc;
bool spinning; // M is out of work and is actively looking for work
bool blocked; // M is blocked on a Note
int8 printlock;
uint32 fastrand;
uint64 ncgocall; // number of cgo calls in total
int32 ncgo; // number of cgo calls currently in progress
......
This diff is collapsed.
......@@ -12,6 +12,8 @@ package main
// issue 8142: lost 'addrtaken' bit on inlined variables.
// no inlining in this test, so just checking that non-inlined works.
func printnl()
type T40 struct {
m map[int]int
}
......@@ -24,7 +26,7 @@ func newT40() *T40 {
func bad40() {
t := newT40() // ERROR "live at call to makemap: ret"
println() // ERROR "live at call to printnl: ret"
printnl() // ERROR "live at call to printnl: ret"
_ = t
}
......@@ -32,6 +34,6 @@ func good40() {
ret := T40{}
ret.m = make(map[int]int) // ERROR "live at call to makemap: ret"
t := &ret
println() // ERROR "live at call to printnl: ret"
printnl() // ERROR "live at call to printnl: ret"
_ = t
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment