e.g.
```
$ docker run -i --restart always busybox sh
pwd
/
exit 11
<...hang...>
```
This is because Attach(daemon side) and Run(client side) both hangs on
WaitStop, if container is restarted too quickly, wait won't have chance
to get exit signal.
Signed-off-by: Zhang Wei <zhangwei555@huawei.com>
| ... | ... |
@@ -287,7 +287,7 @@ func runRun(dockerCli *client.DockerCli, flags *pflag.FlagSet, opts *runOptions, |
| 287 | 287 |
} |
| 288 | 288 |
} else {
|
| 289 | 289 |
// No Autoremove: Simply retrieve the exit code |
| 290 |
- if !config.Tty {
|
|
| 290 |
+ if !config.Tty && hostConfig.RestartPolicy.IsNone() {
|
|
| 291 | 291 |
// In non-TTY mode, we can't detach, so we must wait for container exit |
| 292 | 292 |
if status, err = client.ContainerWait(ctx, createResponse.ID); err != nil {
|
| 293 | 293 |
return err |
| ... | ... |
@@ -119,6 +119,15 @@ func (daemon *Daemon) containerAttach(c *container.Container, stdin io.ReadClose |
| 119 | 119 |
}() |
| 120 | 120 |
stdinPipe = r |
| 121 | 121 |
} |
| 122 |
+ |
|
| 123 |
+ waitChan := make(chan struct{})
|
|
| 124 |
+ if c.Config.StdinOnce && !c.Config.Tty {
|
|
| 125 |
+ go func() {
|
|
| 126 |
+ c.WaitStop(-1 * time.Second) |
|
| 127 |
+ close(waitChan) |
|
| 128 |
+ }() |
|
| 129 |
+ } |
|
| 130 |
+ |
|
| 122 | 131 |
err := <-c.Attach(stdinPipe, stdout, stderr, keys) |
| 123 | 132 |
if err != nil {
|
| 124 | 133 |
if _, ok := err.(container.DetachError); ok {
|
| ... | ... |
@@ -131,7 +140,7 @@ func (daemon *Daemon) containerAttach(c *container.Container, stdin io.ReadClose |
| 131 | 131 |
// If we are in stdinonce mode, wait for the process to end |
| 132 | 132 |
// otherwise, simply return |
| 133 | 133 |
if c.Config.StdinOnce && !c.Config.Tty {
|
| 134 |
- c.WaitStop(-1 * time.Second) |
|
| 134 |
+ <-waitChan |
|
| 135 | 135 |
} |
| 136 | 136 |
} |
| 137 | 137 |
return nil |
| ... | ... |
@@ -1828,6 +1828,37 @@ func (s *DockerSuite) TestRunExitOnStdinClose(c *check.C) {
|
| 1828 | 1828 |
} |
| 1829 | 1829 |
} |
| 1830 | 1830 |
|
| 1831 |
+// Test run -i --restart xxx doesn't hang |
|
| 1832 |
+func (s *DockerSuite) TestRunInteractiveWithRestartPolicy(c *check.C) {
|
|
| 1833 |
+ name := "test-inter-restart" |
|
| 1834 |
+ runCmd := exec.Command(dockerBinary, "run", "-i", "--name", name, "--restart=always", "busybox", "sh") |
|
| 1835 |
+ |
|
| 1836 |
+ stdin, err := runCmd.StdinPipe() |
|
| 1837 |
+ c.Assert(err, checker.IsNil) |
|
| 1838 |
+ |
|
| 1839 |
+ err = runCmd.Start() |
|
| 1840 |
+ c.Assert(err, checker.IsNil) |
|
| 1841 |
+ c.Assert(waitRun(name), check.IsNil) |
|
| 1842 |
+ |
|
| 1843 |
+ _, err = stdin.Write([]byte("exit 11\n"))
|
|
| 1844 |
+ c.Assert(err, checker.IsNil) |
|
| 1845 |
+ |
|
| 1846 |
+ finish := make(chan error) |
|
| 1847 |
+ go func() {
|
|
| 1848 |
+ finish <- runCmd.Wait() |
|
| 1849 |
+ close(finish) |
|
| 1850 |
+ }() |
|
| 1851 |
+ delay := 10 * time.Second |
|
| 1852 |
+ select {
|
|
| 1853 |
+ case <-finish: |
|
| 1854 |
+ case <-time.After(delay): |
|
| 1855 |
+ c.Fatal("run -i --restart hangs")
|
|
| 1856 |
+ } |
|
| 1857 |
+ |
|
| 1858 |
+ c.Assert(waitRun(name), check.IsNil) |
|
| 1859 |
+ dockerCmd(c, "stop", name) |
|
| 1860 |
+} |
|
| 1861 |
+ |
|
| 1831 | 1862 |
// Test for #2267 |
| 1832 | 1863 |
func (s *DockerSuite) TestRunWriteHostsFileAndNotCommit(c *check.C) {
|
| 1833 | 1864 |
// Cannot run on Windows as Windows does not support diff. |