Commit 6f742cb3 authored by Mitchell Hashimoto's avatar Mitchell Hashimoto

packer: fix data race in communicator

parent c71419f7
...@@ -33,9 +33,11 @@ type RemoteCmd struct { ...@@ -33,9 +33,11 @@ type RemoteCmd struct {
// Once Exited is true, this will contain the exit code of the process. // Once Exited is true, this will contain the exit code of the process.
ExitStatus int ExitStatus int
// Internal locks and such used for safely setting some shared variables // Internal fields
l sync.Mutex
exitCh chan struct{} 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 // A Communicator is the interface used to communicate with the machine
...@@ -76,6 +78,9 @@ func (r *RemoteCmd) StartWithUi(c Communicator, ui Ui) error { ...@@ -76,6 +78,9 @@ func (r *RemoteCmd) StartWithUi(c Communicator, ui Ui) error {
originalStdout := r.Stdout originalStdout := r.Stdout
originalStderr := r.Stderr originalStderr := r.Stderr
defer func() { defer func() {
r.Lock()
defer r.Unlock()
r.Stdout = originalStdout r.Stdout = originalStdout
r.Stderr = originalStderr r.Stderr = originalStderr
}() }()
...@@ -141,8 +146,8 @@ OutputLoop: ...@@ -141,8 +146,8 @@ OutputLoop:
// should be called by communicators who are running a remote command in // should be called by communicators who are running a remote command in
// order to set that the command is done. // order to set that the command is done.
func (r *RemoteCmd) SetExited(status int) { func (r *RemoteCmd) SetExited(status int) {
r.l.Lock() r.Lock()
defer r.l.Unlock() defer r.Unlock()
if r.exitCh == nil { if r.exitCh == nil {
r.exitCh = make(chan struct{}) r.exitCh = make(chan struct{})
...@@ -156,11 +161,11 @@ func (r *RemoteCmd) SetExited(status int) { ...@@ -156,11 +161,11 @@ func (r *RemoteCmd) SetExited(status int) {
// Wait waits for the remote command to complete. // Wait waits for the remote command to complete.
func (r *RemoteCmd) Wait() { func (r *RemoteCmd) Wait() {
// Make sure our condition variable is initialized. // Make sure our condition variable is initialized.
r.l.Lock() r.Lock()
if r.exitCh == nil { if r.exitCh == nil {
r.exitCh = make(chan struct{}) r.exitCh = make(chan struct{})
} }
r.l.Unlock() r.Unlock()
<-r.exitCh <-r.exitCh
} }
......
...@@ -15,6 +15,9 @@ type TestCommunicator struct { ...@@ -15,6 +15,9 @@ type TestCommunicator struct {
func (c *TestCommunicator) Start(rc *RemoteCmd) error { func (c *TestCommunicator) Start(rc *RemoteCmd) error {
go func() { go func() {
rc.Lock()
defer rc.Unlock()
if rc.Stdout != nil && c.Stdout != nil { if rc.Stdout != nil && c.Stdout != nil {
io.Copy(rc.Stdout, c.Stdout) io.Copy(rc.Stdout, c.Stdout)
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment