Ensure stdin does not block after container stop

Fixes #11957
Fixes #12319

Also removes check for Darwin when the stdin reader is closed as it
doesn't appear to block any more.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
This commit is contained in:
Brian Goff
2015-09-18 13:48:07 -04:00
parent 9fbef808c1
commit 3dbfb3d38c
2 changed files with 42 additions and 25 deletions
+21 -25
View File
@@ -16,7 +16,6 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/docker/api"
"github.com/docker/docker/autogen/dockerversion"
"github.com/docker/docker/pkg/promise"
"github.com/docker/docker/pkg/stdcopy"
"github.com/docker/docker/pkg/term"
)
@@ -184,8 +183,6 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea
started <- rwc
}
var receiveStdout chan error
var oldState *term.State
if in != nil && setRawTerminal && cli.isTerminalIn && os.Getenv("NORAW") == "" {
@@ -196,19 +193,15 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea
defer term.RestoreTerminal(cli.inFd, oldState)
}
receiveStdout := make(chan error, 1)
if stdout != nil || stderr != nil {
receiveStdout = promise.Go(func() (err error) {
go func() {
defer func() {
if in != nil {
if setRawTerminal && cli.isTerminalIn {
term.RestoreTerminal(cli.inFd, oldState)
}
// For some reason this Close call blocks on darwin..
// As the client exists right after, simply discard the close
// until we find a better solution.
if runtime.GOOS != "darwin" {
in.Close()
}
in.Close()
}
}()
@@ -219,11 +212,12 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea
_, err = stdcopy.StdCopy(stdout, stderr, br)
}
logrus.Debugf("[hijack] End of stdout")
return err
})
receiveStdout <- err
}()
}
sendStdin := promise.Go(func() error {
stdinDone := make(chan struct{})
go func() {
if in != nil {
io.Copy(rwc, in)
logrus.Debugf("[hijack] End of stdin")
@@ -236,22 +230,24 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea
logrus.Debugf("Couldn't send EOF: %s", err)
}
}
// Discard errors due to pipe interruption
return nil
})
close(stdinDone)
}()
if stdout != nil || stderr != nil {
if err := <-receiveStdout; err != nil {
select {
case err := <-receiveStdout:
if err != nil {
logrus.Debugf("Error receiveStdout: %s", err)
return err
}
if cli.isTerminalIn {
return nil
}
case <-stdinDone:
if stdout != nil || stderr != nil {
if err := <-receiveStdout; err != nil {
logrus.Debugf("Error receiveStdout: %s", err)
}
}
}
if !cli.isTerminalIn {
if err := <-sendStdin; err != nil {
logrus.Debugf("Error sendStdin: %s", err)
return err
}
}
return nil
}