Fix race condition with exec and resize
| ... | ... |
@@ -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): |