From 9851bc6a97a1bed0a5ff45aae727bfe6760f5b93 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Wed, 2 Mar 2016 11:24:45 +0100 Subject: 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. --- ipc/gate.go | 42 ++++++++++++++++++++++++++++++++---------- ipc/ipc.go | 2 +- 2 files changed, 33 insertions(+), 11 deletions(-) (limited to 'ipc') 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) { -- cgit mrf-deployment