aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/trace
diff options
context:
space:
mode:
authorRhys Hiltner <rhys@justin.tv>2019-12-17 16:40:46 -0800
committerAustin Clements <austin@google.com>2020-01-02 20:13:03 +0000
commita4c579e8f7c8129b2c27779f206ebd2c9b393633 (patch)
treedfe75aa1cb160812d5acc74bf6572983574be8d1 /src/cmd/trace
parentbf268472408b0f46767d46ae1d14439e5eb84014 (diff)
downloadgo-a4c579e8f7c8129b2c27779f206ebd2c9b393633.tar.gz
go-a4c579e8f7c8129b2c27779f206ebd2c9b393633.zip
runtime: emit trace event in direct semaphore handoff
When a goroutine yields the remainder of its time to another goroutine during direct semaphore handoff (as in an Unlock of a sync.Mutex in starvation mode), it needs to signal that change to the execution tracer. The discussion in CL 200577 didn't reach consensus on how best to describe that, but pointed out that "traceEvGoSched / goroutine calls Gosched" could be confusing. Emit a "traceEvGoPreempt / goroutine is preempted" event in this case, to allow the execution tracer to find a consistent event ordering without being both specific and inaccurate about why the active goroutine has changed. Fixes #36186 Change-Id: Ic4ade19325126db2599aff6aba7cba028bb0bee9 Reviewed-on: https://go-review.googlesource.com/c/go/+/211797 Run-TryBot: Dan Scales <danscales@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Austin Clements <austin@google.com>
Diffstat (limited to 'src/cmd/trace')
-rw-r--r--src/cmd/trace/trace_test.go33
1 files changed, 33 insertions, 0 deletions
diff --git a/src/cmd/trace/trace_test.go b/src/cmd/trace/trace_test.go
index 9e90f50d4b..ef2d06c961 100644
--- a/src/cmd/trace/trace_test.go
+++ b/src/cmd/trace/trace_test.go
@@ -12,7 +12,9 @@ import (
"io/ioutil"
rtrace "runtime/trace"
"strings"
+ "sync"
"testing"
+ "time"
)
// stacks is a fake stack map populated for test.
@@ -233,3 +235,34 @@ func TestFoo(t *testing.T) {
}
}
+
+func TestDirectSemaphoreHandoff(t *testing.T) {
+ prog0 := func() {
+ var mu sync.Mutex
+ var wg sync.WaitGroup
+ mu.Lock()
+ // This is modeled after src/sync/mutex_test.go to trigger Mutex
+ // starvation mode, in which the goroutine that calls Unlock hands off
+ // both the semaphore and its remaining time slice. See issue 36186.
+ for i := 0; i < 2; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ for i := 0; i < 100; i++ {
+ mu.Lock()
+ time.Sleep(100 * time.Microsecond)
+ mu.Unlock()
+ }
+ }()
+ }
+ mu.Unlock()
+ wg.Wait()
+ }
+ if err := traceProgram(t, prog0, "TestDirectSemaphoreHandoff"); err != nil {
+ t.Fatalf("failed to trace the program: %v", err)
+ }
+ _, err := parseTrace()
+ if err != nil {
+ t.Fatalf("failed to parse the trace: %v", err)
+ }
+}