From 73396551fd60addd7d6f0f6811833177553cea08 Mon Sep 17 00:00:00 2001 From: Peng Tao Date: Sat, 6 May 2017 16:54:22 +0800 Subject: [PATCH] read until EOF in streamCopy If either stdoutPipe or stderrPipe reads to EOF, do not close the other one so that it can read to EOF as well. Otherwise we might lose output in the other pipe. This works because if hyperstart ends the stdout/stderr streams, it always closes the writer part of both pipes. Then io.Copy() will get EOF and return success here. Also no need to wait stdin go routine because streamCopy() runs in a go routine itself thus no one is really waiting out there. Signed-off-by: Peng Tao --- hypervisor/vm_states.go | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/hypervisor/vm_states.go b/hypervisor/vm_states.go index 47a48c9d..2e25563a 100644 --- a/hypervisor/vm_states.go +++ b/hypervisor/vm_states.go @@ -172,6 +172,7 @@ func streamCopy(tty *TtyIO, stdinPipe io.WriteCloser, stdoutPipe, stderrPipe io. var wg sync.WaitGroup // old way cleanup all(expect stdinPipe) no matter what kinds of fails, TODO: change it var once sync.Once + // cleanup closes tty.Stdin and thus terminates the first go routine cleanup := func() { tty.Close() // stdinPipe is directly closed in the first go routine @@ -181,7 +182,6 @@ func streamCopy(tty *TtyIO, stdinPipe io.WriteCloser, stdoutPipe, stderrPipe io. } } if tty.Stdin != nil { - wg.Add(1) go func() { _, err := io.Copy(stdinPipe, tty.Stdin) stdinPipe.Close() @@ -189,22 +189,25 @@ func streamCopy(tty *TtyIO, stdinPipe io.WriteCloser, stdoutPipe, stderrPipe io. // we should not call cleanup when tty.Stdin reaches EOF once.Do(cleanup) } - wg.Done() }() } if tty.Stdout != nil { wg.Add(1) go func() { - io.Copy(tty.Stdout, stdoutPipe) - once.Do(cleanup) + _, err := io.Copy(tty.Stdout, stdoutPipe) + if err != nil { + once.Do(cleanup) + } wg.Done() }() } if tty.Stderr != nil && stderrPipe != nil { wg.Add(1) go func() { - io.Copy(tty.Stderr, stderrPipe) - once.Do(cleanup) + _, err := io.Copy(tty.Stderr, stderrPipe) + if err != nil { + once.Do(cleanup) + } wg.Done() }() }