aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2011-02-11 17:47:17 -0500
committerRuss Cox <rsc@golang.org>2011-02-11 17:47:17 -0500
commit26880d7e034bcfd3ca45121148a3f7443409b39e (patch)
treeb287f6636d4c1e912b27b805ff673da9322e07c1
parentca5179d3f6889185f2aa3fb985f34a963015d133 (diff)
downloadgo-26880d7e034bcfd3ca45121148a3f7443409b39e.tar.gz
go-26880d7e034bcfd3ca45121148a3f7443409b39e.zip
sync: check Unlock of unlocked Mutex
R=r, adg CC=golang-dev https://golang.org/cl/4180044
-rw-r--r--src/pkg/sync/mutex.go7
-rw-r--r--src/pkg/sync/mutex_test.go13
2 files changed, 19 insertions, 1 deletions
diff --git a/src/pkg/sync/mutex.go b/src/pkg/sync/mutex.go
index 6c8a5d51d4..2a1270b9c4 100644
--- a/src/pkg/sync/mutex.go
+++ b/src/pkg/sync/mutex.go
@@ -53,9 +53,14 @@ func (m *Mutex) Lock() {
// It is allowed for one goroutine to lock a Mutex and then
// arrange for another goroutine to unlock it.
func (m *Mutex) Unlock() {
- if xadd(&m.key, -1) == 0 {
+ switch v := xadd(&m.key, -1); {
+ case v == 0:
// changed from 1 to 0; no contention
return
+ case int32(v) == -1:
+ // changed from 0 to -1: wasn't locked
+ // (or there are 4 billion goroutines waiting)
+ panic("sync: unlock of unlocked mutex")
}
runtime.Semrelease(&m.sema)
}
diff --git a/src/pkg/sync/mutex_test.go b/src/pkg/sync/mutex_test.go
index d0e048ed7a..f5c20ca49b 100644
--- a/src/pkg/sync/mutex_test.go
+++ b/src/pkg/sync/mutex_test.go
@@ -89,3 +89,16 @@ func BenchmarkContendedMutex(b *testing.B) {
<-c
<-c
}
+
+func TestMutexPanic(t *testing.T) {
+ defer func() {
+ if recover() == nil {
+ t.Fatalf("unlock of unlocked mutex did not panic")
+ }
+ }()
+
+ var mu Mutex
+ mu.Lock()
+ mu.Unlock()
+ mu.Unlock()
+}