1
0
mirror of https://github.com/golang/go synced 2024-11-18 20:04:52 -07:00

imports: wait for fastWalk workers to finish before returning

In some cases walkFn is being called after the fastWalk function has
returned. This often happens when an error was encountered early on in
scanning directories with many entries.

It is caused by fastWalk not waiting for its workers to complete their
work. A sync.WaitGroup is used to wait for all workers to finish when
the function returns.

Updates golang/go#16399

Change-Id: I695d30c18e4878b789520b9d8a650f9688d896ac
Reviewed-on: https://go-review.googlesource.com/40092
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
Joël Stemmer 2017-04-08 23:55:30 +01:00 committed by Brad Fitzpatrick
parent 24acc66eab
commit 4436e54754

View File

@ -19,6 +19,7 @@ import (
"os"
"path/filepath"
"runtime"
"sync"
)
// traverseLink is a sentinel error for fastWalk, similar to filepath.SkipDir.
@ -48,6 +49,12 @@ func fastWalk(root string, walkFn func(path string, typ os.FileMode) error) erro
if n := runtime.NumCPU(); n > numWorkers {
numWorkers = n
}
// Make sure to wait for all workers to finish, otherwise walkFn could
// still be called after returning.
var wg sync.WaitGroup
defer wg.Wait()
w := &walker{
fn: walkFn,
enqueuec: make(chan walkItem, numWorkers), // buffered for performance
@ -60,7 +67,8 @@ func fastWalk(root string, walkFn func(path string, typ os.FileMode) error) erro
defer close(w.donec)
// TODO(bradfitz): start the workers as needed? maybe not worth it.
for i := 0; i < numWorkers; i++ {
go w.doWork()
wg.Add(1)
go w.doWork(&wg)
}
todo := []walkItem{{dir: root}}
out := 0
@ -103,7 +111,8 @@ func fastWalk(root string, walkFn func(path string, typ os.FileMode) error) erro
// doWork reads directories as instructed (via workc) and runs the
// user's callback function.
func (w *walker) doWork() {
func (w *walker) doWork(wg *sync.WaitGroup) {
defer wg.Done()
for {
select {
case <-w.donec: