Browse code

Windows: [TP4] docker kill handling

Signed-off-by: John Howard <jhoward@microsoft.com>

John Howard authored on 2015/10/13 08:34:03
Showing 26 changed files
... ...
@@ -18,6 +18,7 @@ func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessCo
18 18
 		term     execdriver.Terminal
19 19
 		err      error
20 20
 		exitCode int32
21
+		errno    uint32
21 22
 	)
22 23
 
23 24
 	active := d.activeContainers[c.ID]
... ...
@@ -77,12 +78,15 @@ func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessCo
77 77
 		hooks.Start(&c.ProcessConfig, int(pid), chOOM)
78 78
 	}
79 79
 
80
-	if exitCode, err = hcsshim.WaitForProcessInComputeSystem(c.ID, pid); err != nil {
81
-		logrus.Errorf("Failed to WaitForProcessInComputeSystem %s", err)
80
+	if exitCode, errno, err = hcsshim.WaitForProcessInComputeSystem(c.ID, pid, hcsshim.TimeoutInfinite); err != nil {
81
+		if errno == hcsshim.Win32PipeHasBeenEnded {
82
+			logrus.Debugf("Exiting Run() after WaitForProcessInComputeSystem failed with recognised error 0x%X", errno)
83
+			return hcsshim.WaitErrExecFailed, nil
84
+		}
85
+		logrus.Warnf("WaitForProcessInComputeSystem failed (container may have been killed): 0x%X %s", errno, err)
82 86
 		return -1, err
83 87
 	}
84 88
 
85
-	// TODO Windows - Do something with this exit code
86
-	logrus.Debugln("Exiting Run() with ExitCode 0", c.ID)
89
+	logrus.Debugln("Exiting Run()", c.ID)
87 90
 	return int(exitCode), nil
88 91
 }
... ...
@@ -220,22 +220,19 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execd
220 220
 	}
