From 5cfededc7ca552260f8eb7319184437a816e480d Mon Sep 17 00:00:00 2001
From: John Howard <jhoward@microsoft.com>
Date: Thu, 2 Aug 2018 15:09:15 -0700
Subject: [PATCH] Don't invoke HCS shutdown if terminate called

Signed-off-by: John Howard <jhoward@microsoft.com>
---
 libcontainerd/client_local_windows.go | 49 ++++++++++++++++-----------
 1 file changed, 29 insertions(+), 20 deletions(-)

diff --git a/libcontainerd/client_local_windows.go b/libcontainerd/client_local_windows.go
index 89d18c6ba7..9a5a825335 100644
--- a/libcontainerd/client_local_windows.go
+++ b/libcontainerd/client_local_windows.go
@@ -42,18 +42,17 @@ type container struct {
 	// have access to the Spec
 	ociSpec *specs.Spec
 
-	isWindows           bool
-	manualStopRequested bool
-	hcsContainer        hcsshim.Container
+	isWindows    bool
+	hcsContainer hcsshim.Container
 
-	id            string
-	status        Status
-	exitedAt      time.Time
-	exitCode      uint32
-	waitCh        chan struct{}
-	init          *process
-	execs         map[string]*process
-	updatePending bool
+	id               string
+	status           Status
+	exitedAt         time.Time
+	exitCode         uint32
+	waitCh           chan struct{}
+	init             *process
+	execs            map[string]*process
+	terminateInvoked bool
 }
 
 // Win32 error codes that are used for various workarounds
@@ -324,15 +323,15 @@ func (c *client) createWindows(id string, spec *specs.Spec, runtimeOptions inter
 	logger.Debug("starting container")
 	if err = hcsContainer.Start(); err != nil {
 		c.logger.WithError(err).Error("failed to start container")
-		ctr.debugGCS()
+		ctr.Lock()
 		if err := c.terminateContainer(ctr); err != nil {
 			c.logger.WithError(err).Error("failed to cleanup after a failed Start")
 		} else {
 			c.logger.Debug("cleaned up after failed Start by calling Terminate")
 		}
+		ctr.Unlock()
 		return err
 	}
-	ctr.debugGCS()
 
 	c.Lock()
 	c.containers[id] = ctr
@@ -528,11 +527,13 @@ func (c *client) createLinux(id string, spec *specs.Spec, runtimeOptions interfa
 	if err = hcsContainer.Start(); err != nil {
 		c.logger.WithError(err).Error("failed to start container")
 		ctr.debugGCS()
+		ctr.Lock()
 		if err := c.terminateContainer(ctr); err != nil {
 			c.logger.WithError(err).Error("failed to cleanup after a failed Start")
 		} else {
 			c.logger.Debug("cleaned up after failed Start by calling Terminate")
 		}
+		ctr.Unlock()
 		return err
 	}
 	ctr.debugGCS()
@@ -852,8 +853,6 @@ func (c *client) SignalProcess(_ context.Context, containerID, processID string,
 		return err
 	}
 
-	ctr.manualStopRequested = true
-
 	logger := c.logger.WithFields(logrus.Fields{
 		"container": containerID,
 		"process":   processID,
@@ -865,11 +864,14 @@ func (c *client) SignalProcess(_ context.Context, containerID, processID string,
 	if processID == InitProcessName {
 		if syscall.Signal(signal) == syscall.SIGKILL {
 			// Terminate the compute system
+			ctr.Lock()
+			ctr.terminateInvoked = true
 			if err := ctr.hcsContainer.Terminate(); err != nil {
 				if !hcsshim.IsPending(err) {
 					logger.WithError(err).Error("failed to terminate hccshim container")
 				}
 			}
+			ctr.Unlock()
 		} else {
 			// Shut down the container
 			if err := ctr.hcsContainer.Shutdown(); err != nil {
@@ -1171,12 +1173,17 @@ func (c *client) getProcess(containerID, processID string) (*container, *process
 	return ctr, p, nil
 }
 
+// ctr mutex must be held when calling this function.
 func (c *client) shutdownContainer(ctr *container) error {
-	const shutdownTimeout = time.Minute * 5
-	err := ctr.hcsContainer.Shutdown()
+	var err error
+	const waitTimeout = time.Minute * 5
 
-	if hcsshim.IsPending(err) {
-		err = ctr.hcsContainer.WaitTimeout(shutdownTimeout)
+	if !ctr.terminateInvoked {
+		err = ctr.hcsContainer.Shutdown()
+	}
+
+	if hcsshim.IsPending(err) || ctr.terminateInvoked {
+		err = ctr.hcsContainer.WaitTimeout(waitTimeout)
 	} else if hcsshim.IsAlreadyStopped(err) {
 		err = nil
 	}
@@ -1196,8 +1203,10 @@ func (c *client) shutdownContainer(ctr *container) error {
 	return nil
 }
 
+// ctr mutex must be held when calling this function.
 func (c *client) terminateContainer(ctr *container) error {
 	const terminateTimeout = time.Minute * 5
+	ctr.terminateInvoked = true
 	err := ctr.hcsContainer.Terminate()
 
 	if hcsshim.IsPending(err) {
@@ -1263,7 +1272,6 @@ func (c *client) reapProcess(ctr *container, p *process) int {
 		ctr.exitedAt = exitedAt
 		ctr.exitCode = uint32(exitCode)
 		close(ctr.waitCh)
-		ctr.Unlock()
 
 		if err := c.shutdownContainer(ctr); err != nil {
 			exitCode = -1
@@ -1277,6 +1285,7 @@ func (c *client) reapProcess(ctr *container, p *process) int {
 		} else {
 			logger.Debug("completed container shutdown")
 		}
+		ctr.Unlock()
 
 		if err := ctr.hcsContainer.Close(); err != nil {
 			exitCode = -1