Skip to content

Commit ad8b87b

Browse files
committed
Add Wait to binaryProcessor
Add exported `Wait(ctx context.Context) error` interface that waits on the underlying command (or context cancellation) and returns the error. This fixes a race condition between `.wait()` and `.Err error`: containerd#6914 Signed-off-by: Hamza El-Saawy <[email protected]>
1 parent 1e749e5 commit ad8b87b

2 files changed

Lines changed: 32 additions & 0 deletions

File tree

diff/stream_unix.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ func NewBinaryProcessor(ctx context.Context, imt, rmt string, stream StreamProce
8989
r: r,
9090
mt: rmt,
9191
stderr: stderr,
92+
done: make(chan struct{}),
9293
}
9394
go p.wait()
9495

@@ -111,6 +112,11 @@ type binaryProcessor struct {
111112

112113
mu sync.Mutex
113114
err error
115+
116+
// There is a race condition between waiting on c.cmd.Wait() and setting c.err within
117+
// c.wait(), and reading that value from c.Err().
118+
// Use done to wait for the returned error to be captured and set.
119+
done chan struct{}
114120
}
115121

116122
func (c *binaryProcessor) Err() error {
@@ -127,6 +133,16 @@ func (c *binaryProcessor) wait() {
127133
c.mu.Unlock()
128134
}
129135
}
136+
close(c.done)
137+
}
138+
139+
func (c *binaryProcessor) Wait(ctx context.Context) error {
140+
select {
141+
case <-c.done:
142+
return c.Err()
143+
case <-ctx.Done():
144+
return ctx.Err()
145+
}
130146
}
131147

132148
func (c *binaryProcessor) File() *os.File {

diff/stream_windows.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ func NewBinaryProcessor(ctx context.Context, imt, rmt string, stream StreamProce
9898
r: r,
9999
mt: rmt,
100100
stderr: stderr,
101+
done: make(chan struct{}),
101102
}
102103
go p.wait()
103104

@@ -117,6 +118,11 @@ type binaryProcessor struct {
117118

118119
mu sync.Mutex
119120
err error
121+
122+
// There is a race condition between waiting on c.cmd.Wait() and setting c.err within
123+
// c.wait(), and reading that value from c.Err().
124+
// Use done to wait for the returned error to be captured and set.
125+
done chan struct{}
120126
}
121127

122128
func (c *binaryProcessor) Err() error {
@@ -133,6 +139,16 @@ func (c *binaryProcessor) wait() {
133139
c.mu.Unlock()
134140
}
135141
}
142+
close(c.done)
143+
}
144+
145+
func (c *binaryProcessor) Wait(ctx context.Context) error {
146+
select {
147+
case <-c.done:
148+
return c.Err()
149+
case <-ctx.Done():
150+
return ctx.Err()
151+
}
136152
}
137153

138154
func (c *binaryProcessor) File() *os.File {

0 commit comments

Comments
 (0)