221 221
 	defer func() {
222 222
 		// Stop the container
223
-
224
-		if terminateMode {
225
-			logrus.Debugf("Terminating container %s", c.ID)
226
-			if err := hcsshim.TerminateComputeSystem(c.ID); err != nil {
227
-				// IMPORTANT: Don't fail if fails to change state. It could already
228
-				// have been stopped through kill().
229
-				// Otherwise, the docker daemon will hang in job wait()
230
-				logrus.Warnf("Ignoring error from TerminateComputeSystem %s", err)
223
+		if forceKill {
224
+			logrus.Debugf("Forcibly terminating container %s", c.ID)
225
+			if errno, err := hcsshim.TerminateComputeSystem(c.ID, hcsshim.TimeoutInfinite, "exec-run-defer"); err != nil {
226
+				logrus.Warnf("Ignoring error from TerminateComputeSystem 0x%X %s", errno, err)
231 227
 			}
232 228
 		} else {
233 229
 			logrus.Debugf("Shutting down container %s", c.ID)
234
-			if err := hcsshim.ShutdownComputeSystem(c.ID); err != nil {
235
-				// IMPORTANT: Don't fail if fails to change state. It could already
236
-				// have been stopped through kill().
237
-				// Otherwise, the docker daemon will hang in job wait()
238
-				logrus.Warnf("Ignoring error from ShutdownComputeSystem %s", err)
230
+			if errno, err := hcsshim.ShutdownComputeSystem(c.ID, hcsshim.TimeoutInfinite, "exec-run-defer"); err != nil {
231
+				if errno != hcsshim.Win32SystemShutdownIsInProgress &&
232
+					errno != hcsshim.Win32SpecifiedPathInvalid &&
233
+					errno != hcsshim.Win32SystemCannotFindThePathSpecified {
234
+					logrus.Warnf("Ignoring error from ShutdownComputeSystem 0x%X %s", errno, err)
235
+				}
239 236
 			}
240 237
 		}
241 238
 	}()
... ...
@@ -303,11 +300,20 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execd
303 303
 		hooks.Start(&c.ProcessConfig, int(pid), chOOM)
304 304
 	}
305 305
 
306
-	var exitCode int32
307
-	exitCode, err = hcsshim.WaitForProcessInComputeSystem(c.ID, pid)
306
+	var (
307
+		exitCode int32
308
+		errno    uint32
309
+	)
310
+	exitCode, errno, err = hcsshim.WaitForProcessInComputeSystem(c.ID, pid, hcsshim.TimeoutInfinite)
308 311
 	if err != nil {
309
-		logrus.Errorf("Failed to WaitForProcessInComputeSystem %s", err)
310
-		return execdriver.ExitStatus{ExitCode: -1}, err
312
+		if errno != hcsshim.Win32PipeHasBeenEnded {
313
+			logrus.Warnf("WaitForProcessInComputeSystem failed (container may have been killed): %s", err)
314
+		}
315
+		// Do NOT return err here as the container would have
316
+		// started, otherwise docker will deadlock. It's perfectly legitimate
317
+		// for WaitForProcessInComputeSystem to fail in situations such
318
+		// as the container being killed on another thread.
319
+		return execdriver.ExitStatus{ExitCode: hcsshim.WaitErrExecFailed}, nil
311 320
 	}
312 321
 
313 322
 	logrus.Debugf("Exiting Run() exitCode %d id=%s", exitCode, c.ID)
... ...
@@ -3,6 +3,9 @@
3 3
 package windows
4 4
 
5 5
 import (
6
+	"fmt"
7
+	"syscall"
8
+
6 9
 	"github.com/Sirupsen/logrus"
7 10
 	"github.com/docker/docker/daemon/execdriver"
8 11
 	"github.com/microsoft/hcsshim"
... ...
@@ -10,37 +13,36 @@ import (
10 10
 
11 11
 // Terminate implements the exec driver Driver interface.
12 12
 func (d *Driver) Terminate(p *execdriver.Command) error {
13
-	logrus.Debugf("WindowsExec: Terminate() id=%s", p.ID)
14
-	return kill(p.ID, p.ContainerPid)
13
+	return kill(p.ID, p.ContainerPid, syscall.SIGTERM)
15 14
 }
16 15
 
17 16
 // Kill implements the exec driver Driver interface.
18 17
 func (d *Driver) Kill(p *execdriver.Command, sig int) error {
19
-	logrus.Debugf("WindowsExec: Kill() id=%s sig=%d", p.ID, sig)
20
-	return kill(p.ID, p.ContainerPid)
18
+	return kill(p.ID, p.ContainerPid, syscall.Signal(sig))
21 19
 }
22 20
 
23
-func kill(id string, pid int) error {
24
-	logrus.Debugln("kill() ", id, pid)
21
+func kill(id string, pid int, sig syscall.Signal) error {
22
+	logrus.Debugf("WindowsExec: kill() id=%s pid=%d sig=%d", id, pid, sig)
25 23
 	var err error
24
+	context := fmt.Sprintf("kill: sig=%d pid=%d", sig, pid)
26 25
 
27
-	// Terminate Process
28
-	if err = hcsshim.TerminateProcessInComputeSystem(id, uint32(pid)); err != nil {
29
-		logrus.Warnf("Failed to terminate pid %d in %s: %q", pid, id, err)
30
-		// Ignore errors
31
-		err = nil
32
-	}
33
-
34
-	if terminateMode {
26
+	if sig == syscall.SIGKILL || forceKill {
35 27
 		// Terminate the compute system
36
-		if err = hcsshim.TerminateComputeSystem(id); err != nil {
37
-			logrus.Errorf("Failed to terminate %s - %q", id, err)
28
+		if errno, err := hcsshim.TerminateComputeSystem(id, hcsshim.TimeoutInfinite, context); err != nil {
29
+			logrus.Errorf("Failed to terminate %s - 0x%X %q", id, errno, err)
38 30
 		}
39 31
 
40 32
 	} else {
33
+		// Terminate Process
34
+		if err = hcsshim.TerminateProcessInComputeSystem(id, uint32(pid)); err != nil {
35
+			logrus.Warnf("Failed to terminate pid %d in %s: %q", pid, id, err)
36
+			// Ignore errors
37
+			err = nil
38
+		}
39
+
41 40
 		// Shutdown the compute system
42
-		if err = hcsshim.ShutdownComputeSystem(id); err != nil {
43
-			logrus.Errorf("Failed to shutdown %s - %q", id, err)
41
+		if errno, err := hcsshim.ShutdownComputeSystem(id, hcsshim.TimeoutInfinite, context); err != nil {
42
+			logrus.Errorf("Failed to shutdown %s - 0x%X %q", id, errno, err)
44 43
 		}
45 44
 	}
46 45
 	return err
... ...
@@ -18,7 +18,8 @@ import (
18 18
 var dummyMode bool
19 19
 
20 20
 // This allows the daemon to terminate containers rather than shutdown
21
-var terminateMode bool
21
+// This allows the daemon to force kill (HCS terminate) rather than shutdown
22
+var forceKill bool
22 23
 
23 24
 // Define name and version for windows
24 25
 var (
... ...
@@ -62,11 +63,11 @@ func NewDriver(root, initPath string, options []string) (*Driver, error) {
62 62
 				logrus.Warn("Using dummy mode in Windows exec driver. This is for development use only!")
63 63
 			}
64 64
 
65
-		case "terminate":
65
+		case "forcekill":
66 66
 			switch val {
67 67
 			case "1":
68
-				terminateMode = true
69
-				logrus.Warn("Using terminate mode in Windows exec driver. This is for testing purposes only.")
68
+				forceKill = true
69
+				logrus.Warn("Using force kill mode in Windows exec driver. This is for testing purposes only.")
70 70
 			}
71 71
 
72 72
 		default:
... ...
@@ -1,6 +1,12 @@
1 1
 package daemon
2 2
 
3
-import "syscall"
3
+import (
4
+	"fmt"
5
+	"runtime"
6
+	"syscall"
7
+
8
+	"github.com/docker/docker/pkg/signal"
9
+)
4 10
 
5 11
 // ContainerKill send signal to the container
6 12
 // If no signal is given (sig 0), then Kill with SIGKILL and wait
... ...
@@ -12,6 +18,10 @@ func (daemon *Daemon) ContainerKill(name string, sig uint64) error {
12 12
 		return err
13 13
 	}
14 14
 
15
+	if sig != 0 && !signal.ValidSignalForPlatform(syscall.Signal(sig)) {
16
+		return fmt.Errorf("The %s daemon does not support signal %d", runtime.GOOS, sig)
17
+	}
18
+
15 19
 	// If no signal is passed, or SIGKILL, perform regular Kill (SIGKILL + wait())
16 20
 	if sig == 0 || syscall.Signal(sig) == syscall.SIGKILL {
17 21
 		if err := container.Kill(); err != nil {
... ...
@@ -14,7 +14,7 @@ clone git github.com/gorilla/context 14f550f51a
14 14
 clone git github.com/gorilla/mux e444e69cbd
15 15
 clone git github.com/kr/pty 5cf931ef8f
16 16
 clone git github.com/mattn/go-sqlite3 v1.1.0
17
-clone git github.com/microsoft/hcsshim 7f646aa6b26bcf90caee91e93cde4a80d0d8a83e
17
+clone git github.com/microsoft/hcsshim 325e531f8c49dd78580d5fd197ddb972fa4610e7
18 18
 clone git github.com/mistifyio/go-zfs v2.1.1
19 19
 clone git github.com/tchap/go-patricia v2.1.0
20 20
 clone git golang.org/x/net 3cffabab72adf04f8e3b01c5baf775361837b5fe https://github.com/golang/net.git
... ...
@@ -42,3 +42,13 @@ func ParseSignal(rawSignal string) (syscall.Signal, error) {
42 42
 	}
43 43
 	return signal, nil
44 44
 }
45
+
46
+// ValidSignalForPlatform returns true if a signal is valid on the platform
47
+func ValidSignalForPlatform(sig syscall.Signal) bool {
48
+	for _, v := range SignalMap {
49
+		if v == sig {
50
+			return true
51
+		}
52
+	}
53
+	return false
54
+}
... ...
@@ -14,7 +14,7 @@ import (
14 14
 // An activated layer must later be deactivated via DeactivateLayer.
15 15
 func ActivateLayer(info DriverInfo, id string) error {
16 16
 	title := "hcsshim::ActivateLayer "
17
-	logrus.Debugf(title+"Flavour %s ID %s", info.Flavour, id)
17
+	logrus.Debugf(title+"Flavour %d ID %s", info.Flavour, id)
18 18
 
19 19
 	// Load the DLL and get a handle to the procedure we need
20 20
 	dll, proc, err := loadAndFind(procActivateLayer)
... ...
@@ -12,7 +12,7 @@ import (
12 12
 // the parent layer provided.
13 13
 func CreateLayer(info DriverInfo, id, parent string) error {
14 14
 	title := "hcsshim::CreateLayer "
15
-	logrus.Debugf(title+"Flavour %s ID %s parent %s", info.Flavour, id, parent)
15
+	logrus.Debugf(title+"Flavour %d ID %s parent %s", info.Flavour, id, parent)
16 16
 
17 17
 	// Load the DLL and get a handle to the procedure we need
18 18
 	dll, proc, err := loadAndFind(procCreateLayer)
... ...
@@ -70,7 +70,7 @@ func (p *pipe) Write(b []byte) (int, error) {
70 70
 func CreateProcessInComputeSystem(id string, useStdin bool, useStdout bool, useStderr bool, params CreateProcessParams) (processid uint32, stdin io.WriteCloser, stdout io.ReadCloser, stderr io.ReadCloser, err error) {
71 71
 
72 72
 	title := "HCSShim::CreateProcessInComputeSystem"
73
-	logrus.Debugf(title+"id=%s params=%s", id, params)
73
+	logrus.Debugf(title+" id=%s", id)
74 74
 
75 75
 	// Load the DLL and get a handle to the procedure we need
76 76
 	dll, proc, err := loadAndFind(procCreateProcessWithStdHandlesInComputeSystem)
... ...
@@ -110,7 +110,7 @@ func CreateProcessInComputeSystem(id string, useStdin bool, useStdout bool, useS
110 110
 	// Get a POINTER to variable to take the pid outparm
111 111
 	pid := new(uint32)
112 112
 
113
-	logrus.Debugf(title+" - Calling the procedure itself %s %s", id, paramsJson)
113
+	logrus.Debugf(title+" - Calling Win32 %s %s", id, paramsJson)
114 114
 
115 115
 	var stdinHandle, stdoutHandle, stderrHandle syscall.Handle
116 116
 	var stdinParam, stdoutParam, stderrParam uintptr
... ...
@@ -11,7 +11,7 @@ import (
11 11
 // DeactivateLayer will dismount a layer that was mounted via ActivateLayer.
12 12
 func DeactivateLayer(info DriverInfo, id string) error {
13 13
 	title := "hcsshim::DeactivateLayer "
14
-	logrus.Debugf(title+"Flavour %s ID %s", info.Flavour, id)
14
+	logrus.Debugf(title+"Flavour %d ID %s", info.Flavour, id)
15 15
 
16 16
 	// Load the DLL and get a handle to the procedure we need
17 17
 	dll, proc, err := loadAndFind(procDeactivateLayer)
... ...
@@ -53,6 +53,6 @@ func DeactivateLayer(info DriverInfo, id string) error {
53 53
 		return err
54 54
 	}
55 55
 
56
-	logrus.Debugf(title+" - succeeded id=%s flavour=%d", id, info.Flavour)
56
+	logrus.Debugf(title+"succeeded flavour=%d id=%s", info.Flavour, id)
57 57
 	return nil
58 58
 }
... ...
@@ -12,7 +12,7 @@ import (
12 12
 // id, including that layer's containing folder, if any.
13 13
 func DestroyLayer(info DriverInfo, id string) error {
14 14
 	title := "hcsshim::DestroyLayer "
15
-	logrus.Debugf(title+"Flavour %s ID %s", info.Flavour, id)
15
+	logrus.Debugf(title+"Flavour %d ID %s", info.Flavour, id)
16 16
 
17 17
 	// Load the DLL and get a handle to the procedure we need
18 18
 	dll, proc, err := loadAndFind(procDestroyLayer)
... ...
@@ -54,6 +54,6 @@ func DestroyLayer(info DriverInfo, id string) error {
54 54
 		return err
55 55
 	}
56 56
 
57
-	logrus.Debugf(title+" - succeeded id=%s flavour=%d", id, info.Flavour)
57
+	logrus.Debugf(title+"succeeded flavour=%d id=%s", info.Flavour, id)
58 58
 	return nil
59 59
 }
... ...
@@ -83,6 +83,6 @@ func ExportLayer(info DriverInfo, layerId string, exportFolderPath string, paren
83 83
 		return err
84 84
 	}
85 85
 
86
-	logrus.Debugf(title+"- succeeded layerId=%s flavour=%d folder=%s", layerId, info.Flavour, exportFolderPath)
86
+	logrus.Debugf(title+"succeeded flavour=%d layerId=%s folder=%s", info.Flavour, layerId, exportFolderPath)
87 87
 	return nil
88 88
 }
... ...
@@ -14,7 +14,7 @@ import (
14 14
 // folder path at which the layer is stored.
15 15
 func GetLayerMountPath(info DriverInfo, id string) (string, error) {
16 16
 	title := "hcsshim::GetLayerMountPath "
17
-	logrus.Debugf(title+"Flavour %s ID %s", info.Flavour, id)
17
+	logrus.Debugf(title+"Flavour %d ID %s", info.Flavour, id)
18 18
 
19 19
 	// Load the DLL and get a handle to the procedure we need
20 20
 	dll, proc, err := loadAndFind(procGetLayerMountPath)
... ...
@@ -86,6 +86,6 @@ func GetLayerMountPath(info DriverInfo, id string) (string, error) {
86 86
 	}
87 87
 
88 88
 	path := syscall.UTF16ToString(mountPathp[0:])
89
-	logrus.Debugf(title+" - succeeded id=%s flavour=%d path=%s", id, info.Flavour, path)
89
+	logrus.Debugf(title+"succeeded flavour=%d id=%s path=%s", info.Flavour, id, path)
90 90
 	return path, nil
91 91
 }
... ...
@@ -46,6 +46,18 @@ const (
46 46
 
47 47
 	// Utility functions
48 48
 	procCoTaskMemFree = "CoTaskMemFree"
49
+
50
+	// Specific user-visible exit codes
51
+	WaitErrExecFailed = 32767
52
+
53
+	// Known Win32 RC values which should be trapped
54
+	Win32PipeHasBeenEnded                 = 0x8007006d // WaitForProcessInComputeSystem: The pipe has been ended
55
+	Win32SystemShutdownIsInProgress       = 0x8007045B // ShutdownComputeSystem: A system shutdown is in progress
56
+	Win32SpecifiedPathInvalid             = 0x800700A1 // ShutdownComputeSystem: The specified path is invalid
57
+	Win32SystemCannotFindThePathSpecified = 0x80070003 // ShutdownComputeSystem: The system cannot find the path specified
58
+
59
+	// Timeout on wait calls
60
+	TimeoutInfinite = 0xFFFFFFFF
49 61
 )
50 62
 
51 63
 // loadAndFindFromDll finds a procedure in the given DLL. Note we do NOT do lazy loading as
... ...
@@ -53,8 +65,6 @@ const (
53 53
 // if a function can't be found. By explicitly loading, we can control error
54 54
 // handling gracefully without the daemon terminating.
55 55
 func loadAndFindFromDll(dllName, procedure string) (dll *syscall.DLL, proc *syscall.Proc, err error) {
56
-	logrus.Debugf("hcsshim::loadAndFindFromDll %s %s", dllName, procedure)
57
-
58 56
 	dll, err = syscall.LoadDLL(dllName)
59 57
 	if err != nil {
60 58
 		err = fmt.Errorf("Failed to load %s - error %s", dllName, err)
... ...
@@ -82,6 +82,6 @@ func ImportLayer(info DriverInfo, layerId string, importFolderPath string, paren
82 82
 		return err
83 83
 	}
84 84
 
85
-	logrus.Debugf(title+"- succeeded layerId=%s flavour=%d folder=%s", layerId, info.Flavour, importFolderPath)
85
+	logrus.Debugf(title+"succeeded flavour=%d layerId=%s folder=%s", info.Flavour, layerId, importFolderPath)
86 86
 	return nil
87 87
 }
... ...
@@ -12,7 +12,7 @@ import (
12 12
 // to the system.
13 13
 func LayerExists(info DriverInfo, id string) (bool, error) {
14 14
 	title := "hcsshim::LayerExists "
15
-	logrus.Debugf(title+"Flavour %s ID %s", info.Flavour, id)
15
+	logrus.Debugf(title+"Flavour %d ID %s", info.Flavour, id)
16 16
 
17 17
 	// Load the DLL and get a handle to the procedure we need
18 18
 	dll, proc, err := loadAndFind(procLayerExists)
... ...
@@ -57,6 +57,6 @@ func LayerExists(info DriverInfo, id string) (bool, error) {
57 57
 		return false, err
58 58
 	}
59 59
 
60
-	logrus.Debugf(title+" - succeeded id=%s flavour=%d exists=%d", id, info.Flavour, exists)
60
+	logrus.Debugf(title+"succeeded flavour=%d id=%s exists=%d", info.Flavour, id, exists)
61 61
 	return exists, nil
62 62
 }
... ...
@@ -73,6 +73,6 @@ func PrepareLayer(info DriverInfo, layerId string, parentLayerPaths []string) er
73 73
 		return err
74 74
 	}
75 75
 
76
-	logrus.Debugf(title+"- succeeded layerId=%s flavour=%d", layerId, info.Flavour)
76
+	logrus.Debugf(title+"succeeded flavour=%d layerId=%s", info.Flavour, layerId)
77 77
 	return nil
78 78
 }
... ...
@@ -42,7 +42,7 @@ func ResizeConsoleInComputeSystem(id string, processid uint32, h, w int) error {
42 42
 		return err
43 43
 	}
44 44
 
45
-	logrus.Debugf(title+" - succeeded id=%s processid=%d (%d,%d)", id, processid, h, w)
45
+	logrus.Debugf(title+" succeeded id=%s processid=%d (%d,%d)", id, processid, h, w)
46 46
 	return nil
47 47
 
48 48
 }
49 49
deleted file mode 100644
... ...
@@ -1,50 +0,0 @@
1
-package hcsshim
2
-
3
-import (
4
-	"fmt"
5
-	"syscall"
6
-	"unsafe"
7
-
8
-	"github.com/Sirupsen/logrus"
9
-)
10
-
11
-// ShutdownComputeSystem shuts down a container by requesting a shutdown within
12
-// the container operating system.
13
-func ShutdownComputeSystem(id string) error {
14
-
15
-	var title = "HCSShim::ShutdownComputeSystem"
16
-	logrus.Debugf(title+" id=%s", id)
17
-
18
-	// Load the DLL and get a handle to the procedure we need
19
-	dll, proc, err := loadAndFind(procShutdownComputeSystem)
20
-	if dll != nil {
21
-		defer dll.Release()
22
-	}
23
-	if err != nil {
24
-		return err
25
-	}
26
-
27
-	// Convert id to uint16 pointers for calling the procedure
28
-	idp, err := syscall.UTF16PtrFromString(id)
29
-	if err != nil {
30
-		err = fmt.Errorf(title+" - Failed conversion of id %s to pointer %s", id, err)
31
-		logrus.Error(err)
32
-		return err
33
-	}
34
-
35
-	timeout := uint32(0xffffffff)
36
-
37
-	// Call the procedure itself.
38
-	r1, _, err := proc.Call(
39
-		uintptr(unsafe.Pointer(idp)), uintptr(timeout))
40
-
41
-	use(unsafe.Pointer(idp))
42
-
43
-	if r1 != 0 {
44
-		err = fmt.Errorf(title+" - Win32 API call returned error r1=%d err=%s id=%s", r1, syscall.Errno(r1), id)
45
-		return syscall.Errno(r1)
46
-	}
47
-
48
-	logrus.Debugf(title+" - succeeded id=%s", id)
49
-	return nil
50
-}
51 1
new file mode 100644
... ...
@@ -0,0 +1,69 @@
0
+package hcsshim
1
+
2
+import (
3
+	"fmt"
4
+	"syscall"
5
+	"unsafe"
6
+
7
+	"github.com/Sirupsen/logrus"
8
+)
9
+
10
+// TerminateComputeSystem force terminates a container.
11
+func TerminateComputeSystem(id string, timeout uint32, context string) (uint32, error) {
12
+	return shutdownTerminate(false, id, timeout, context)
13
+}
14
+
15
+// ShutdownComputeSystem shuts down a container by requesting a shutdown within
16
+// the container operating system.
17
+func ShutdownComputeSystem(id string, timeout uint32, context string) (uint32, error) {
18
+	return shutdownTerminate(true, id, timeout, context)
19
+}
20
+
21
+// shutdownTerminate is a wrapper for ShutdownComputeSystem and TerminateComputeSystem
22
+// which have very similar calling semantics
23
+func shutdownTerminate(shutdown bool, id string, timeout uint32, context string) (uint32, error) {
24
+
25
+	var (
26
+		title    = "HCSShim::"
27
+		procName string
28
+	)
29
+	if shutdown {
30
+		title = title + "ShutdownComputeSystem"
31
+		procName = procShutdownComputeSystem
32
+	} else {
33
+		title = title + "TerminateComputeSystem"
34
+		procName = procTerminateComputeSystem
35
+	}
36
+	logrus.Debugf(title+" id=%s context=%s", id, context)
37
+
38
+	// Load the DLL and get a handle to the procedure we need
39
+	dll, proc, err := loadAndFind(procName)
40
+	if dll != nil {
41
+		defer dll.Release()
42
+	}
43
+	if err != nil {
44
+		return 0xffffffff, err
45
+	}
46
+
47
+	// Convert id to uint16 pointers for calling the procedure
48
+	idp, err := syscall.UTF16PtrFromString(id)
49
+	if err != nil {
50
+		err = fmt.Errorf(title+" - Failed conversion of id %s to pointer %s", id, err)
51
+		logrus.Error(err)
52
+		return 0xffffffff, err
53
+	}
54
+
55
+	// Call the procedure itself.
56
+	r1, _, err := proc.Call(
57
+		uintptr(unsafe.Pointer(idp)), uintptr(timeout))
58
+
59
+	use(unsafe.Pointer(idp))
60
+
61
+	if r1 != 0 {
62
+		err = fmt.Errorf(title+" - Win32 API call returned error r1=0x%X err=%s id=%s context=%s", r1, syscall.Errno(r1), id, context)
63
+		return uint32(r1), err
64
+	}
65
+
66
+	logrus.Debugf(title+" succeeded id=%s context=%s", id, context)
67
+	return 0, nil
68
+}
... ...
@@ -43,6 +43,6 @@ func StartComputeSystem(id string) error {
43 43
 		return err
44 44
 	}
45 45
 
46
-	logrus.Debugf("HCSShim::StartComputeSystem - succeeded id=%s", id)
46
+	logrus.Debugf(title+" succeeded id=%s", id)
47 47
 	return nil
48 48
 }
49 49
deleted file mode 100644
... ...
@@ -1,49 +0,0 @@
1
-package hcsshim
2
-
3
-import (
4
-	"fmt"
5
-	"syscall"
6
-	"unsafe"
7
-
8
-	"github.com/Sirupsen/logrus"
9
-)
10
-
11
-// TerminateComputeSystem force terminates a container.
12
-func TerminateComputeSystem(id string) error {
13
-
14
-	var title = "HCSShim::TerminateComputeSystem"
15
-	logrus.Debugf(title+" id=%s", id)
16
-
17
-	// Load the DLL and get a handle to the procedure we need
18
-	dll, proc, err := loadAndFind(procTerminateComputeSystem)
19
-	if dll != nil {
20
-		defer dll.Release()
21
-	}
22
-	if err != nil {
23
-		return err
24
-	}
25
-
26
-	// Convert id to uint16 pointers for calling the procedure
27
-	idp, err := syscall.UTF16PtrFromString(id)
28
-	if err != nil {
29
-		err = fmt.Errorf(title+" - Failed conversion of id %s to pointer %s", id, err)
30
-		logrus.Error(err)
31
-		return err
32
-	}
33
-
34
-	timeout := uint32(0xffffffff)
35
-
36
-	// Call the procedure itself.
37
-	r1, _, err := proc.Call(
38
-		uintptr(unsafe.Pointer(idp)), uintptr(timeout))
39
-
40
-	use(unsafe.Pointer(idp))
41
-
42
-	if r1 != 0 {
43
-		err = fmt.Errorf(title+" - Win32 API call returned error r1=%d err=%s id=%s", r1, syscall.Errno(r1), id)
44
-		return syscall.Errno(r1)
45
-	}
46
-
47
-	logrus.Debugf(title+" - succeeded id=%s", id)
48
-	return nil
49
-}
... ...
@@ -44,6 +44,6 @@ func TerminateProcessInComputeSystem(id string, processid uint32) (err error) {
44 44
 		return err
45 45
 	}
46 46
 
47
-	logrus.Debugf(title+" - succeeded id=%s", id)
47
+	logrus.Debugf(title+" succeeded id=%s", id)
48 48
 	return nil
49 49
 }
... ...
@@ -54,6 +54,6 @@ func UnprepareLayer(info DriverInfo, layerId string) error {
54 54
 		return err
55 55
 	}
56 56
 
57
-	logrus.Debugf(title+"- succeeded layerId=%s flavour=%d", layerId, info.Flavour)
57
+	logrus.Debugf(title+"succeeded flavour %d layerId=%s", info.Flavour, layerId)
58 58
 	return nil
59 59
 }
... ...
@@ -9,21 +9,19 @@ import (
9 9
 )
10 10
 
11 11
 // WaitForProcessInComputeSystem waits for a process ID to terminate and returns
12
-// the exit code.
13
-func WaitForProcessInComputeSystem(id string, processid uint32) (exitcode int32, err error) {
12
+// the exit code. Returns exitcode, errno, error
13
+func WaitForProcessInComputeSystem(id string, processid uint32, timeout uint32) (int32, uint32, error) {
14 14
 
15 15
 	title := "HCSShim::WaitForProcessInComputeSystem"
16 16
 	logrus.Debugf(title+" id=%s processid=%d", id, processid)
17 17
 
18
-	var timeout uint32 = 0xFFFFFFFF // (-1/INFINITE)
19
-
20 18
 	// Load the DLL and get a handle to the procedure we need
21 19
 	dll, proc, err := loadAndFind(procWaitForProcessInComputeSystem)
22 20
 	if dll != nil {
23 21
 		defer dll.Release()
24 22
 	}
25 23
 	if err != nil {
26
-		return 0, err
24
+		return 0, 0, err
27 25
 	}
28 26
 
29 27
 	// Convert id to uint16 pointer for calling the procedure
... ...
@@ -31,7 +29,7 @@ func WaitForProcessInComputeSystem(id string, processid uint32) (exitcode int32,
31 31
 	if err != nil {
32 32
 		err = fmt.Errorf(title+" - Failed conversion of id %s to pointer %s", id, err)
33 33
 		logrus.Error(err)
34
-		return 0, err
34
+		return 0, 0, err
35 35
 	}
36 36
 
37 37
 	// To get a POINTER to the ExitCode
... ...
@@ -47,10 +45,10 @@ func WaitForProcessInComputeSystem(id string, processid uint32) (exitcode int32,
47 47
 	use(unsafe.Pointer(idp))
48 48
 
49 49
 	if r1 != 0 {
50
-		err = fmt.Errorf(title+" - Win32 API call returned error r1=%d err=%s id=%s", r1, syscall.Errno(r1), id)
51
-		return 0, err
50
+		err = fmt.Errorf(title+" - Win32 API call returned error r1=0x%X err=%s id=%s", r1, syscall.Errno(r1), id)
51
+		return 0, uint32(r1), err
52 52
 	}
53 53
 
54
-	logrus.Debugf(title+" - succeeded id=%s processid=%d exitcode=%d", id, processid, *ec)
55
-	return *ec, nil
54
+	logrus.Debugf(title+" succeeded id=%s processid=%d exitcode=%d", id, processid, *ec)
55
+	return *ec, 0, nil
56 56
 }