diff --git a/commands.go b/commands.go index 74cbe74600..78f8154a36 100644 --- a/commands.go +++ b/commands.go @@ -2053,9 +2053,18 @@ func (cli *DockerCli) CmdRun(args ...string) error { }() } - // We need to make the chan because the select needs to have a closing - // chan, it can't be uninitialized - hijacked := make(chan bool) + // We need to instanciate the chan because the select needs it. It can + // be closed but can't be uninitialized. + hijacked := make(chan io.Closer) + + // Block the return until the chan gets closed + defer func() { + utils.Debugf("End of CmdRun(), Waiting for hijack to finish.") + if _, ok := <-hijacked; ok { + utils.Errorf("Hijack did not finish (chan still open)") + } + }() + if config.AttachStdin || config.AttachStdout || config.AttachStderr { var ( out, stderr io.Writer @@ -2090,7 +2099,12 @@ func (cli *DockerCli) CmdRun(args ...string) error { // Acknowledge the hijack before starting select { - case <-hijacked: + case closer := <-hijacked: + // Make sure that hijack gets closed when returning. (result + // in closing hijack chan and freeing server's goroutines. + if closer != nil { + defer closer.Close() + } case err := <-errCh: if err != nil { utils.Debugf("Error hijack: %s", err) @@ -2339,7 +2353,12 @@ func (cli *DockerCli) stream(method, path string, in io.Reader, out io.Writer, h return nil } -func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.ReadCloser, stdout, stderr io.Writer, started chan bool) error { +func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.ReadCloser, stdout, stderr io.Writer, started chan io.Closer) error { + defer func() { + if started != nil { + close(started) + } + }() // fixme: refactor client to support redirect re := regexp.MustCompile("/+") path = re.ReplaceAllString(path, "/") @@ -2369,7 +2388,7 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea defer rwc.Close() if started != nil { - started <- true + started <- rwc } var receiveStdout chan error