From ae334b045fcd9a5dd1fcc206c2082d52dc497a47 Mon Sep 17 00:00:00 2001 From: Kenfe-Mickael Laventure Date: Thu, 13 Jul 2017 10:46:14 +0200 Subject: [PATCH 1/3] Prevent a data race in client_test.go on test failure Signed-off-by: Kenfe-Mickael Laventure --- client_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client_test.go b/client_test.go index addd23919..db307a96a 100644 --- a/client_test.go +++ b/client_test.go @@ -98,7 +98,7 @@ func TestMain(m *testing.M) { if err := cmd.Process.Signal(syscall.SIGTERM); err != nil { fmt.Fprintln(os.Stderr, err) } - if _, err := cmd.Process.Wait(); err != nil { + if err := cmd.Wait(); err != nil { fmt.Fprintln(os.Stderr, err) } if err := os.RemoveAll(defaultRoot); err != nil { From 9dcf725b76dfcbd1fa25a754867018168b0595d2 Mon Sep 17 00:00:00 2001 From: Kenfe-Mickael Laventure Date: Thu, 13 Jul 2017 11:12:29 +0200 Subject: [PATCH 2/3] Fix data race when task's exec fails to start Signed-off-by: Kenfe-Mickael Laventure --- process.go | 1 + 1 file changed, 1 insertion(+) diff --git a/process.go b/process.go index caa332017..9f91dfa0e 100644 --- a/process.go +++ b/process.go @@ -45,6 +45,7 @@ func (p *process) Start(ctx context.Context) error { } response, err := p.task.client.TaskService().Exec(ctx, request) if err != nil { + p.io.Wait() p.io.Close() return err } From a5b3038cccc52c2f022caaf0c0f31a2cf54f34cd Mon Sep 17 00:00:00 2001 From: Kenfe-Mickael Laventure Date: Thu, 13 Jul 2017 11:13:02 +0200 Subject: [PATCH 3/3] Fix deadlock when task's exec start fails Signed-off-by: Kenfe-Mickael Laventure --- io.go | 19 ++++++++++++++++--- io_unix.go | 18 ++++++++++-------- process.go | 1 + 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/io.go b/io.go index ea103c354..e4fce203c 100644 --- a/io.go +++ b/io.go @@ -1,6 +1,7 @@ package containerd import ( + "context" "fmt" "io" "io/ioutil" @@ -18,6 +19,13 @@ type IO struct { closer *wgCloser } +func (i *IO) Cancel() { + if i.closer == nil { + return + } + i.closer.Cancel() +} + func (i *IO) Wait() { if i.closer == nil { return @@ -134,9 +142,10 @@ type ioSet struct { } type wgCloser struct { - wg *sync.WaitGroup - dir string - set []io.Closer + wg *sync.WaitGroup + dir string + set []io.Closer + cancel context.CancelFunc } func (g *wgCloser) Wait() { @@ -152,3 +161,7 @@ func (g *wgCloser) Close() error { } return nil } + +func (g *wgCloser) Cancel() { + g.cancel() +} diff --git a/io_unix.go b/io_unix.go index ed8960585..ea05f251a 100644 --- a/io_unix.go +++ b/io_unix.go @@ -13,16 +13,17 @@ import ( func copyIO(fifos *FIFOSet, ioset *ioSet, tty bool) (_ *wgCloser, err error) { var ( - f io.ReadWriteCloser - set []io.Closer - ctx = context.Background() - wg = &sync.WaitGroup{} + f io.ReadWriteCloser + set []io.Closer + ctx, cancel = context.WithCancel(context.Background()) + wg = &sync.WaitGroup{} ) defer func() { if err != nil { for _, f := range set { f.Close() } + cancel() } }() @@ -55,13 +56,14 @@ func copyIO(fifos *FIFOSet, ioset *ioSet, tty bool) (_ *wgCloser, err error) { wg.Add(1) go func(r io.ReadCloser) { io.Copy(ioset.err, r) - wg.Done() r.Close() + wg.Done() }(f) } return &wgCloser{ - wg: wg, - dir: fifos.Dir, - set: set, + wg: wg, + dir: fifos.Dir, + set: set, + cancel: cancel, }, nil } diff --git a/process.go b/process.go index 9f91dfa0e..a3b4b3565 100644 --- a/process.go +++ b/process.go @@ -45,6 +45,7 @@ func (p *process) Start(ctx context.Context) error { } response, err := p.task.client.TaskService().Exec(ctx, request) if err != nil { + p.io.Cancel() p.io.Wait() p.io.Close() return err