diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2017-06-17 12:47:35 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2017-06-17 14:41:15 +0200 |
| commit | e8e63830a60fc048df976188bf726abc32045162 (patch) | |
| tree | 9e38c6b9d3e6cbaeba29cc5b29ed36aac0706d3d /pkg/ipc/gate.go | |
| parent | baad3b4b027658f49ba318c41dfc745788ba87d1 (diff) | |
pkg/ipc: move from ipc
Diffstat (limited to 'pkg/ipc/gate.go')
| -rw-r--r-- | pkg/ipc/gate.go | 76 |
1 files changed, 76 insertions, 0 deletions
diff --git a/pkg/ipc/gate.go b/pkg/ipc/gate.go new file mode 100644 index 000000000..b1b1f1fc8 --- /dev/null +++ b/pkg/ipc/gate.go @@ -0,0 +1,76 @@ +// Copyright 2015 syzkaller project authors. All rights reserved. +// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. + +package ipc + +import ( + "sync" +) + +// Gate limits concurrency level and window to the given value. +// Limitation of concurrency window means that if a very old activity is still +// running it will not let new activities to start even if concurrency level is low. +type Gate struct { + cv *sync.Cond + busy []bool + pos int + running int + stop bool + f func() +} + +// If f is not nil, it will be called after each batch of c activities. +func NewGate(c int, f func()) *Gate { + return &Gate{ + cv: sync.NewCond(new(sync.Mutex)), + busy: make([]bool, c), + f: f, + } +} + +func (g *Gate) Enter() int { + g.cv.L.Lock() + for g.busy[g.pos] || g.stop { + g.cv.Wait() + } + idx := g.pos + g.pos++ + if g.pos >= len(g.busy) { + g.pos = 0 + } + g.busy[idx] = true + g.running++ + if g.running > len(g.busy) { + panic("broken gate") + } + g.cv.L.Unlock() + return idx +} + +func (g *Gate) Leave(idx int) { + g.cv.L.Lock() + if !g.busy[idx] { + panic("broken gate") + } + g.busy[idx] = false + g.running-- + if g.running < 0 { + panic("broken gate") + } + if idx == 0 && g.f != nil { + if g.stop { + panic("broken gate") + } + g.stop = true + for g.running != 0 { + g.cv.Wait() + } + g.stop = false + g.f() + g.cv.Broadcast() + } + if idx == g.pos && !g.stop || g.running == 0 && g.stop { + g.cv.Broadcast() + } + g.cv.L.Unlock() +} |
