diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2016-03-02 11:24:45 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2016-03-10 17:47:13 +0100 |
| commit | 9851bc6a97a1bed0a5ff45aae727bfe6760f5b93 (patch) | |
| tree | a67b72991971658a00a959ee8c2f545c0852e38c /ipc | |
| parent | 094d49fe0c7597c2a679c8e0d57f77215fa6a1e3 (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.go | 42 | ||||
| -rw-r--r-- | ipc/ipc.go | 2 |
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) { |
