Browse code

Merge pull request #21022 from hqhq/hq_fix_race_resize

Fix race condition with exec and resize

Antonio Murdaca authored on 2016/03/16 06:54:55
Showing 2 changed files
... ...
@@ -307,6 +307,9 @@ func (d *Daemon) monitorExec(container *container.Container, execConfig *exec.Co
307 307
 	}
308 308
 
309 309
 	if execConfig.ProcessConfig.Terminal != nil {
310
+		if err := execConfig.WaitResize(); err != nil {
311
+			logrus.Errorf("Error waiting for resize: %v", err)
312
+		}
310 313
 		if err := execConfig.ProcessConfig.Terminal.Close(); err != nil {
311 314
 			logrus.Errorf("Error closing terminal while running in container %s: %s", container.ID, err)
312 315
 		}
... ...
@@ -29,6 +29,9 @@ type Config struct {
29 29
 
30 30
 	// waitStart will be closed immediately after the exec is really started.
31 31
 	waitStart chan struct{}
32
+
33
+	// waitResize will be closed after Resize is finished.
34
+	waitResize chan struct{}
32 35
 }
33 36
 
34 37
 // NewConfig initializes the a new exec configuration
... ...
@@ -37,6 +40,7 @@ func NewConfig() *Config {
37 37
 		ID:           stringid.GenerateNonCryptoID(),
38 38
 		StreamConfig: runconfig.NewStreamConfig(),
39 39
 		waitStart:    make(chan struct{}),
40
+		waitResize:   make(chan struct{}),
40 41
 	}
41 42
 }
42 43
 
... ...
@@ -106,13 +110,29 @@ func (c *Config) Wait(cErr chan error) error {
106 106
 	return nil
107 107
 }
108 108
 
109
+// WaitResize waits until terminal resize finishes or time out.
110
+func (c *Config) WaitResize() error {
111
+	select {
112
+	case <-c.waitResize:
113
+	case <-time.After(time.Second):
114
+		return fmt.Errorf("Terminal resize for exec %s time out.", c.ID)
115
+	}
116
+	return nil
117
+}
118
+
109 119
 // Close closes the wait channel for the progress.
110 120
 func (c *Config) Close() {
111 121
 	close(c.waitStart)
112 122
 }
113 123
 
124
+// CloseResize closes the wait channel for resizing terminal.
125
+func (c *Config) CloseResize() {
126
+	close(c.waitResize)
127
+}
128
+
114 129
 // Resize changes the size of the terminal for the exec process.
115 130
 func (c *Config) Resize(h, w int) error {
131
+	defer c.CloseResize()
116 132
 	select {
117 133
 	case <-c.waitStart:
118 134
 	case <-time.After(time.Second):