mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Fix race condition with exec and resize
When I use `docker exec -ti test ls`, I got error: ``` ERRO[0035] Handler for POST /v1.23/exec/9677ecd7aa9de96f8e9e667519ff266ad26a5be80e80021a997fff6084ed6d75/resize returned error: bad file descriptor ``` It's because `POST /exec/<id>/start` and `POST /exec/<id>/resize` are asynchronous, it is possible that exec process finishes and ternimal is closed before resize. Then `console.Fd()` will get a large invalid number and we got the above error. Fix it by adding synchronization between exec and resize. Signed-off-by: Qiang Huang <h.huangqiang@huawei.com>
This commit is contained in:
parent
edf3c0f112
commit
dc56a76bc9
2 changed files with 23 additions and 0 deletions
|
@ -305,6 +305,9 @@ func (d *Daemon) monitorExec(container *container.Container, execConfig *exec.Co
|
|||
}
|
||||
|
||||
if execConfig.ProcessConfig.Terminal != nil {
|
||||
if err := execConfig.WaitResize(); err != nil {
|
||||
logrus.Errorf("Error waiting for resize: %v", err)
|
||||
}
|
||||
if err := execConfig.ProcessConfig.Terminal.Close(); err != nil {
|
||||
logrus.Errorf("Error closing terminal while running in container %s: %s", container.ID, err)
|
||||
}
|
||||
|
|
|
@ -29,6 +29,9 @@ type Config struct {
|
|||
|
||||
// waitStart will be closed immediately after the exec is really started.
|
||||
waitStart chan struct{}
|
||||
|
||||
// waitResize will be closed after Resize is finished.
|
||||
waitResize chan struct{}
|
||||
}
|
||||
|
||||
// NewConfig initializes the a new exec configuration
|
||||
|
@ -37,6 +40,7 @@ func NewConfig() *Config {
|
|||
ID: stringid.GenerateNonCryptoID(),
|
||||
StreamConfig: runconfig.NewStreamConfig(),
|
||||
waitStart: make(chan struct{}),
|
||||
waitResize: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -106,13 +110,29 @@ func (c *Config) Wait(cErr chan error) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// WaitResize waits until terminal resize finishes or time out.
|
||||
func (c *Config) WaitResize() error {
|
||||
select {
|
||||
case <-c.waitResize:
|
||||
case <-time.After(time.Second):
|
||||
return fmt.Errorf("Terminal resize for exec %s time out.", c.ID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close closes the wait channel for the progress.
|
||||
func (c *Config) Close() {
|
||||
close(c.waitStart)
|
||||
}
|
||||
|
||||
// CloseResize closes the wait channel for resizing terminal.
|
||||
func (c *Config) CloseResize() {
|
||||
close(c.waitResize)
|
||||
}
|
||||
|
||||
// Resize changes the size of the terminal for the exec process.
|
||||
func (c *Config) Resize(h, w int) error {
|
||||
defer c.CloseResize()
|
||||
select {
|
||||
case <-c.waitStart:
|
||||
case <-time.After(time.Second):
|
||||
|
|
Loading…
Add table
Reference in a new issue