aboutsummaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2016-03-02 11:24:45 +0100
committerDmitry Vyukov <dvyukov@google.com>2016-03-10 17:47:13 +0100
commit9851bc6a97a1bed0a5ff45aae727bfe6760f5b93 (patch)
treea67b72991971658a00a959ee8c2f545c0852e38c /ipc
parent094d49fe0c7597c2a679c8e0d57f77215fa6a1e3 (diff)
fuzzer: improve kmemleak logic
Kmemleak has false positives. To mitigate most of them, it checksums potentially leaked objects, and reports them only on the next scan iff the checksum does not change. Because of that we do the following intricate dance: Scan, sleep, scan again. At this point we can get some leaks. If there are leaks, we sleep and scan again, this can remove false leaks. Then, read kmemleak again. If we get leaks now, then hopefully these are true positives during the previous testing cycle.
Diffstat (limited to 'ipc')
-rw-r--r--ipc/gate.go42
-rw-r--r--ipc/ipc.go2
2 files changed, 33 insertions, 11 deletions
diff --git a/ipc/gate.go b/ipc/gate.go
index 941dc9f2a..b1b1f1fc8 100644
--- a/ipc/gate.go
+++ b/ipc/gate.go
@@ -11,21 +11,26 @@ import (
// 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
+ cv *sync.Cond
+ busy []bool
+ pos int
+ running int
+ stop bool
+ f func()
}
-func NewGate(c int) *Gate {
+// 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] {
+ for g.busy[g.pos] || g.stop {
g.cv.Wait()
}
idx := g.pos
@@ -34,20 +39,37 @@ func (g *Gate) Enter() int {
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, f func()) {
+func (g *Gate) Leave(idx int) {
g.cv.L.Lock()
if !g.busy[idx] {
panic("broken gate")
}
- if f != nil {
- f()
- }
g.busy[idx] = false
- if idx == g.pos {
+ 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()
diff --git a/ipc/ipc.go b/ipc/ipc.go
index 6f591961f..92c1a253e 100644
--- a/ipc/ipc.go
+++ b/ipc/ipc.go
@@ -54,7 +54,7 @@ var (
// Executor protects against most hangs, so we use quite large timeout here.
// Executor can be slow due to global locks in namespaces and other things,
// so let's better wait than report false misleading crashes.
- flagTimeout = flag.Duration("timeout", 1*time.Minute, "execution timeout")
+ flagTimeout = flag.Duration("timeout", 1*time.Minute, "execution timeout")
)
func DefaultFlags() (uint64, time.Duration) {