90 lines
2.7 KiB
Diff
90 lines
2.7 KiB
Diff
|
|
From d886f6c03cca051b45fd77cc77d0cc870aed1aed Mon Sep 17 00:00:00 2001
|
||
|
|
From: build <build@obs.com>
|
||
|
|
Date: Wed, 4 Sep 2019 05:21:06 -0400
|
||
|
|
Subject: [PATCH] containerd: add timeout for I/O waitgroups
|
||
|
|
|
||
|
|
reason: This and a combination of a couple Docker changes are needed to fully
|
||
|
|
resolve the issue on the Docker side. However, this ensures that after
|
||
|
|
processes exit, we still leave some time for the I/O to fully flush
|
||
|
|
before closing. Without this timeout, the delete methods would block
|
||
|
|
forever.
|
||
|
|
|
||
|
|
Cherry-pick from upstream 245052243d
|
||
|
|
Reference from https://github.com/containerd/containerd/pull/3361
|
||
|
|
|
||
|
|
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
|
||
|
|
---
|
||
|
|
runtime/v1/linux/proc/exec.go | 2 +-
|
||
|
|
runtime/v1/linux/proc/init.go | 2 +-
|
||
|
|
runtime/v1/linux/proc/utils.go | 20 ++++++++++++++++++++
|
||
|
|
3 files changed, 22 insertions(+), 2 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/runtime/v1/linux/proc/exec.go b/runtime/v1/linux/proc/exec.go
|
||
|
|
index 715a977..08c581f 100644
|
||
|
|
--- a/runtime/v1/linux/proc/exec.go
|
||
|
|
+++ b/runtime/v1/linux/proc/exec.go
|
||
|
|
@@ -94,7 +94,7 @@ func (e *execProcess) setExited(status int) {
|
||
|
|
}
|
||
|
|
|
||
|
|
func (e *execProcess) delete(ctx context.Context) error {
|
||
|
|
- e.wg.Wait()
|
||
|
|
+ waitTimeout(ctx, &e.wg, 2*time.Second)
|
||
|
|
if e.io != nil {
|
||
|
|
for _, c := range e.closers {
|
||
|
|
c.Close()
|
||
|
|
diff --git a/runtime/v1/linux/proc/init.go b/runtime/v1/linux/proc/init.go
|
||
|
|
index 44d3f58..49fa8ec 100644
|
||
|
|
--- a/runtime/v1/linux/proc/init.go
|
||
|
|
+++ b/runtime/v1/linux/proc/init.go
|
||
|
|
@@ -263,7 +263,7 @@ func (p *Init) setExited(status int) {
|
||
|
|
}
|
||
|
|
|
||
|
|
func (p *Init) delete(context context.Context) error {
|
||
|
|
- p.wg.Wait()
|
||
|
|
+ waitTimeout(context, &p.wg, 2*time.Second)
|
||
|
|
err := p.runtime.Delete(context, p.id, nil)
|
||
|
|
// ignore errors if a runtime has already deleted the process
|
||
|
|
// but we still hold metadata and pipes
|
||
|
|
diff --git a/runtime/v1/linux/proc/utils.go b/runtime/v1/linux/proc/utils.go
|
||
|
|
index ab9f5fa..d6f047c 100644
|
||
|
|
--- a/runtime/v1/linux/proc/utils.go
|
||
|
|
+++ b/runtime/v1/linux/proc/utils.go
|
||
|
|
@@ -19,10 +19,12 @@
|
||
|
|
package proc
|
||
|
|
|
||
|
|
import (
|
||
|
|
+ "context"
|
||
|
|
"encoding/json"
|
||
|
|
"io"
|
||
|
|
"os"
|
||
|
|
"strings"
|
||
|
|
+ "sync"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"github.com/containerd/containerd/errdefs"
|
||
|
|
@@ -103,3 +105,21 @@ func checkKillError(err error) error {
|
||
|
|
func hasNoIO(r *CreateConfig) bool {
|
||
|
|
return r.Stdin == "" && r.Stdout == "" && r.Stderr == ""
|
||
|
|
}
|
||
|
|
+
|
||
|
|
+// waitTimeout handles waiting on a waitgroup with a specified timeout.
|
||
|
|
+// this is commonly used for waiting on IO to finish after a process has exited
|
||
|
|
+func waitTimeout(ctx context.Context, wg *sync.WaitGroup, timeout time.Duration) error {
|
||
|
|
+ ctx, cancel := context.WithTimeout(ctx, timeout)
|
||
|
|
+ defer cancel()
|
||
|
|
+ done := make(chan struct{}, 1)
|
||
|
|
+ go func() {
|
||
|
|
+ wg.Wait()
|
||
|
|
+ close(done)
|
||
|
|
+ }()
|
||
|
|
+ select {
|
||
|
|
+ case <-done:
|
||
|
|
+ return nil
|
||
|
|
+ case <-ctx.Done():
|
||
|
|
+ return ctx.Err()
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
--
|
||
|
|
2.20.1
|
||
|
|
|