Skip to content

Commit 19495eb

Browse files
committed
Remove possible races (#4070)
1 parent bacc860 commit 19495eb

File tree

3 files changed

+39
-39
lines changed

3 files changed

+39
-39
lines changed

src/core.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,9 @@ func Run(opts *Options) (int, error) {
172172
return chunkList.Push(data)
173173
}, eventBox, executor, opts.ReadZero, opts.Filter == nil)
174174

175-
go reader.ReadSource(opts.Input, opts.WalkerRoot, opts.WalkerOpts, opts.WalkerSkip, initialReload, initialEnv)
175+
readyChan := make(chan bool)
176+
go reader.ReadSource(opts.Input, opts.WalkerRoot, opts.WalkerOpts, opts.WalkerSkip, initialReload, initialEnv, readyChan)
177+
<-readyChan
176178
}
177179

178180
// Matcher
@@ -224,7 +226,7 @@ func Run(opts *Options) (int, error) {
224226
}
225227
return false
226228
}, eventBox, executor, opts.ReadZero, false)
227-
reader.ReadSource(opts.Input, opts.WalkerRoot, opts.WalkerOpts, opts.WalkerSkip, initialReload, initialEnv)
229+
reader.ReadSource(opts.Input, opts.WalkerRoot, opts.WalkerOpts, opts.WalkerSkip, initialReload, initialEnv, nil)
228230
} else {
229231
eventBox.Unwatch(EvtReadNew)
230232
eventBox.WaitFor(EvtReadFin)
@@ -299,7 +301,9 @@ func Run(opts *Options) (int, error) {
299301
itemIndex = 0
300302
inputRevision.bumpMajor()
301303
header = make([]string, 0, opts.HeaderLines)
302-
reader.restart(command, environ)
304+
readyChan := make(chan bool)
305+
go reader.restart(command, environ, readyChan)
306+
<-readyChan
303307
}
304308

305309
exitCode := ExitOk

src/reader.go

Lines changed: 24 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"io"
77
"io/fs"
88
"os"
9-
"os/exec"
109
"path/filepath"
1110
"sync"
1211
"sync/atomic"
@@ -98,20 +97,14 @@ func (r *Reader) terminate() {
9897
r.mutex.Unlock()
9998
}
10099

101-
func (r *Reader) restart(command commandSpec, environ []string) {
100+
func (r *Reader) restart(command commandSpec, environ []string, readyChan chan bool) {
102101
r.event = int32(EvtReady)
103102
r.startEventPoller()
104-
105-
r.mutex.Lock()
106-
defer r.mutex.Unlock()
107-
108-
if exec, execOut := r.startCommand(command.command, environ); exec != nil {
109-
go func() {
110-
success := r.feedCommandOutput(exec, execOut)
111-
r.fin(success)
112-
removeFiles(command.tempFiles)
113-
}()
114-
}
103+
success := r.readFromCommand(command.command, environ, func() {
104+
readyChan <- true
105+
})
106+
r.fin(success)
107+
removeFiles(command.tempFiles)
115108
}
116109

117110
func (r *Reader) readChannel(inputChan chan string) bool {
@@ -128,21 +121,29 @@ func (r *Reader) readChannel(inputChan chan string) bool {
128121
}
129122

130123
// ReadSource reads data from the default command or from standard input
131-
func (r *Reader) ReadSource(inputChan chan string, root string, opts walkerOpts, ignores []string, initCmd string, initEnv []string) {
124+
func (r *Reader) ReadSource(inputChan chan string, root string, opts walkerOpts, ignores []string, initCmd string, initEnv []string, readyChan chan bool) {
132125
r.startEventPoller()
133126
var success bool
127+
signalReady := func() {
128+
if readyChan != nil {
129+
readyChan <- true
130+
}
131+
}
134132
if inputChan != nil {
133+
signalReady()
135134
success = r.readChannel(inputChan)
136135
} else if len(initCmd) > 0 {
137-
success = r.readFromCommand(initCmd, initEnv)
136+
success = r.readFromCommand(initCmd, initEnv, signalReady)
138137
} else if util.IsTty(os.Stdin) {
139138
cmd := os.Getenv("FZF_DEFAULT_COMMAND")
140139
if len(cmd) == 0 {
140+
signalReady()
141141
success = r.readFiles(root, opts, ignores)
142142
} else {
143-
success = r.readFromCommand(cmd, initEnv)
143+
success = r.readFromCommand(cmd, initEnv, signalReady)
144144
}
145145
} else {
146+
signalReady()
146147
success = r.readFromStdin()
147148
}
148149
r.fin(success)
@@ -304,8 +305,9 @@ func (r *Reader) readFiles(root string, opts walkerOpts, ignores []string) bool
304305
return fastwalk.Walk(&conf, root, fn) == nil
305306
}
306307

307-
// Should be called with the mutex held
308-
func (r *Reader) startCommand(command string, environ []string) (*exec.Cmd, io.ReadCloser) {
308+
func (r *Reader) readFromCommand(command string, environ []string, signalReady func()) bool {
309+
r.mutex.Lock()
310+
309311
r.termFunc = nil
310312
r.command = &command
311313
exec := r.executor.ExecCommand(command, true)
@@ -314,7 +316,8 @@ func (r *Reader) startCommand(command string, environ []string) (*exec.Cmd, io.R
314316
}
315317
execOut, err := exec.StdoutPipe()
316318
if err != nil || exec.Start() != nil {
317-
return nil, nil
319+
r.mutex.Unlock()
320+
return false
318321
}
319322

320323
// Function to call to terminate the running command
@@ -323,20 +326,9 @@ func (r *Reader) startCommand(command string, environ []string) (*exec.Cmd, io.R
323326
util.KillCommand(exec)
324327
}
325328

326-
return exec, execOut
327-
}
329+
signalReady()
330+
r.mutex.Unlock()
328331

329-
func (r *Reader) feedCommandOutput(exec *exec.Cmd, execOut io.ReadCloser) bool {
330332
r.feed(execOut)
331333
return exec.Wait() == nil
332334
}
333-
334-
func (r *Reader) readFromCommand(command string, environ []string) bool {
335-
r.mutex.Lock()
336-
exec, execOut := r.startCommand(command, environ)
337-
r.mutex.Unlock()
338-
if exec == nil {
339-
return false
340-
}
341-
return r.feedCommandOutput(exec, execOut)
342-
}

src/reader_test.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,12 @@ func TestReadFromCommand(t *testing.T) {
2323
}
2424

2525
// Normal command
26-
reader.fin(reader.readFromCommand(`echo abc&&echo def`, nil))
27-
if len(strs) != 2 || strs[0] != "abc" || strs[1] != "def" {
26+
counter := 0
27+
ready := func() {
28+
counter++
29+
}
30+
reader.fin(reader.readFromCommand(`echo abc&&echo def`, nil, ready))
31+
if len(strs) != 2 || strs[0] != "abc" || strs[1] != "def" || counter != 1 {
2832
t.Errorf("%s", strs)
2933
}
3034

@@ -48,9 +52,9 @@ func TestReadFromCommand(t *testing.T) {
4852
reader.startEventPoller()
4953

5054
// Failing command
51-
reader.fin(reader.readFromCommand(`no-such-command`, nil))
55+
reader.fin(reader.readFromCommand(`no-such-command`, nil, ready))
5256
strs = []string{}
53-
if len(strs) > 0 {
57+
if len(strs) > 0 || counter != 2 {
5458
t.Errorf("%s", strs)
5559
}
5660

0 commit comments

Comments
 (0)