packer: fix data race in communicator

This commit is contained in:
Mitchell Hashimoto 2013-08-21 10:16:20 -07:00
parent 32ab55c79f
commit 4524b13911
2 changed files with 14 additions and 6 deletions

View File

@ -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 {
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:
// 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) {
// 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
} }

View File

@ -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)
} }