Merge pull request #2299 from dmage/regulator

Fix signalling Wait in regulator.enter
This commit is contained in:
Aaron Lehmann 2017-06-23 15:25:35 -07:00 committed by GitHub
commit caa175c710
2 changed files with 68 additions and 5 deletions

View file

@ -38,11 +38,7 @@ func (r *regulator) enter() {
func (r *regulator) exit() {
r.L.Lock()
// We only need to signal to a waiting FS operation if we're already at the
// limit of threads used
if r.available == 0 {
r.Signal()
}
r.available++
r.L.Unlock()
}

View file

@ -0,0 +1,67 @@
package base
import (
"sync"
"testing"
"time"
)
func TestRegulatorEnterExit(t *testing.T) {
const limit = 500
r := NewRegulator(nil, limit).(*regulator)
for try := 0; try < 50; try++ {
run := make(chan struct{})
var firstGroupReady sync.WaitGroup
var firstGroupDone sync.WaitGroup
firstGroupReady.Add(limit)
firstGroupDone.Add(limit)
for i := 0; i < limit; i++ {
go func() {
r.enter()
firstGroupReady.Done()
<-run
r.exit()
firstGroupDone.Done()
}()
}
firstGroupReady.Wait()
// now we exhausted all the limit, let's run a little bit more
var secondGroupReady sync.WaitGroup
var secondGroupDone sync.WaitGroup
for i := 0; i < 50; i++ {
secondGroupReady.Add(1)
secondGroupDone.Add(1)
go func() {
secondGroupReady.Done()
r.enter()
r.exit()
secondGroupDone.Done()
}()
}
secondGroupReady.Wait()
// allow the first group to return resources
close(run)
done := make(chan struct{})
go func() {
secondGroupDone.Wait()
close(done)
}()
select {
case <-done:
case <-time.After(5 * time.Second):
t.Fatal("some r.enter() are still locked")
}
firstGroupDone.Wait()
if r.available != limit {
t.Fatalf("r.available: got %d, want %d", r.available, limit)
}
}
}