From e18f5a53045d4b2810f56d33b9ff9a8f6a7ae8bf Mon Sep 17 00:00:00 2001
From: Sebastiaan van Stijn <github@gone.nl>
Date: Fri, 18 Aug 2023 16:18:40 +0200
Subject: [PATCH] container: internalize InitAttachContext

Move the initialization logic to the attachContext itself, so that
the container doesn't have to be aware about mutexes and other logic.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
---
 container/attach_context.go | 35 +++++++++++++++++++++++++++++++++++
 container/container.go      | 26 ++++----------------------
 daemon/attach.go            |  2 +-
 3 files changed, 40 insertions(+), 23 deletions(-)
 create mode 100644 container/attach_context.go

diff --git a/container/attach_context.go b/container/attach_context.go
new file mode 100644
index 0000000000..5a7d0748f0
--- /dev/null
+++ b/container/attach_context.go
@@ -0,0 +1,35 @@
+package container
+
+import (
+	"context"
+	"sync"
+)
+
+// attachContext is the context used for for attach calls.
+type attachContext struct {
+	mu         sync.Mutex
+	ctx        context.Context
+	cancelFunc context.CancelFunc
+}
+
+// init returns the context for attach calls. It creates a new context
+// if no context is created yet.
+func (ac *attachContext) init() context.Context {
+	ac.mu.Lock()
+	defer ac.mu.Unlock()
+	if ac.ctx == nil {
+		ac.ctx, ac.cancelFunc = context.WithCancel(context.Background())
+	}
+	return ac.ctx
+}
+
+// cancelFunc cancels the attachContext. All attach calls should detach
+// after this call.
+func (ac *attachContext) cancel() {
+	ac.mu.Lock()
+	if ac.ctx != nil {
+		ac.cancelFunc()
+		ac.ctx = nil
+	}
+	ac.mu.Unlock()
+}
diff --git a/container/container.go b/container/container.go
index bc21a33881..be492a0fa3 100644
--- a/container/container.go
+++ b/container/container.go
@@ -10,7 +10,6 @@ import (
 	"path/filepath"
 	"runtime"
 	"strings"
-	"sync"
 	"syscall"
 	"time"
 
@@ -594,32 +593,15 @@ func (container *Container) ResetRestartManager(resetCount bool) {
 	container.restartManager = nil
 }
 
-type attachContext struct {
-	ctx    context.Context
-	cancel context.CancelFunc
-	mu     sync.Mutex
-}
-
-// InitAttachContext initializes or returns existing context for attach calls to
-// track container liveness.
-func (container *Container) InitAttachContext() context.Context {
-	container.attachContext.mu.Lock()
-	defer container.attachContext.mu.Unlock()
-	if container.attachContext.ctx == nil {
-		container.attachContext.ctx, container.attachContext.cancel = context.WithCancel(context.Background())
-	}
-	return container.attachContext.ctx
+// AttachContext returns the context for attach calls to track container liveness.
+func (container *Container) AttachContext() context.Context {
+	return container.attachContext.init()
 }
 
 // CancelAttachContext cancels attach context. All attach calls should detach
 // after this call.
 func (container *Container) CancelAttachContext() {
-	container.attachContext.mu.Lock()
-	if container.attachContext.ctx != nil {
-		container.attachContext.cancel()
-		container.attachContext.ctx = nil
-	}
-	container.attachContext.mu.Unlock()
+	container.attachContext.cancel()
 }
 
 func (container *Container) startLogging() error {
diff --git a/daemon/attach.go b/daemon/attach.go
index 18480df5db..9809671134 100644
--- a/daemon/attach.go
+++ b/daemon/attach.go
@@ -175,7 +175,7 @@ func (daemon *Daemon) containerAttach(c *container.Container, cfg *stream.Attach
 		}()
 	}
 
-	ctx := c.InitAttachContext()
+	ctx := c.AttachContext()
 	err := <-c.StreamConfig.CopyStreams(ctx, cfg)
 	if err != nil {
 		var ierr term.EscapeError