Merge pull request #29424 from tonistiigi/fix-sdin-close
Fix race on sending stdin close event
diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go
index 3a16abf..d63510b 100644
--- a/integration-cli/docker_cli_run_test.go
+++ b/integration-cli/docker_cli_run_test.go
@@ -4,6 +4,7 @@
"bufio"
"bytes"
"fmt"
+ "io"
"io/ioutil"
"net"
"os"
@@ -4467,3 +4468,32 @@
// NGoroutines is not updated right away, so we need to wait before failing
c.Assert(waitForGoroutines(nroutines), checker.IsNil)
}
+
+// #28658
+func (s *DockerSuite) TestSlowStdinClosing(c *check.C) {
+ name := "testslowstdinclosing"
+ repeat := 3 // regression happened 50% of the time
+ for i := 0; i < repeat; i++ {
+ cmd := exec.Command(dockerBinary, "run", "--rm", "--name", name, "-i", "busybox", "cat")
+ cmd.Stdin = &delayedReader{}
+ done := make(chan error, 1)
+ go func() {
+ _, err := runCommand(cmd)
+ done <- err
+ }()
+
+ select {
+ case <-time.After(15 * time.Second):
+ c.Fatal("running container timed out") // cleanup in teardown
+ case err := <-done:
+ c.Assert(err, checker.IsNil)
+ }
+ }
+}
+
+type delayedReader struct{}
+
+func (s *delayedReader) Read([]byte) (int, error) {
+ time.Sleep(500 * time.Millisecond)
+ return 0, io.EOF
+}
diff --git a/libcontainerd/container_linux.go b/libcontainerd/container_linux.go
index 3c58713..29c98de 100644
--- a/libcontainerd/container_linux.go
+++ b/libcontainerd/container_linux.go
@@ -117,10 +117,14 @@
go func() {
select {
case <-ready:
+ case <-ctx.Done():
+ }
+ select {
+ case <-ready:
if err := ctr.sendCloseStdin(); err != nil {
logrus.Warnf("failed to close stdin: %+v", err)
}
- case <-ctx.Done():
+ default:
}
}()
})