From 4524b13911b0e780ab97ee1ed04f601f6ab2fd69 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 21 Aug 2013 10:16:20 -0700 Subject: [PATCH] packer: fix data race in communicator --- packer/communicator.go | 17 +++++++++++------ packer/communicator_test.go | 3 +++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/packer/communicator.go b/packer/communicator.go index a3bed992f..27360b63a 100644 --- a/packer/communicator.go +++ b/packer/communicator.go @@ -33,9 +33,11 @@ type RemoteCmd struct { // Once Exited is true, this will contain the exit code of the process. ExitStatus int - // Internal locks and such used for safely setting some shared variables - l sync.Mutex + // Internal fields exitCh chan struct{} + + // This thing is a mutex, lock when making modifications concurrently + sync.Mutex } // A Communicator is the interface used to communicate with the machine @@ -76,6 +78,9 @@ func (r *RemoteCmd) StartWithUi(c Communicator, ui Ui) error { originalStdout := r.Stdout originalStderr := r.Stderr defer func() { + r.Lock() + defer r.Unlock() + r.Stdout = originalStdout r.Stderr = originalStderr }() @@ -141,8 +146,8 @@ OutputLoop: // should be called by communicators who are running a remote command in // order to set that the command is done. func (r *RemoteCmd) SetExited(status int) { - r.l.Lock() - defer r.l.Unlock() + r.Lock() + defer r.Unlock() if r.exitCh == nil { r.exitCh = make(chan struct{}) @@ -156,11 +161,11 @@ func (r *RemoteCmd) SetExited(status int) { // Wait waits for the remote command to complete. func (r *RemoteCmd) Wait() { // Make sure our condition variable is initialized. - r.l.Lock() + r.Lock() if r.exitCh == nil { r.exitCh = make(chan struct{}) } - r.l.Unlock() + r.Unlock() <-r.exitCh } diff --git a/packer/communicator_test.go b/packer/communicator_test.go index ac4c5b3e8..05c387ec1 100644 --- a/packer/communicator_test.go +++ b/packer/communicator_test.go @@ -15,6 +15,9 @@ type TestCommunicator struct { func (c *TestCommunicator) Start(rc *RemoteCmd) error { go func() { + rc.Lock() + defer rc.Unlock() + if rc.Stdout != nil && c.Stdout != nil { io.Copy(rc.Stdout, c.Stdout) }