mirror of https://github.com/docker/docs.git
Merge pull request #18196 from cpuguy83/18190_on_your_marks
Fix race in locker call to `dec()`
This commit is contained in:
commit
ac055a7d54
|
@ -32,22 +32,23 @@ type Locker struct {
|
||||||
type lockCtr struct {
|
type lockCtr struct {
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
// waiters is the number of waiters waiting to acquire the lock
|
// waiters is the number of waiters waiting to acquire the lock
|
||||||
waiters uint32
|
// this is int32 instead of uint32 so we can add `-1` in `dec()`
|
||||||
|
waiters int32
|
||||||
}
|
}
|
||||||
|
|
||||||
// inc increments the number of waiters waiting for the lock
|
// inc increments the number of waiters waiting for the lock
|
||||||
func (l *lockCtr) inc() {
|
func (l *lockCtr) inc() {
|
||||||
atomic.AddUint32(&l.waiters, 1)
|
atomic.AddInt32(&l.waiters, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// dec decrements the number of waiters wating on the lock
|
// dec decrements the number of waiters wating on the lock
|
||||||
func (l *lockCtr) dec() {
|
func (l *lockCtr) dec() {
|
||||||
atomic.AddUint32(&l.waiters, ^uint32(l.waiters-1))
|
atomic.AddInt32(&l.waiters, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// count gets the current number of waiters
|
// count gets the current number of waiters
|
||||||
func (l *lockCtr) count() uint32 {
|
func (l *lockCtr) count() int32 {
|
||||||
return atomic.LoadUint32(&l.waiters)
|
return atomic.LoadInt32(&l.waiters)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock locks the mutex
|
// Lock locks the mutex
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package locker
|
package locker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -89,3 +90,35 @@ func TestLockerUnlock(t *testing.T) {
|
||||||
t.Fatalf("lock should not be blocked")
|
t.Fatalf("lock should not be blocked")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLockerConcurrency(t *testing.T) {
|
||||||
|
l := New()
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for i := 0; i <= 10000; i++ {
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
l.Lock("test")
|
||||||
|
// if there is a concurrency issue, will very likely panic here
|
||||||
|
l.Unlock("test")
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
chDone := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
wg.Wait()
|
||||||
|
close(chDone)
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-chDone:
|
||||||
|
case <-time.After(10 * time.Second):
|
||||||
|
t.Fatal("timeout waiting for locks to complete")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since everything has unlocked this should not exist anymore
|
||||||
|
if ctr, exists := l.locks["test"]; exists {
|
||||||
|
t.Fatalf("lock should not exist: %v", ctr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue