Skip to content

Commit 8147801

Browse files
committed
imports: wait for fastWalk workers to finish before returning (take 2)
This is Joël Stemmer's https://golang.org/cl/40092 again, but with a fix to prevent workers from deadlocking on send if the caller had already started to shut down. See: golang/go#16399 (comment) Updates golang/go#16399 Fixes golang/go#20109 (it looks like) Change-Id: I3d1cf6f24563d02e1369a4496c2d37dcc1f5e5b8 Reviewed-on: https://go-review.googlesource.com/41681 Run-TryBot: Brad Fitzpatrick <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Joël Stemmer <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]>
1 parent 75e5ff3 commit 8147801

File tree

1 file changed

+19
-4
lines changed

1 file changed

+19
-4
lines changed

imports/fastwalk.go

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"os"
2020
"path/filepath"
2121
"runtime"
22+
"sync"
2223
)
2324

2425
// traverseLink is a sentinel error for fastWalk, similar to filepath.SkipDir.
@@ -48,6 +49,13 @@ func fastWalk(root string, walkFn func(path string, typ os.FileMode) error) erro
4849
if n := runtime.NumCPU(); n > numWorkers {
4950
numWorkers = n
5051
}
52+
53+
// Make sure to wait for all workers to finish, otherwise
54+
// walkFn could still be called after returning. This Wait call
55+
// runs after close(e.donec) below.
56+
var wg sync.WaitGroup
57+
defer wg.Wait()
58+
5159
w := &walker{
5260
fn: walkFn,
5361
enqueuec: make(chan walkItem, numWorkers), // buffered for performance
@@ -58,9 +66,10 @@ func fastWalk(root string, walkFn func(path string, typ os.FileMode) error) erro
5866
resc: make(chan error, numWorkers),
5967
}
6068
defer close(w.donec)
61-
// TODO(bradfitz): start the workers as needed? maybe not worth it.
69+
6270
for i := 0; i < numWorkers; i++ {
63-
go w.doWork()
71+
wg.Add(1)
72+
go w.doWork(&wg)
6473
}
6574
todo := []walkItem{{dir: root}}
6675
out := 0
@@ -103,13 +112,18 @@ func fastWalk(root string, walkFn func(path string, typ os.FileMode) error) erro
103112

104113
// doWork reads directories as instructed (via workc) and runs the
105114
// user's callback function.
106-
func (w *walker) doWork() {
115+
func (w *walker) doWork(wg *sync.WaitGroup) {
116+
defer wg.Done()
107117
for {
108118
select {
109119
case <-w.donec:
110120
return
111121
case it := <-w.workc:
112-
w.resc <- w.walk(it.dir, !it.callbackDone)
122+
select {
123+
case <-w.donec:
124+
return
125+
case w.resc <- w.walk(it.dir, !it.callbackDone):
126+
}
113127
}
114128
}
115129
}
@@ -157,6 +171,7 @@ func (w *walker) onDirEnt(dirName, baseName string, typ os.FileMode) error {
157171
}
158172
return err
159173
}
174+
160175
func (w *walker) walk(root string, runUserCallback bool) error {
161176
if runUserCallback {
162177
err := w.fn(root, os.ModeDir)

0 commit comments

Comments
 (0)