Browse code

Change Docker to use the new HCS RPC API

Signed-off-by: Darren Stahl <darst@microsoft.com>

Darren Stahl authored on 2016/05/24 08:12:06
Showing 16 changed files
... ...
@@ -43,7 +43,7 @@ esac
43 43
 
44 44
 # the following lines are in sorted order, FYI
45 45
 clone git github.com/Azure/go-ansiterm 388960b655244e76e24c75f48631564eaefade62
46
-clone git github.com/Microsoft/hcsshim v0.2.2
46
+clone git github.com/Microsoft/hcsshim v0.3.0
47 47
 clone git github.com/Microsoft/go-winio v0.3.4
48 48
 clone git github.com/Sirupsen/logrus v0.10.0 # logrus is a common dependency among multiple deps
49 49
 clone git github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
... ...
@@ -1,7 +1,6 @@
1 1
 package libcontainerd
2 2
 
3 3
 import (
4
-	"encoding/json"
5 4
 	"errors"
6 5
 	"fmt"
7 6
 	"io"
... ...
@@ -29,76 +28,6 @@ const (
29 29
 	ErrorInvalidObject = syscall.Errno(0x800710D8) // The object identifier does not represent a valid object
30 30
 )
31 31
 
32
-type layer struct {
33
-	ID   string
34
-	Path string
35
-}
36
-
37
-type defConfig struct {
38
-	DefFile string
39
-}
40
-
41
-type portBinding struct {
42
-	Protocol     string
43
-	InternalPort int
44
-	ExternalPort int
45
-}
46
-
47
-type natSettings struct {
48
-	Name         string
49
-	PortBindings []portBinding
50
-}
51
-
52
-type networkConnection struct {
53
-	NetworkName string
54
-	Nat         natSettings
55
-}
56
-type networkSettings struct {
57
-	MacAddress string
58
-}
59
-
60
-type device struct {
61
-	DeviceType string
62
-	Connection interface{}
63
-	Settings   interface{}
64
-}
65
-
66
-type mappedDir struct {
67
-	HostPath      string
68
-	ContainerPath string
69
-	ReadOnly      bool
70
-}
71
-
72
-type hvRuntime struct {
73
-	ImagePath string `json:",omitempty"`
74
-}
75
-
76
-// TODO Windows: @darrenstahlmsft Add ProcessorCount
77
-type containerInit struct {
78
-	SystemType              string      // HCS requires this to be hard-coded to "Container"
79
-	Name                    string      // Name of the container. We use the docker ID.
80
-	Owner                   string      // The management platform that created this container
81
-	IsDummy                 bool        // Used for development purposes.
82
-	VolumePath              string      // Windows volume path for scratch space
83
-	Devices                 []device    // Devices used by the container
84
-	IgnoreFlushesDuringBoot bool        // Optimization hint for container startup in Windows
85
-	LayerFolderPath         string      // Where the layer folders are located
86
-	Layers                  []layer     // List of storage layers
87
-	ProcessorWeight         uint64      `json:",omitempty"` // CPU Shares 0..10000 on Windows; where 0 will be omitted and HCS will default.
88
-	ProcessorMaximum        int64       `json:",omitempty"` // CPU maximum usage percent 1..100
89
-	StorageIOPSMaximum      uint64      `json:",omitempty"` // Maximum Storage IOPS
90
-	StorageBandwidthMaximum uint64      `json:",omitempty"` // Maximum Storage Bandwidth in bytes per second
91
-	StorageSandboxSize      uint64      `json:",omitempty"` // Size in bytes that the container system drive should be expanded to if smaller
92
-	MemoryMaximumInMB       int64       `json:",omitempty"` // Maximum memory available to the container in Megabytes
93
-	HostName                string      // Hostname
94
-	MappedDirectories       []mappedDir // List of mapped directories (volumes/mounts)
95
-	SandboxPath             string      // Location of unmounted sandbox (used for Hyper-V containers)
96
-	HvPartition             bool        // True if it a Hyper-V Container
97
-	EndpointList            []string    // List of networking endpoints to be attached to container
98
-	HvRuntime               *hvRuntime  // Hyper-V container settings
99
-	Servicing               bool        // True if this container is for servicing
100
-}
101
-
102 32
 // defaultOwner is a tag passed to HCS to allow it to differentiate between
103 33
 // container creator management stacks. We hard code "docker" in the case
104 34
 // of docker.
... ...
@@ -109,7 +38,7 @@ const defaultOwner = "docker"
109 109
 func (clnt *client) Create(containerID string, spec Spec, options ...CreateOption) error {
110 110
 	logrus.Debugln("LCD client.Create() with spec", spec)
111 111
 
112
-	cu := &containerInit{
112
+	configuration := &hcsshim.ContainerConfig{
113 113
 		SystemType: "Container",
114 114
 		Name:       containerID,
115 115
 		Owner:      defaultOwner,
... ...
@@ -121,90 +50,84 @@ func (clnt *client) Create(containerID string, spec Spec, options ...CreateOptio
121 121
 	}
122 122
 
123 123
 	if spec.Windows.Networking != nil {
124
-		cu.EndpointList = spec.Windows.Networking.EndpointList
124
+		configuration.EndpointList = spec.Windows.Networking.EndpointList
125 125
 	}
126 126
 
127 127
 	if spec.Windows.Resources != nil {
128 128
 		if spec.Windows.Resources.CPU != nil {
129 129
 			if spec.Windows.Resources.CPU.Shares != nil {
130
-				cu.ProcessorWeight = *spec.Windows.Resources.CPU.Shares
130
+				configuration.ProcessorWeight = *spec.Windows.Resources.CPU.Shares
131 131
 			}
132 132
 			if spec.Windows.Resources.CPU.Percent != nil {
133
-				cu.ProcessorMaximum = *spec.Windows.Resources.CPU.Percent * 100 // ProcessorMaximum is a value between 1 and 10000
133
+				configuration.ProcessorMaximum = *spec.Windows.Resources.CPU.Percent * 100 // ProcessorMaximum is a value between 1 and 10000
134 134
 			}
135 135
 		}
136 136
 		if spec.Windows.Resources.Memory != nil {
137 137
 			if spec.Windows.Resources.Memory.Limit != nil {
138
-				cu.MemoryMaximumInMB = *spec.Windows.Resources.Memory.Limit / 1024 / 1024
138
+				configuration.MemoryMaximumInMB = *spec.Windows.Resources.Memory.Limit / 1024 / 1024
139 139
 			}
140 140
 		}
141 141
 		if spec.Windows.Resources.Storage != nil {
142 142
 			if spec.Windows.Resources.Storage.Bps != nil {
143
-				cu.StorageBandwidthMaximum = *spec.Windows.Resources.Storage.Bps
143
+				configuration.StorageBandwidthMaximum = *spec.Windows.Resources.Storage.Bps
144 144
 			}
145 145
 			if spec.Windows.Resources.Storage.Iops != nil {
146
-				cu.StorageIOPSMaximum = *spec.Windows.Resources.Storage.Iops
146
+				configuration.StorageIOPSMaximum = *spec.Windows.Resources.Storage.Iops
147 147
 			}
148 148
 			if spec.Windows.Resources.Storage.SandboxSize != nil {
149
-				cu.StorageSandboxSize = *spec.Windows.Resources.Storage.SandboxSize
149
+				configuration.StorageSandboxSize = *spec.Windows.Resources.Storage.SandboxSize
150 150
 			}
151 151
 		}
152 152
 	}
153 153
 
154 154
 	if spec.Windows.HvRuntime != nil {
155
-		cu.HvPartition = true
156
-		cu.HvRuntime = &hvRuntime{
155
+		configuration.HvPartition = true
156
+		configuration.HvRuntime = &hcsshim.HvRuntime{
157 157
 			ImagePath: spec.Windows.HvRuntime.ImagePath,
158 158
 		}
159 159
 	}
160 160
 
161
+	if configuration.HvPartition {
162
+		configuration.SandboxPath = filepath.Dir(spec.Windows.LayerFolder)
163
+	} else {
164
+		configuration.VolumePath = spec.Root.Path
165
+		configuration.LayerFolderPath = spec.Windows.LayerFolder
166
+	}
167
+
161 168
 	for _, option := range options {
162 169
 		if s, ok := option.(*ServicingOption); ok {
163
-			cu.Servicing = s.IsServicing
170
+			configuration.Servicing = s.IsServicing
164 171
 			break
165 172
 		}
166 173
 	}
167 174
 
168
-	if cu.HvPartition {
169
-		cu.SandboxPath = filepath.Dir(spec.Windows.LayerFolder)
170
-	} else {
171
-		cu.VolumePath = spec.Root.Path
172
-		cu.LayerFolderPath = spec.Windows.LayerFolder
173
-	}
174
-
175 175
 	for _, layerPath := range spec.Windows.LayerPaths {
176 176
 		_, filename := filepath.Split(layerPath)
177 177
 		g, err := hcsshim.NameToGuid(filename)
178 178
 		if err != nil {
179 179
 			return err
180 180
 		}
181
-		cu.Layers = append(cu.Layers, layer{
181
+		configuration.Layers = append(configuration.Layers, hcsshim.Layer{
182 182
 			ID:   g.ToString(),
183 183
 			Path: layerPath,
184 184
 		})
185 185
 	}
186 186
 
187 187
 	// Add the mounts (volumes, bind mounts etc) to the structure
188
-	mds := make([]mappedDir, len(spec.Mounts))
188
+	mds := make([]hcsshim.MappedDir, len(spec.Mounts))
189 189
 	for i, mount := range spec.Mounts {
190
-		mds[i] = mappedDir{
190
+		mds[i] = hcsshim.MappedDir{
191 191
 			HostPath:      mount.Source,
192 192
 			ContainerPath: mount.Destination,
193 193
 			ReadOnly:      mount.Readonly}
194 194
 	}
195
-	cu.MappedDirectories = mds
195
+	configuration.MappedDirectories = mds
196 196
 
197
-	configurationb, err := json.Marshal(cu)
197
+	hcsContainer, err := hcsshim.CreateContainer(containerID, configuration)
198 198
 	if err != nil {
199 199
 		return err
200 200
 	}
201 201
 
202
-	// Create the compute system
203
-	configuration := string(configurationb)
204
-	if err := hcsshim.CreateComputeSystem(containerID, configuration); err != nil {
205
-		return err
206
-	}
207
-
208 202
 	// Construct a container object for calling start on it.
209 203
 	container := &container{
210 204
 		containerCommon: containerCommon{
... ...
@@ -218,7 +141,8 @@ func (clnt *client) Create(containerID string, spec Spec, options ...CreateOptio
218 218
 			},
219 219
 			processes: make(map[string]*process),
220 220
 		},
221
-		ociSpec: spec,
221
+		ociSpec:      spec,
222
+		hcsContainer: hcsContainer,
222 223
 	}
223 224
 
224 225
 	container.options = options
... ...
@@ -252,10 +176,17 @@ func (clnt *client) AddProcess(containerID, processFriendlyName string, procToAd
252 252
 	if err != nil {
253 253
 		return err
254 254
 	}
255
-
256
-	createProcessParms := hcsshim.CreateProcessParams{
257
-		EmulateConsole: procToAdd.Terminal,
258
-		ConsoleSize:    procToAdd.InitialConsoleSize,
255
+	// Note we always tell HCS to
256
+	// create stdout as it's required regardless of '-i' or '-t' options, so that
257
+	// docker can always grab the output through logs. We also tell HCS to always
258
+	// create stdin, even if it's not used - it will be closed shortly. Stderr
259
+	// is only created if it we're not -t.
260
+	createProcessParms := hcsshim.ProcessConfig{
261
+		EmulateConsole:   procToAdd.Terminal,
262
+		ConsoleSize:      procToAdd.InitialConsoleSize,
263
+		CreateStdInPipe:  true,
264
+		CreateStdOutPipe: true,
265
+		CreateStdErrPipe: !procToAdd.Terminal,
259 266
 	}
260 267
 
261 268
 	// Take working directory from the process to add if it is defined,
... ...
@@ -272,25 +203,24 @@ func (clnt *client) AddProcess(containerID, processFriendlyName string, procToAd
272 272
 
273 273
 	logrus.Debugf("commandLine: %s", createProcessParms.CommandLine)
274 274
 
275
-	// Start the command running in the container. Note we always tell HCS to
276
-	// create stdout as it's required regardless of '-i' or '-t' options, so that
277
-	// docker can always grab the output through logs. We also tell HCS to always
278
-	// create stdin, even if it's not used - it will be closed shortly. Stderr
279
-	// is only created if it we're not -t.
275
+	// Start the command running in the container.
280 276
 	var stdout, stderr io.ReadCloser
281
-	var pid uint32
282
-	iopipe := &IOPipe{Terminal: procToAdd.Terminal}
283
-	pid, iopipe.Stdin, stdout, stderr, err = hcsshim.CreateProcessInComputeSystem(
284
-		containerID,
285
-		true,
286
-		true,
287
-		!procToAdd.Terminal,
288
-		createProcessParms)
277
+	var stdin io.WriteCloser
278
+	newProcess, err := container.hcsContainer.CreateProcess(&createProcessParms)
279
+	if err != nil {
280
+		logrus.Errorf("AddProcess %s CreateProcess() failed %s", containerID, err)
281
+		return err
282
+	}
283
+
284
+	stdin, stdout, stderr, err = newProcess.Stdio()
289 285
 	if err != nil {
290
-		logrus.Errorf("AddProcess %s CreateProcessInComputeSystem() failed %s", containerID, err)
286
+		logrus.Errorf("%s getting std pipes failed %s", containerID, err)
291 287
 		return err
292 288
 	}
293 289
 
290
+	iopipe := &IOPipe{Terminal: procToAdd.Terminal}
291
+	iopipe.Stdin = createStdInCloser(stdin, newProcess)
292
+
294 293
 	// TEMP: Work around Windows BS/DEL behavior.
295 294
 	iopipe.Stdin = fixStdinBackspaceBehavior(iopipe.Stdin, procToAdd.Terminal)
296 295
 
... ...
@@ -302,17 +232,21 @@ func (clnt *client) AddProcess(containerID, processFriendlyName string, procToAd
302 302
 		iopipe.Stderr = openReaderFromPipe(stderr)
303 303
 	}
304 304
 
305
-	// Add the process to the containers list of processes
306
-	container.processes[processFriendlyName] =
307
-		&process{
308
-			processCommon: processCommon{
309
-				containerID:  containerID,
310
-				friendlyName: processFriendlyName,
311
-				client:       clnt,
312
-				systemPid:    pid,
313
-			},
314
-			commandLine: createProcessParms.CommandLine,
315
-		}
305
+	pid := newProcess.Pid()
306
+
307
+	proc := &process{
308
+		processCommon: processCommon{
309
+			containerID:  containerID,
310
+			friendlyName: processFriendlyName,
311
+			client:       clnt,
312
+			systemPid:    uint32(pid),
313
+		},
314
+		commandLine: createProcessParms.CommandLine,
315
+		hcsProcess:  newProcess,
316
+	}
317
+
318
+	// Add the process to the container's list of processes
319
+	container.processes[processFriendlyName] = proc
316 320
 
317 321
 	// Make sure the lock is not held while calling back into the daemon
318 322
 	clnt.unlock(containerID)
... ...
@@ -326,7 +260,7 @@ func (clnt *client) AddProcess(containerID, processFriendlyName string, procToAd
326 326
 	clnt.lock(containerID)
327 327
 
328 328
 	// Spin up a go routine waiting for exit to handle cleanup
329
-	go container.waitExit(pid, processFriendlyName, false)
329
+	go container.waitExit(proc, false)
330 330
 
331 331
 	return nil
332 332
 }
... ...
@@ -350,16 +284,17 @@ func (clnt *client) Signal(containerID string, sig int) error {
350 350
 	cont.manualStopRequested = true
351 351
 
352 352
 	logrus.Debugf("lcd: Signal() containerID=%s sig=%d pid=%d", containerID, sig, cont.systemPid)
353
-	context := fmt.Sprintf("Signal: sig=%d pid=%d", sig, cont.systemPid)
354 353
 
355 354
 	if syscall.Signal(sig) == syscall.SIGKILL {
356 355
 		// Terminate the compute system
357
-		if err := hcsshim.TerminateComputeSystem(containerID, hcsshim.TimeoutInfinite, context); err != nil {
358
-			logrus.Errorf("Failed to terminate %s - %q", containerID, err)
356
+		if err := cont.hcsContainer.Terminate(); err != nil {
357
+			if err != hcsshim.ErrVmcomputeOperationPending {
358
+				logrus.Errorf("Failed to terminate %s - %q", containerID, err)
359
+			}
359 360
 		}
360 361
 	} else {
361 362
 		// Terminate Process
362
-		if err = hcsshim.TerminateProcessInComputeSystem(containerID, cont.systemPid); err != nil {
363
+		if err := cont.hcsProcess.Kill(); err != nil {
363 364
 			logrus.Warnf("Failed to terminate pid %d in %s: %q", cont.systemPid, containerID, err)
364 365
 			// Ignore errors
365 366
 			err = nil
... ...
@@ -380,15 +315,17 @@ func (clnt *client) Resize(containerID, processFriendlyName string, width, heigh
380 380
 		return err
381 381
 	}
382 382
 
383
+	h, w := uint16(height), uint16(width)
384
+
383 385
 	if processFriendlyName == InitFriendlyName {
384 386
 		logrus.Debugln("Resizing systemPID in", containerID, cont.process.systemPid)
385
-		return hcsshim.ResizeConsoleInComputeSystem(containerID, cont.process.systemPid, height, width)
387
+		return cont.process.hcsProcess.ResizeConsole(w, h)
386 388
 	}
387 389
 
388 390
 	for _, p := range cont.processes {
389 391
 		if p.friendlyName == processFriendlyName {
390 392
 			logrus.Debugln("Resizing exec'd process", containerID, p.systemPid)
391
-			return hcsshim.ResizeConsoleInComputeSystem(containerID, p.systemPid, height, width)
393
+			return p.hcsProcess.ResizeConsole(w, h)
392 394
 		}
393 395
 	}
394 396
 
... ...
@@ -22,6 +22,7 @@ type container struct {
22 22
 	ociSpec Spec
23 23
 
24 24
 	manualStopRequested bool
25
+	hcsContainer        hcsshim.Container
25 26
 }
26 27
 
27 28
 func (ctr *container) newProcess(friendlyName string) *process {
... ...
@@ -40,7 +41,7 @@ func (ctr *container) start() error {
40 40
 	// Start the container.  If this is a servicing container, this call will block
41 41
 	// until the container is done with the servicing execution.
42 42
 	logrus.Debugln("Starting container ", ctr.containerID)
43
-	if err = hcsshim.StartComputeSystem(ctr.containerID); err != nil {
43
+	if err = ctr.hcsContainer.Start(); err != nil {
44 44
 		logrus.Errorf("Failed to start compute system: %s", err)
45 45
 		return err
46 46
 	}
... ...
@@ -49,59 +50,61 @@ func (ctr *container) start() error {
49 49
 		if s, ok := option.(*ServicingOption); ok && s.IsServicing {
50 50
 			// Since the servicing operation is complete when StartCommputeSystem returns without error,
51 51
 			// we can shutdown (which triggers merge) and exit early.
52
-			const shutdownTimeout = 5 * 60 * 1000  // 4 minutes
53
-			const terminateTimeout = 1 * 60 * 1000 // 1 minute
54
-			if err := hcsshim.ShutdownComputeSystem(ctr.containerID, shutdownTimeout, ""); err != nil {
55
-				logrus.Errorf("Failed during cleanup of servicing container: %s", err)
56
-				// Terminate the container, ignoring errors.
57
-				if err2 := hcsshim.TerminateComputeSystem(ctr.containerID, terminateTimeout, ""); err2 != nil {
58
-					logrus.Errorf("Failed to terminate container %s after shutdown failure: %q", ctr.containerID, err2)
59
-				}
60
-				return err
61
-			}
62
-			return nil
52
+			return ctr.shutdown()
63 53
 		}
64 54
 	}
65 55
 
66
-	createProcessParms := hcsshim.CreateProcessParams{
56
+	// Note we always tell HCS to
57
+	// create stdout as it's required regardless of '-i' or '-t' options, so that
58
+	// docker can always grab the output through logs. We also tell HCS to always
59
+	// create stdin, even if it's not used - it will be closed shortly. Stderr
60
+	// is only created if it we're not -t.
61
+	createProcessParms := &hcsshim.ProcessConfig{
67 62
 		EmulateConsole:   ctr.ociSpec.Process.Terminal,
68 63
 		WorkingDirectory: ctr.ociSpec.Process.Cwd,
69 64
 		ConsoleSize:      ctr.ociSpec.Process.InitialConsoleSize,
65
+		CreateStdInPipe:  true,
66
+		CreateStdOutPipe: true,
67
+		CreateStdErrPipe: !ctr.ociSpec.Process.Terminal,
70 68
 	}
71 69
 
72 70
 	// Configure the environment for the process
73 71
 	createProcessParms.Environment = setupEnvironmentVariables(ctr.ociSpec.Process.Env)
74 72
 	createProcessParms.CommandLine = strings.Join(ctr.ociSpec.Process.Args, " ")
75 73
 
76
-	iopipe := &IOPipe{Terminal: ctr.ociSpec.Process.Terminal}
77
-
78
-	// Start the command running in the container. Note we always tell HCS to
79
-	// create stdout as it's required regardless of '-i' or '-t' options, so that
80
-	// docker can always grab the output through logs. We also tell HCS to always
81
-	// create stdin, even if it's not used - it will be closed shortly. Stderr
82
-	// is only created if it we're not -t.
83
-	var pid uint32
84
-	var stdout, stderr io.ReadCloser
85
-	pid, iopipe.Stdin, stdout, stderr, err = hcsshim.CreateProcessInComputeSystem(
86
-		ctr.containerID,
87
-		true,
88
-		true,
89
-		!ctr.ociSpec.Process.Terminal,
90
-		createProcessParms)
74
+	// Start the command running in the container.
75
+	hcsProcess, err := ctr.hcsContainer.CreateProcess(createProcessParms)
91 76
 	if err != nil {
92
-		logrus.Errorf("CreateProcessInComputeSystem() failed %s", err)
93
-
94
-		// Explicitly terminate the compute system here.
95
-		if err2 := hcsshim.TerminateComputeSystem(ctr.containerID, hcsshim.TimeoutInfinite, "CreateProcessInComputeSystem failed"); err2 != nil {
96
-			// Ignore this error, there's not a lot we can do except log it
97
-			logrus.Warnf("Failed to TerminateComputeSystem after a failed CreateProcessInComputeSystem. Ignoring this.", err2)
77
+		logrus.Errorf("CreateProcess() failed %s", err)
78
+		if err2 := ctr.terminate(); err2 != nil {
79
+			logrus.Debugf("Failed to cleanup after a failed CreateProcess. Ignoring this. %s", err2)
98 80
 		} else {
99
-			logrus.Debugln("Cleaned up after failed CreateProcessInComputeSystem by calling TerminateComputeSystem")
81
+			logrus.Debugln("Cleaned up after failed CreateProcess by calling Terminate")
100 82
 		}
101 83
 		return err
102 84
 	}
103 85
 	ctr.startedAt = time.Now()
104 86
 
87
+	// Save the hcs Process and PID
88
+	ctr.process.friendlyName = InitFriendlyName
89
+	pid := hcsProcess.Pid()
90
+	ctr.process.hcsProcess = hcsProcess
91
+
92
+	var stdout, stderr io.ReadCloser
93
+	var stdin io.WriteCloser
94
+	stdin, stdout, stderr, err = hcsProcess.Stdio()
95
+	if err != nil {
96
+		logrus.Errorf("failed to get stdio pipes: %s", err)
97
+		if err := ctr.terminate(); err != nil {
98
+			logrus.Debugf("Failed to cleanup after a failed CreateProcess. Ignoring this. %s", err)
99
+		}
100
+		return err
101
+	}
102
+
103
+	iopipe := &IOPipe{Terminal: ctr.ociSpec.Process.Terminal}
104
+
105
+	iopipe.Stdin = createStdInCloser(stdin, hcsProcess)
106
+
105 107
 	// TEMP: Work around Windows BS/DEL behavior.
106 108
 	iopipe.Stdin = fixStdinBackspaceBehavior(iopipe.Stdin, ctr.ociSpec.Process.Terminal)
107 109
 
... ...
@@ -118,7 +121,7 @@ func (ctr *container) start() error {
118 118
 	ctr.systemPid = uint32(pid)
119 119
 
120 120
 	// Spin up a go routine waiting for exit to handle cleanup
121
-	go ctr.waitExit(pid, InitFriendlyName, true)
121
+	go ctr.waitExit(&ctr.process, true)
122 122
 
123 123
 	ctr.client.appendContainer(ctr)
124 124
 
... ...
@@ -140,17 +143,27 @@ func (ctr *container) start() error {
140 140
 // waitExit runs as a goroutine waiting for the process to exit. It's
141 141
 // equivalent to (in the linux containerd world) where events come in for
142 142
 // state change notifications from containerd.
143
-func (ctr *container) waitExit(pid uint32, processFriendlyName string, isFirstProcessToStart bool) error {
144
-	logrus.Debugln("waitExit on pid", pid)
143
+func (ctr *container) waitExit(process *process, isFirstProcessToStart bool) error {
144
+	logrus.Debugln("waitExit on pid", process.systemPid)
145 145
 
146 146
 	// Block indefinitely for the process to exit.
147
-	exitCode, err := hcsshim.WaitForProcessInComputeSystem(ctr.containerID, pid, hcsshim.TimeoutInfinite)
147
+	err := process.hcsProcess.Wait()
148 148
 	if err != nil {
149
-		if herr, ok := err.(*hcsshim.HcsError); ok && herr.Err != syscall.ERROR_BROKEN_PIPE {
149
+		if herr, ok := err.(*hcsshim.ProcessError); ok && herr.Err != syscall.ERROR_BROKEN_PIPE {
150 150
 			logrus.Warnf("WaitForProcessInComputeSystem failed (container may have been killed): %s", err)
151 151
 		}
152 152
 		// Fall through here, do not return. This ensures we attempt to continue the
153
-		// shutdown in HCS nad tell the docker engine that the process/container
153
+		// shutdown in HCS and tell the docker engine that the process/container
154
+		// has exited to avoid a container being dropped on the floor.
155
+	}
156
+
157
+	exitCode, err := process.hcsProcess.ExitCode()
158
+	if err != nil {
159
+		if herr, ok := err.(*hcsshim.ProcessError); ok && herr.Err != syscall.ERROR_BROKEN_PIPE {
160
+			logrus.Warnf("Unable to get exit code from container %s", ctr.containerID)
161
+		}
162
+		// Fall through here, do not return. This ensures we attempt to continue the
163
+		// shutdown in HCS and tell the docker engine that the process/container
154 164
 		// has exited to avoid a container being dropped on the floor.
155 165
 	}
156 166
 
... ...
@@ -159,46 +172,35 @@ func (ctr *container) waitExit(pid uint32, processFriendlyName string, isFirstPr
159 159
 		CommonStateInfo: CommonStateInfo{
160 160
 			State:     StateExit,
161 161
 			ExitCode:  uint32(exitCode),
162
-			Pid:       pid,
163
-			ProcessID: processFriendlyName,
162
+			Pid:       process.systemPid,
163
+			ProcessID: process.friendlyName,
164 164
 		},
165 165
 		UpdatePending: false,
166 166
 	}
167 167
 
168 168
 	// But it could have been an exec'd process which exited
169 169
 	if !isFirstProcessToStart {
170
+		if err := process.hcsProcess.Close(); err != nil {
171
+			logrus.Error(err)
172
+		}
170 173
 		si.State = StateExitProcess
171 174
 	} else {
172
-		// Since this is the init process, always call into vmcompute.dll to
173
-		// shutdown the container after we have completed.
174
-
175
-		propertyCheckFlag := 1 // Include update pending check.
176
-		csProperties, err := hcsshim.GetComputeSystemProperties(ctr.containerID, uint32(propertyCheckFlag))
175
+		updatePending, err := ctr.hcsContainer.HasPendingUpdates()
177 176
 		if err != nil {
178
-			logrus.Warnf("GetComputeSystemProperties failed (container may have been killed): %s", err)
177
+			logrus.Warnf("HasPendingUpdates failed (container may have been killed): %s", err)
179 178
 		} else {
180
-			si.UpdatePending = csProperties.AreUpdatesPending
179
+			si.UpdatePending = updatePending
181 180
 		}
182 181
 
183 182
 		logrus.Debugf("Shutting down container %s", ctr.containerID)
184
-		// Explicit timeout here rather than hcsshim.TimeoutInfinte to avoid a
185
-		// (remote) possibility that ShutdownComputeSystem hangs indefinitely.
186
-		const shutdownTimeout = 5 * 60 * 1000 // 5 minutes
187
-		if err := hcsshim.ShutdownComputeSystem(ctr.containerID, shutdownTimeout, "waitExit"); err != nil {
188
-			if herr, ok := err.(*hcsshim.HcsError); !ok ||
189
-				(herr.Err != hcsshim.ERROR_SHUTDOWN_IN_PROGRESS &&
190
-					herr.Err != ErrorBadPathname &&
191
-					herr.Err != syscall.ERROR_PATH_NOT_FOUND) {
192
-				logrus.Debugf("waitExit - error from ShutdownComputeSystem on %s %v. Calling TerminateComputeSystem", ctr.containerCommon, err)
193
-				if err := hcsshim.TerminateComputeSystem(ctr.containerID, shutdownTimeout, "waitExit"); err != nil {
194
-					logrus.Debugf("waitExit - ignoring error from TerminateComputeSystem %s %v", ctr.containerID, err)
195
-				} else {
196
-					logrus.Debugf("Successful TerminateComputeSystem after failed ShutdownComputeSystem on %s in waitExit", ctr.containerID)
197
-				}
198
-			}
183
+		if err := ctr.shutdown(); err != nil {
184
+			logrus.Debugf("Failed to shutdown container %s", ctr.containerID)
199 185
 		} else {
200 186
 			logrus.Debugf("Completed shutting down container %s", ctr.containerID)
201 187
 		}
188
+		if err := ctr.hcsContainer.Close(); err != nil {
189
+			logrus.Error(err)
190
+		}
202 191
 
203 192
 		if !ctr.manualStopRequested && ctr.restartManager != nil {
204 193
 			restart, wait, err := ctr.restartManager.ShouldRestart(uint32(exitCode), false, time.Since(ctr.startedAt))
... ...
@@ -227,6 +229,9 @@ func (ctr *container) waitExit(pid uint32, processFriendlyName string, isFirstPr
227 227
 		// Remove process from list if we have exited
228 228
 		// We need to do so here in case the Message Handler decides to restart it.
229 229
 		if si.State == StateExit {
230
+			if err := ctr.hcsContainer.Close(); err != nil {
231
+				logrus.Error(err)
232
+			}
230 233
 			ctr.client.deleteContainer(ctr.friendlyName)
231 234
 		}
232 235
 	}
... ...
@@ -240,3 +245,37 @@ func (ctr *container) waitExit(pid uint32, processFriendlyName string, isFirstPr
240 240
 	logrus.Debugln("waitExit() completed OK")
241 241
 	return nil
242 242
 }
243
+
244
+func (ctr *container) shutdown() error {
245
+	const shutdownTimeout = time.Minute * 5
246
+	err := ctr.hcsContainer.Shutdown()
247
+	if err == hcsshim.ErrVmcomputeOperationPending {
248
+		// Explicit timeout to avoid a (remote) possibility that shutdown hangs indefinitely.
249
+		err = ctr.hcsContainer.WaitTimeout(shutdownTimeout)
250
+	}
251
+
252
+	if err != nil {
253
+		logrus.Debugf("error shutting down container %s %v calling terminate", ctr.containerID, err)
254
+		if err := ctr.terminate(); err != nil {
255
+			return err
256
+		}
257
+		return err
258
+	}
259
+
260
+	return nil
261
+}
262
+
263
+func (ctr *container) terminate() error {
264
+	const terminateTimeout = time.Minute * 5
265
+	err := ctr.hcsContainer.Terminate()
266
+
267
+	if err == hcsshim.ErrVmcomputeOperationPending {
268
+		err = ctr.hcsContainer.WaitTimeout(terminateTimeout)
269
+	}
270
+
271
+	if err != nil {
272
+		return err
273
+	}
274
+
275
+	return nil
276
+}
... ...
@@ -3,6 +3,7 @@ package libcontainerd
3 3
 import (
4 4
 	"io"
5 5
 
6
+	"github.com/Microsoft/hcsshim"
6 7
 	"github.com/docker/docker/pkg/system"
7 8
 )
8 9
 
... ...
@@ -14,6 +15,7 @@ type process struct {
14 14
 
15 15
 	// commandLine is to support returning summary information for docker top
16 16
 	commandLine string
17
+	hcsProcess  hcsshim.Process
17 18
 }
18 19
 
19 20
 func openReaderFromPipe(p io.ReadCloser) io.Reader {
... ...
@@ -57,3 +59,27 @@ func (w *delToBsWriter) Write(b []byte) (int, error) {
57 57
 	}
58 58
 	return w.WriteCloser.Write(bc)
59 59
 }
60
+
61
+type stdInCloser struct {
62
+	io.WriteCloser
63
+	hcsshim.Process
64
+}
65
+
66
+func createStdInCloser(pipe io.WriteCloser, process hcsshim.Process) *stdInCloser {
67
+	return &stdInCloser{
68
+		WriteCloser: pipe,
69
+		Process:     process,
70
+	}
71
+}
72
+
73
+func (stdin *stdInCloser) Close() error {
74
+	if err := stdin.WriteCloser.Close(); err != nil {
75
+		return err
76
+	}
77
+
78
+	return stdin.Process.CloseStdin()
79
+}
80
+
81
+func (stdin *stdInCloser) Write(p []byte) (n int, err error) {
82
+	return stdin.WriteCloser.Write(p)
83
+}
... ...
@@ -62,20 +62,17 @@ func (w *baseLayerWriter) Add(name string, fileInfo *winio.FileBasicInfo) (err e
62 62
 		}
63 63
 	}()
64 64
 
65
-	err = winio.RunWithPrivileges([]string{winio.SeBackupPrivilege, winio.SeRestorePrivilege}, func() (err error) {
66
-		createmode := uint32(syscall.CREATE_NEW)
67
-		if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
68
-			err := os.Mkdir(path, 0)
69
-			if err != nil && !os.IsExist(err) {
70
-				return err
71
-			}
72
-			createmode = syscall.OPEN_EXISTING
65
+	createmode := uint32(syscall.CREATE_NEW)
66
+	if fileInfo.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
67
+		err := os.Mkdir(path, 0)
68
+		if err != nil && !os.IsExist(err) {
69
+			return err
73 70
 		}
71
+		createmode = syscall.OPEN_EXISTING
72
+	}
74 73
 
75
-		mode := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | winio.WRITE_DAC | winio.WRITE_OWNER | winio.ACCESS_SYSTEM_SECURITY)
76
-		f, err = winio.OpenForBackup(path, mode, syscall.FILE_SHARE_READ, createmode)
77
-		return
78
-	})
74
+	mode := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | winio.WRITE_DAC | winio.WRITE_OWNER | winio.ACCESS_SYSTEM_SECURITY)
75
+	f, err = winio.OpenForBackup(path, mode, syscall.FILE_SHARE_READ, createmode)
79 76
 	if err != nil {
80 77
 		return err
81 78
 	}
... ...
@@ -113,9 +110,7 @@ func (w *baseLayerWriter) AddLink(name string, target string) (err error) {
113 113
 		return err
114 114
 	}
115 115
 
116
-	return winio.RunWithPrivileges([]string{winio.SeBackupPrivilege, winio.SeRestorePrivilege}, func() (err error) {
117
-		return os.Link(linktarget, linkpath)
118
-	})
116
+	return os.Link(linktarget, linkpath)
119 117
 }
120 118
 
121 119
 func (w *baseLayerWriter) Remove(name string) error {
... ...
@@ -123,11 +118,7 @@ func (w *baseLayerWriter) Remove(name string) error {
123 123
 }
124 124
 
125 125
 func (w *baseLayerWriter) Write(b []byte) (int, error) {
126
-	var n int
127
-	err := winio.RunWithPrivileges([]string{winio.SeBackupPrivilege, winio.SeRestorePrivilege}, func() (err error) {
128
-		n, err = w.bw.Write(b)
129
-		return
130
-	})
126
+	n, err := w.bw.Write(b)
131 127
 	if err != nil {
132 128
 		w.err = err
133 129
 	}
134 130
new file mode 100644
... ...
@@ -0,0 +1,78 @@
0
+package hcsshim
1
+
2
+import (
3
+	"errors"
4
+	"sync"
5
+	"syscall"
6
+)
7
+
8
+var (
9
+	nextCallback    uintptr
10
+	callbackMap     = map[uintptr]*notifcationWatcherContext{}
11
+	callbackMapLock = sync.RWMutex{}
12
+
13
+	notificationWatcherCallback = syscall.NewCallback(notificationWatcher)
14
+
15
+	// Notifications for HCS_SYSTEM handles
16
+	hcsNotificationSystemExited          hcsNotification = 0x00000001
17
+	hcsNotificationSystemCreateCompleted hcsNotification = 0x00000002
18
+	hcsNotificationSystemStartCompleted  hcsNotification = 0x00000003
19
+	hcsNotificationSystemPauseCompleted  hcsNotification = 0x00000004
20
+	hcsNotificationSystemResumeCompleted hcsNotification = 0x00000005
21
+
22
+	// Notifications for HCS_PROCESS handles
23
+	hcsNotificationProcessExited hcsNotification = 0x00010000
24
+
25
+	// Common notifications
26
+	hcsNotificationInvalid           hcsNotification = 0x00000000
27
+	hcsNotificationServiceDisconnect hcsNotification = 0x01000000
28
+
29
+	// ErrUnexpectedContainerExit is the error returned when a container exits while waiting for
30
+	// a different expected notification
31
+	ErrUnexpectedContainerExit = errors.New("unexpected container exit")
32
+
33
+	// ErrUnexpectedProcessAbort is the error returned when communication with the compute service
34
+	// is lost while waiting for a notification
35
+	ErrUnexpectedProcessAbort = errors.New("lost communication with compute service")
36
+)
37
+
38
+type hcsNotification uint32
39
+type notificationChannel chan error
40
+
41
+type notifcationWatcherContext struct {
42
+	channel              notificationChannel
43
+	expectedNotification hcsNotification
44
+	handle               hcsCallback
45
+}
46
+
47
+func notificationWatcher(notificationType hcsNotification, callbackNumber uintptr, notificationStatus uintptr, notificationData *uint16) uintptr {
48
+	var (
49
+		result       error
50
+		completeWait = false
51
+	)
52
+
53
+	callbackMapLock.RLock()
54
+	context := callbackMap[callbackNumber]
55
+	callbackMapLock.RUnlock()
56
+
57
+	if notificationType == context.expectedNotification {
58
+		if int32(notificationStatus) < 0 {
59
+			result = syscall.Errno(win32FromHresult(notificationStatus))
60
+		} else {
61
+			result = nil
62
+		}
63
+		completeWait = true
64
+	} else if notificationType == hcsNotificationSystemExited {
65
+		result = ErrUnexpectedContainerExit
66
+		completeWait = true
67
+	} else if notificationType == hcsNotificationServiceDisconnect {
68
+		result = ErrUnexpectedProcessAbort
69
+		completeWait = true
70
+	}
71
+
72
+	if completeWait {
73
+		context.channel <- result
74
+	}
75
+
76
+	return 0
77
+}
0 78
new file mode 100644
... ...
@@ -0,0 +1,513 @@
0
+package hcsshim
1
+
2
+import (
3
+	"encoding/json"
4
+	"errors"
5
+	"fmt"
6
+	"runtime"
7
+	"syscall"
8
+	"time"
9
+
10
+	"github.com/Sirupsen/logrus"
11
+)
12
+
13
+var (
14
+	defaultTimeout = time.Minute * 4
15
+
16
+	// ErrTimeout is an error encountered when waiting on a notification times out
17
+	ErrTimeout = errors.New("hcsshim: timeout waiting for notification")
18
+)
19
+
20
+type ContainerError struct {
21
+	Container *container
22
+	Operation string
23
+	ExtraInfo string
24
+	Err       error
25
+}
26
+
27
+type container struct {
28
+	handle hcsSystem
29
+	id     string
30
+}
31
+
32
+type containerProperties struct {
33
+	ID                string `json:"Id"`
34
+	Name              string
35
+	SystemType        string
36
+	Owner             string
37
+	SiloGUID          string `json:"SiloGuid,omitempty"`
38
+	IsDummy           bool   `json:",omitempty"`
39
+	RuntimeID         string `json:"RuntimeId,omitempty"`
40
+	Stopped           bool   `json:",omitempty"`
41
+	ExitType          string `json:",omitempty"`
42
+	AreUpdatesPending bool   `json:",omitempty"`
43
+}
44
+
45
+// CreateContainer creates a new container with the given configuration but does not start it.
46
+func CreateContainer(id string, c *ContainerConfig) (Container, error) {
47
+	operation := "CreateContainer"
48
+	title := "HCSShim::" + operation
49
+	logrus.Debugf(title+" id=%s", id)
50
+
51
+	container := &container{
52
+		id: id,
53
+	}
54
+
55
+	configurationb, err := json.Marshal(c)
56
+	if err != nil {
57
+		return nil, err
58
+	}
59
+
60
+	configuration := string(configurationb)
61
+
62
+	var (
63
+		handle      hcsSystem
64
+		resultp     *uint16
65
+		createError error
66
+	)
67
+	if hcsCallbacksSupported {
68
+		var identity syscall.Handle
69
+		createError = hcsCreateComputeSystem(id, configuration, identity, &handle, &resultp)
70
+	} else {
71
+		createError = hcsCreateComputeSystemTP5(id, configuration, &handle, &resultp)
72
+	}
73
+	container.handle = handle
74
+
75
+	err = processAsyncHcsResult(container, createError, resultp, hcsNotificationSystemCreateCompleted, &defaultTimeout)
76
+	if err != nil {
77
+		err := &ContainerError{Container: container, Operation: operation, ExtraInfo: configuration, Err: err}
78
+		logrus.Error(err)
79
+		return nil, err
80
+	}
81
+
82
+	logrus.Debugf(title+" succeeded id=%s handle=%d", id, container.handle)
83
+	runtime.SetFinalizer(container, closeContainer)
84
+	return container, nil
85
+}
86
+
87
+// OpenContainer opens an existing container by ID.
88
+func OpenContainer(id string) (Container, error) {
89
+	operation := "OpenContainer"
90
+	title := "HCSShim::" + operation
91
+	logrus.Debugf(title+" id=%s", id)
92
+
93
+	container := &container{
94
+		id: id,
95
+	}
96
+
97
+	var (
98
+		handle  hcsSystem
99
+		resultp *uint16
100
+	)
101
+	err := hcsOpenComputeSystem(id, &handle, &resultp)
102
+	err = processHcsResult(err, resultp)
103
+	if err != nil {
104
+		err = &ContainerError{Container: container, Operation: operation, Err: err}
105
+		logrus.Error(err)
106
+		return nil, err
107
+	}
108
+
109
+	container.handle = handle
110
+
111
+	logrus.Debugf(title+" succeeded id=%s handle=%d", id, handle)
112
+	runtime.SetFinalizer(container, closeContainer)
113
+	return container, nil
114
+}
115
+
116
+// Start synchronously starts the container.
117
+func (container *container) Start() error {
118
+	operation := "Start"
119
+	title := "HCSShim::Container::" + operation
120
+	logrus.Debugf(title+" id=%s", container.id)
121
+
122
+	var resultp *uint16
123
+	err := hcsStartComputeSystemTP5(container.handle, nil, &resultp)
124
+	err = processAsyncHcsResult(container, err, resultp, hcsNotificationSystemStartCompleted, &defaultTimeout)
125
+	if err != nil {
126
+		err := &ContainerError{Container: container, Operation: operation, Err: err}
127
+		logrus.Error(err)
128
+		return err
129
+	}
130
+
131
+	logrus.Debugf(title+" succeeded id=%s", container.id)
132
+	return nil
133
+}
134
+
135
+// Shutdown requests a container shutdown, but it may not actually be shut down until Wait() succeeds.
136
+// It returns ErrVmcomputeOperationPending if the shutdown is in progress, nil if the shutdown is complete.
137
+func (container *container) Shutdown() error {
138
+	operation := "Shutdown"
139
+	title := "HCSShim::Container::" + operation
140
+	logrus.Debugf(title+" id=%s", container.id)
141
+
142
+	var resultp *uint16
143
+	err := hcsShutdownComputeSystemTP5(container.handle, nil, &resultp)
144
+	err = processHcsResult(err, resultp)
145
+	if err != nil {
146
+		if err == ErrVmcomputeOperationPending {
147
+			return ErrVmcomputeOperationPending
148
+		}
149
+		err = &ContainerError{Container: container, Operation: operation, Err: err}
150
+		logrus.Error(err)
151
+		return err
152
+	}
153
+
154
+	logrus.Debugf(title+" succeeded id=%s", container.id)
155
+	return nil
156
+}
157
+
158
+// Terminate requests a container terminate, but it may not actually be terminated until Wait() succeeds.
159
+// It returns ErrVmcomputeOperationPending if the shutdown is in progress, nil if the shutdown is complete.
160
+func (container *container) Terminate() error {
161
+	operation := "Terminate"
162
+	title := "HCSShim::Container::" + operation
163
+	logrus.Debugf(title+" id=%s", container.id)
164
+
165
+	var resultp *uint16
166
+	err := hcsTerminateComputeSystemTP5(container.handle, nil, &resultp)
167
+	err = processHcsResult(err, resultp)
168
+	if err != nil {
169
+		if err == ErrVmcomputeOperationPending {
170
+			return ErrVmcomputeOperationPending
171
+		}
172
+		err = &ContainerError{Container: container, Operation: operation, Err: err}
173
+		logrus.Error(err)
174
+		return err
175
+	}
176
+
177
+	logrus.Debugf(title+" succeeded id=%s", container.id)
178
+	return nil
179
+}
180
+
181
+// Wait synchronously waits for the container to shutdown or terminate.
182
+func (container *container) Wait() error {
183
+	operation := "Wait"
184
+	title := "HCSShim::Container::" + operation
185
+	logrus.Debugf(title+" id=%s", container.id)
186
+
187
+	if hcsCallbacksSupported {
188
+		err := registerAndWaitForCallback(container, hcsNotificationSystemExited)
189
+		if err != nil {
190
+			err := &ContainerError{Container: container, Operation: operation, Err: err}
191
+			logrus.Error(err)
192
+			return err
193
+		}
194
+	} else {
195
+		_, err := container.waitTimeoutInternal(syscall.INFINITE)
196
+		if err != nil {
197
+			err := &ContainerError{Container: container, Operation: operation, Err: err}
198
+			logrus.Error(err)
199
+			return err
200
+		}
201
+	}
202
+
203
+	logrus.Debugf(title+" succeeded id=%s", container.id)
204
+	return nil
205
+}
206
+
207
+func (container *container) waitTimeoutInternal(timeout uint32) (bool, error) {
208
+	return waitTimeoutInternalHelper(container, timeout)
209
+}
210
+
211
+// WaitTimeout synchronously waits for the container to terminate or the duration to elapse. It returns
212
+// ErrTimeout if the timeout duration expires before the container is shut down.
213
+func (container *container) WaitTimeout(timeout time.Duration) error {
214
+	operation := "WaitTimeout"
215
+	title := "HCSShim::Container::" + operation
216
+	logrus.Debugf(title+" id=%s", container.id)
217
+
218
+	if hcsCallbacksSupported {
219
+		err := registerAndWaitForCallbackTimeout(container, hcsNotificationSystemExited, timeout)
220
+		if err == ErrTimeout {
221
+			return ErrTimeout
222
+		} else if err != nil {
223
+			err := &ContainerError{Container: container, Operation: operation, Err: err}
224
+			logrus.Error(err)
225
+			return err
226
+		}
227
+	} else {
228
+		finished, err := waitTimeoutHelper(container, timeout)
229
+		if !finished {
230
+			return ErrTimeout
231
+		} else if err != nil {
232
+			err := &ContainerError{Container: container, Operation: operation, Err: err}
233
+			logrus.Error(err)
234
+			return err
235
+		}
236
+	}
237
+
238
+	logrus.Debugf(title+" succeeded id=%s", container.id)
239
+	return nil
240
+}
241
+
242
+func (container *container) hcsWait(timeout uint32) (bool, error) {
243
+	var (
244
+		resultp   *uint16
245
+		exitEvent syscall.Handle
246
+	)
247
+
248
+	err := hcsCreateComputeSystemWait(container.handle, &exitEvent, &resultp)
249
+	err = processHcsResult(err, resultp)
250
+	if err != nil {
251
+		return false, err
252
+	}
253
+	defer syscall.CloseHandle(exitEvent)
254
+
255
+	return waitForSingleObject(exitEvent, timeout)
256
+}
257
+
258
+func (container *container) properties() (*containerProperties, error) {
259
+	var (
260
+		resultp     *uint16
261
+		propertiesp *uint16
262
+	)
263
+	err := hcsGetComputeSystemProperties(container.handle, "", &propertiesp, &resultp)
264
+	err = processHcsResult(err, resultp)
265
+	if err != nil {
266
+		return nil, err
267
+	}
268
+
269
+	if propertiesp == nil {
270
+		return nil, errors.New("Unexpected result from hcsGetComputeSystemProperties, properties should never be nil")
271
+	}
272
+	propertiesRaw := convertAndFreeCoTaskMemBytes(propertiesp)
273
+
274
+	properties := &containerProperties{}
275
+	if err := json.Unmarshal(propertiesRaw, properties); err != nil {
276
+		return nil, err
277
+	}
278
+
279
+	return properties, nil
280
+}
281
+
282
+// HasPendingUpdates returns true if the container has updates pending to install
283
+func (container *container) HasPendingUpdates() (bool, error) {
284
+	operation := "HasPendingUpdates"
285
+	title := "HCSShim::Container::" + operation
286
+	logrus.Debugf(title+" id=%s", container.id)
287
+	properties, err := container.properties()
288
+	if err != nil {
289
+		err := &ContainerError{Container: container, Operation: operation, Err: err}
290
+		logrus.Error(err)
291
+		return false, err
292
+	}
293
+
294
+	logrus.Debugf(title+" succeeded id=%s", container.id)
295
+	return properties.AreUpdatesPending, nil
296
+}
297
+
298
+// Pause pauses the execution of the container. This feature is not enabled in TP5.
299
+func (container *container) Pause() error {
300
+	operation := "Pause"
301
+	title := "HCSShim::Container::" + operation
302
+	logrus.Debugf(title+" id=%s", container.id)
303
+
304
+	var resultp *uint16
305
+	err := hcsPauseComputeSystemTP5(container.handle, nil, &resultp)
306
+	err = processAsyncHcsResult(container, err, resultp, hcsNotificationSystemPauseCompleted, &defaultTimeout)
307
+	if err != nil {
308
+		err := &ContainerError{Container: container, Operation: operation, Err: err}
309
+		logrus.Error(err)
310
+		return err
311
+	}
312
+
313
+	logrus.Debugf(title+" succeeded id=%s", container.id)
314
+	return nil
315
+}
316
+
317
+// Resume resumes the execution of the container. This feature is not enabled in TP5.
318
+func (container *container) Resume() error {
319
+	operation := "Resume"
320
+	title := "HCSShim::Container::" + operation
321
+	logrus.Debugf(title+" id=%s", container.id)
322
+	var (
323
+		resultp *uint16
324
+	)
325
+
326
+	err := hcsResumeComputeSystemTP5(container.handle, nil, &resultp)
327
+	err = processAsyncHcsResult(container, err, resultp, hcsNotificationSystemResumeCompleted, &defaultTimeout)
328
+	if err != nil {
329
+		err := &ContainerError{Container: container, Operation: operation, Err: err}
330
+		logrus.Error(err)
331
+		return err
332
+	}
333
+
334
+	logrus.Debugf(title+" succeeded id=%s", container.id)
335
+	return nil
336
+}
337
+
338
+// CreateProcess launches a new process within the container.
339
+func (container *container) CreateProcess(c *ProcessConfig) (Process, error) {
340
+	operation := "CreateProcess"
341
+	title := "HCSShim::Container::" + operation
342
+	logrus.Debugf(title+" id=%s", container.id)
343
+	var (
344
+		processInfo   hcsProcessInformation
345
+		processHandle hcsProcess
346
+		resultp       *uint16
347
+	)
348
+
349
+	// If we are not emulating a console, ignore any console size passed to us
350
+	if !c.EmulateConsole {
351
+		c.ConsoleSize[0] = 0
352
+		c.ConsoleSize[1] = 0
353
+	}
354
+
355
+	configurationb, err := json.Marshal(c)
356
+	if err != nil {
357
+		return nil, err
358
+	}
359
+
360
+	configuration := string(configurationb)
361
+
362
+	err = hcsCreateProcess(container.handle, configuration, &processInfo, &processHandle, &resultp)
363
+	err = processHcsResult(err, resultp)
364
+	if err != nil {
365
+		err = &ContainerError{Container: container, Operation: operation, ExtraInfo: configuration, Err: err}
366
+		logrus.Error(err)
367
+		return nil, err
368
+	}
369
+
370
+	process := &process{
371
+		handle:    processHandle,
372
+		processID: int(processInfo.ProcessId),
373
+		container: container,
374
+		cachedPipes: &cachedPipes{
375
+			stdIn:  processInfo.StdInput,
376
+			stdOut: processInfo.StdOutput,
377
+			stdErr: processInfo.StdError,
378
+		},
379
+	}
380
+
381
+	logrus.Debugf(title+" succeeded id=%s processid=%s", container.id, process.processID)
382
+	runtime.SetFinalizer(process, closeProcess)
383
+	return process, nil
384
+}
385
+
386
+// OpenProcess gets an interface to an existing process within the container.
387
+func (container *container) OpenProcess(pid int) (Process, error) {
388
+	operation := "OpenProcess"
389
+	title := "HCSShim::Container::" + operation
390
+	logrus.Debugf(title+" id=%s, processid=%d", container.id, pid)
391
+	var (
392
+		processHandle hcsProcess
393
+		resultp       *uint16
394
+	)
395
+
396
+	err := hcsOpenProcess(container.handle, uint32(pid), &processHandle, &resultp)
397
+	err = processHcsResult(err, resultp)
398
+	if err != nil {
399
+		err = &ContainerError{Container: container, Operation: operation, Err: err}
400
+		logrus.Error(err)
401
+		return nil, err
402
+	}
403
+
404
+	process := &process{
405
+		handle:    processHandle,
406
+		processID: pid,
407
+		container: container,
408
+	}
409
+
410
+	logrus.Debugf(title+" succeeded id=%s processid=%s", container.id, process.processID)
411
+	runtime.SetFinalizer(process, closeProcess)
412
+	return process, nil
413
+}
414
+
415
+// Close cleans up any state associated with the container but does not terminate or wait for it.
416
+func (container *container) Close() error {
417
+	operation := "Close"
418
+	title := "HCSShim::Container::" + operation
419
+	logrus.Debugf(title+" id=%s", container.id)
420
+
421
+	// Don't double free this
422
+	if container.handle == 0 {
423
+		return nil
424
+	}
425
+
426
+	if err := hcsCloseComputeSystem(container.handle); err != nil {
427
+		err = &ContainerError{Container: container, Operation: operation, Err: err}
428
+		logrus.Error(err)
429
+		return err
430
+	}
431
+
432
+	container.handle = 0
433
+
434
+	logrus.Debugf(title+" succeeded id=%s", container.id)
435
+	return nil
436
+}
437
+
438
+// closeContainer wraps container.Close for use by a finalizer
439
+func closeContainer(container *container) {
440
+	container.Close()
441
+}
442
+
443
+func (container *container) registerCallback(expectedNotification hcsNotification) (uintptr, error) {
444
+	callbackMapLock.Lock()
445
+	defer callbackMapLock.Unlock()
446
+
447
+	callbackNumber := nextCallback
448
+	nextCallback++
449
+
450
+	context := &notifcationWatcherContext{
451
+		expectedNotification: expectedNotification,
452
+		channel:              make(chan error, 1),
453
+	}
454
+	callbackMap[callbackNumber] = context
455
+
456
+	var callbackHandle hcsCallback
457
+	err := hcsRegisterComputeSystemCallback(container.handle, notificationWatcherCallback, callbackNumber, &callbackHandle)
458
+	if err != nil {
459
+		return 0, err
460
+	}
461
+	context.handle = callbackHandle
462
+
463
+	return callbackNumber, nil
464
+}
465
+
466
+func (container *container) unregisterCallback(callbackNumber uintptr) error {
467
+	callbackMapLock.Lock()
468
+	defer callbackMapLock.Unlock()
469
+
470
+	handle := callbackMap[callbackNumber].handle
471
+
472
+	if handle == 0 {
473
+		return nil
474
+	}
475
+
476
+	err := hcsUnregisterComputeSystemCallback(handle)
477
+	if err != nil {
478
+		return err
479
+	}
480
+
481
+	callbackMap[callbackNumber] = nil
482
+
483
+	handle = 0
484
+
485
+	return nil
486
+}
487
+
488
+func (e *ContainerError) Error() string {
489
+	if e == nil {
490
+		return "<nil>"
491
+	}
492
+
493
+	if e.Container == nil {
494
+		return "unexpected nil container for error: " + e.Err.Error()
495
+	}
496
+
497
+	s := "container " + e.Container.id
498
+
499
+	if e.Operation != "" {
500
+		s += " encountered an error during " + e.Operation
501
+	}
502
+
503
+	if e.Err != nil {
504
+		s += fmt.Sprintf(" failed in Win32: %s (0x%x)", e.Err, win32FromError(e.Err))
505
+	}
506
+
507
+	if e.ExtraInfo != "" {
508
+		s += " extra info: " + e.ExtraInfo
509
+	}
510
+
511
+	return s
512
+}
... ...
@@ -112,7 +112,9 @@ func (r *FilterLayerReader) Close() (err error) {
112 112
 }
113 113
 
114 114
 // NewLayerReader returns a new layer reader for reading the contents of an on-disk layer.
115
-func NewLayerReader(info DriverInfo, layerId string, parentLayerPaths []string) (LayerReader, error) {
115
+// The caller must have taken the SeBackupPrivilege privilege
116
+// to call this and any methods on the resulting LayerReader.
117
+func NewLayerReader(info DriverInfo, layerID string, parentLayerPaths []string) (LayerReader, error) {
116 118
 	if procExportLayerBegin.Find() != nil {
117 119
 		// The new layer reader is not available on this Windows build. Fall back to the
118 120
 		// legacy export code path.
... ...
@@ -120,7 +122,7 @@ func NewLayerReader(info DriverInfo, layerId string, parentLayerPaths []string)
120 120
 		if err != nil {
121 121
 			return nil, err
122 122
 		}
123
-		err = ExportLayer(info, layerId, path, parentLayerPaths)
123
+		err = ExportLayer(info, layerID, path, parentLayerPaths)
124 124
 		if err != nil {
125 125
 			os.RemoveAll(path)
126 126
 			return nil, err
... ...
@@ -137,7 +139,7 @@ func NewLayerReader(info DriverInfo, layerId string, parentLayerPaths []string)
137 137
 		return nil, err
138 138
 	}
139 139
 	r := &FilterLayerReader{}
140
-	err = exportLayerBegin(&infop, layerId, layers, &r.context)
140
+	err = exportLayerBegin(&infop, layerID, layers, &r.context)
141 141
 	if err != nil {
142 142
 		return nil, makeError(err, "ExportLayerBegin", "")
143 143
 	}
... ...
@@ -7,6 +7,8 @@ import (
7 7
 	"fmt"
8 8
 	"syscall"
9 9
 	"unsafe"
10
+
11
+	"github.com/Sirupsen/logrus"
10 12
 )
11 13
 
12 14
 //go:generate go run mksyscall_windows.go -output zhcsshim.go hcsshim.go
... ...
@@ -50,6 +52,40 @@ import (
50 50
 //sys waitForProcessInComputeSystem(id string, pid uint32, timeout uint32, exitCode *uint32) (hr error) = vmcompute.WaitForProcessInComputeSystem?
51 51
 //sys getComputeSystemProperties(id string, flags uint32, properties **uint16) (hr error) = vmcompute.GetComputeSystemProperties?
52 52
 
53
+//sys hcsEnumerateComputeSystems(query string, computeSystems **uint16, result **uint16) (hr error) = vmcompute.HcsEnumerateComputeSystems?
54
+//sys hcsCreateComputeSystem(id string, configuration string, identity syscall.Handle, computeSystem *hcsSystem, result **uint16) (hr error) = vmcompute.HcsCreateComputeSystem?
55
+//sys hcsOpenComputeSystem(id string, computeSystem *hcsSystem, result **uint16) (hr error) = vmcompute.HcsOpenComputeSystem?
56
+//sys hcsCloseComputeSystem(computeSystem hcsSystem) (hr error) = vmcompute.HcsCloseComputeSystem?
57
+//sys hcsStartComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsStartComputeSystem?
58
+//sys hcsShutdownComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsShutdownComputeSystem?
59
+//sys hcsTerminateComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsTerminateComputeSystem?
60
+//sys hcsPauseComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsPauseComputeSystem?
61
+//sys hcsResumeComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsResumeComputeSystem?
62
+//sys hcsGetComputeSystemProperties(computeSystem hcsSystem, propertyQuery string, properties **uint16, result **uint16) (hr error) = vmcompute.HcsGetComputeSystemProperties?
63
+//sys hcsModifyComputeSystem(computeSystem hcsSystem, configuration string, result **uint16) (hr error) = vmcompute.HcsModifyComputeSystem?
64
+//sys hcsCreateComputeSystemWait(computeSystem hcsSystem, exitEvent *syscall.Handle, result **uint16) (hr error) = vmcompute.HcsCreateComputeSystemWait?
65
+//sys hcsCreateProcess(computeSystem hcsSystem, processParameters string, processInformation *hcsProcessInformation, process *hcsProcess, result **uint16) (hr error) = vmcompute.HcsCreateProcess?
66
+//sys hcsOpenProcess(computeSystem hcsSystem, pid uint32, process *hcsProcess, result **uint16) (hr error) = vmcompute.HcsOpenProcess?
67
+//sys hcsCloseProcess(process hcsProcess) (hr error) = vmcompute.HcsCloseProcess?
68
+//sys hcsTerminateProcess(process hcsProcess, result **uint16) (hr error) = vmcompute.HcsTerminateProcess?
69
+//sys hcsGetProcessInfo(process hcsProcess, processInformation *hcsProcessInformation, result **uint16) (hr error) = vmcompute.HcsGetProcessInfo?
70
+//sys hcsGetProcessProperties(process hcsProcess, processProperties **uint16, result **uint16) (hr error) = vmcompute.HcsGetProcessProperties?
71
+//sys hcsModifyProcess(process hcsProcess, settings string, result **uint16) (hr error) = vmcompute.HcsModifyProcess?
72
+//sys hcsCreateProcessWait(process hcsProcess, settings *syscall.Handle, result **uint16) (hr error) = vmcompute.HcsCreateProcessWait?
73
+//sys hcsGetServiceProperties(propertyQuery string, properties **uint16, result **uint16) (hr error) = vmcompute.HcsGetServiceProperties?
74
+//sys hcsModifyServiceSettings(settings string, result **uint16) (hr error) = vmcompute.HcsModifyServiceSettings?
75
+
76
+//sys hcsCreateComputeSystemTP5(id string, configuration string, computeSystem *hcsSystem, result **uint16) (hr error) = vmcompute.HcsCreateComputeSystem?
77
+//sys hcsStartComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) = vmcompute.HcsStartComputeSystem?
78
+//sys hcsShutdownComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) = vmcompute.HcsShutdownComputeSystem?
79
+//sys hcsTerminateComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) = vmcompute.HcsTerminateComputeSystem?
80
+//sys hcsPauseComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) = vmcompute.HcsPauseComputeSystem?
81
+//sys hcsResumeComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) = vmcompute.HcsResumeComputeSystem?
82
+//sys hcsRegisterComputeSystemCallback(computeSystem hcsSystem, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) = vmcompute.HcsRegisterComputeSystemCallback?
83
+//sys hcsUnregisterComputeSystemCallback(callbackHandle hcsCallback) (hr error) = vmcompute.HcsUnregisterComputeSystemCallback?
84
+//sys hcsRegisterProcessCallback(process hcsProcess, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) = vmcompute.HcsRegisterProcessCallback?
85
+//sys hcsUnregisterProcessCallback(callbackHandle hcsCallback) (hr error) = vmcompute.HcsUnregisterProcessCallback?
86
+
53 87
 //sys _hnsCall(method string, path string, object string, response **uint16) (hr error) = vmcompute.HNSCall?
54 88
 
55 89
 const (
... ...
@@ -60,6 +96,8 @@ const (
60 60
 	ERROR_SHUTDOWN_IN_PROGRESS = syscall.Errno(1115)
61 61
 	WSAEINVAL                  = syscall.Errno(10022)
62 62
 
63
+	ErrVmcomputeOperationPending = syscall.Errno(0xC0370103)
64
+
63 65
 	// Timeout on wait calls
64 66
 	TimeoutInfinite = 0xFFFFFFFF
65 67
 )
... ...
@@ -70,6 +108,18 @@ type HcsError struct {
70 70
 	Err   error
71 71
 }
72 72
 
73
+type hcsSystem syscall.Handle
74
+type hcsProcess syscall.Handle
75
+type hcsCallback syscall.Handle
76
+
77
+type hcsProcessInformation struct {
78
+	ProcessId uint32
79
+	Reserved  uint32
80
+	StdInput  syscall.Handle
81
+	StdOutput syscall.Handle
82
+	StdError  syscall.Handle
83
+}
84
+
73 85
 func makeError(err error, title, rest string) error {
74 86
 	// Pass through DLL errors directly since they do not originate from HCS.
75 87
 	if _, ok := err.(*syscall.DLLError); ok {
... ...
@@ -119,3 +169,15 @@ func convertAndFreeCoTaskMemString(buffer *uint16) string {
119 119
 	coTaskMemFree(unsafe.Pointer(buffer))
120 120
 	return str
121 121
 }
122
+
123
+func convertAndFreeCoTaskMemBytes(buffer *uint16) []byte {
124
+	return []byte(convertAndFreeCoTaskMemString(buffer))
125
+}
126
+
127
+func processHcsResult(err error, resultp *uint16) error {
128
+	if resultp != nil {
129
+		result := convertAndFreeCoTaskMemString(resultp)
130
+		logrus.Debugf("Result: %s", result)
131
+	}
132
+	return err
133
+}
... ...
@@ -148,6 +148,8 @@ func (r *legacyLayerWriterWrapper) Close() error {
148 148
 }
149 149
 
150 150
 // NewLayerWriter returns a new layer writer for creating a layer on disk.
151
+// The caller must have taken the SeBackupPrivilege and SeRestorePrivilege privileges
152
+// to call this and any methods on the resulting LayerWriter.
151 153
 func NewLayerWriter(info DriverInfo, layerID string, parentLayerPaths []string) (LayerWriter, error) {
152 154
 	if len(parentLayerPaths) == 0 {
153 155
 		// This is a base layer. It gets imported differently.
154 156
new file mode 100644
... ...
@@ -0,0 +1,147 @@
0
+package hcsshim
1
+
2
+import (
3
+	"io"
4
+	"time"
5
+)
6
+
7
+// ProcessConfig is used as both the input of Container.CreateProcess
8
+// and to convert the parameters to JSON for passing onto the HCS
9
+type ProcessConfig struct {
10
+	ApplicationName  string
11
+	CommandLine      string
12
+	WorkingDirectory string
13
+	Environment      map[string]string
14
+	EmulateConsole   bool
15
+	CreateStdInPipe  bool
16
+	CreateStdOutPipe bool
17
+	CreateStdErrPipe bool
18
+	ConsoleSize      [2]int
19
+}
20
+
21
+type Layer struct {
22
+	ID   string
23
+	Path string
24
+}
25
+
26
+type MappedDir struct {
27
+	HostPath      string
28
+	ContainerPath string
29
+	ReadOnly      bool
30
+}
31
+
32
+type HvRuntime struct {
33
+	ImagePath string `json:",omitempty"`
34
+}
35
+
36
+// ContainerConfig is used as both the input of CreateContainer
37
+// and to convert the parameters to JSON for passing onto the HCS
38
+// TODO Windows: @darrenstahlmsft Add ProcessorCount
39
+type ContainerConfig struct {
40
+	SystemType              string      // HCS requires this to be hard-coded to "Container"
41
+	Name                    string      // Name of the container. We use the docker ID.
42
+	Owner                   string      // The management platform that created this container
43
+	IsDummy                 bool        // Used for development purposes.
44
+	VolumePath              string      // Windows volume path for scratch space
45
+	IgnoreFlushesDuringBoot bool        // Optimization hint for container startup in Windows
46
+	LayerFolderPath         string      // Where the layer folders are located
47
+	Layers                  []Layer     // List of storage layers
48
+	ProcessorWeight         uint64      `json:",omitempty"` // CPU Shares 0..10000 on Windows; where 0 will be omitted and HCS will default.
49
+	ProcessorMaximum        int64       `json:",omitempty"` // CPU maximum usage percent 1..100
50
+	StorageIOPSMaximum      uint64      `json:",omitempty"` // Maximum Storage IOPS
51
+	StorageBandwidthMaximum uint64      `json:",omitempty"` // Maximum Storage Bandwidth in bytes per second
52
+	StorageSandboxSize      uint64      `json:",omitempty"` // Size in bytes that the container system drive should be expanded to if smaller
53
+	MemoryMaximumInMB       int64       `json:",omitempty"` // Maximum memory available to the container in Megabytes
54
+	HostName                string      // Hostname
55
+	MappedDirectories       []MappedDir // List of mapped directories (volumes/mounts)
56
+	SandboxPath             string      // Location of unmounted sandbox (used for Hyper-V containers)
57
+	HvPartition             bool        // True if it a Hyper-V Container
58
+	EndpointList            []string    // List of networking endpoints to be attached to container
59
+	HvRuntime               *HvRuntime  // Hyper-V container settings
60
+	Servicing               bool        // True if this container is for servicing
61
+}
62
+
63
+const (
64
+	notificationTypeNone           string = "None"
65
+	notificationTypeGracefulExit   string = "GracefulExit"
66
+	notificationTypeForcedExit     string = "ForcedExit"
67
+	notificationTypeUnexpectedExit string = "UnexpectedExit"
68
+	notificationTypeReboot         string = "Reboot"
69
+	notificationTypeConstructed    string = "Constructed"
70
+	notificationTypeStarted        string = "Started"
71
+	notificationTypePaused         string = "Paused"
72
+	notificationTypeUnknown        string = "Unknown"
73
+)
74
+
75
+// Container represents a created (but not necessarily running) container.
76
+type Container interface {
77
+	// Start synchronously starts the container.
78
+	Start() error
79
+
80
+	// Shutdown requests a container shutdown, but it may not actually be shutdown until Wait() succeeds.
81
+	Shutdown() error
82
+
83
+	// Terminate requests a container terminate, but it may not actually be terminated until Wait() succeeds.
84
+	Terminate() error
85
+
86
+	// Waits synchronously waits for the container to shutdown or terminate.
87
+	Wait() error
88
+
89
+	// WaitTimeout synchronously waits for the container to terminate or the duration to elapse. It
90
+	// returns false if timeout occurs.
91
+	WaitTimeout(time.Duration) error
92
+
93
+	// Pause pauses the execution of a container.
94
+	Pause() error
95
+
96
+	// Resume resumes the execution of a container.
97
+	Resume() error
98
+
99
+	// HasPendingUpdates returns true if the container has updates pending to install.
100
+	HasPendingUpdates() (bool, error)
101
+
102
+	// CreateProcess launches a new process within the container.
103
+	CreateProcess(c *ProcessConfig) (Process, error)
104
+
105
+	// OpenProcess gets an interface to an existing process within the container.
106
+	OpenProcess(pid int) (Process, error)
107
+
108
+	// Close cleans up any state associated with the container but does not terminate or wait for it.
109
+	Close() error
110
+}
111
+
112
+// Process represents a running or exited process.
113
+type Process interface {
114
+	// Pid returns the process ID of the process within the container.
115
+	Pid() int
116
+
117
+	// Kill signals the process to terminate but does not wait for it to finish terminating.
118
+	Kill() error
119
+
120
+	// Wait waits for the process to exit.
121
+	Wait() error
122
+
123
+	// WaitTimeout waits for the process to exit or the duration to elapse. It returns
124
+	// false if timeout occurs.
125
+	WaitTimeout(time.Duration) error
126
+
127
+	// ExitCode returns the exit code of the process. The process must have
128
+	// already terminated.
129
+	ExitCode() (int, error)
130
+
131
+	// ResizeConsole resizes the console of the process.
132
+	ResizeConsole(width, height uint16) error
133
+
134
+	// Stdio returns the stdin, stdout, and stderr pipes, respectively. Closing
135
+	// these pipes does not close the underlying pipes; it should be possible to
136
+	// call this multiple times to get multiple interfaces.
137
+	Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, error)
138
+
139
+	// CloseStdin closes the write side of the stdin pipe so that the process is
140
+	// notified on the read side that there is no more data in stdin.
141
+	CloseStdin() error
142
+
143
+	// Close cleans up any state associated with the process but does not kill
144
+	// or wait on it.
145
+	Close() error
146
+}
... ...
@@ -598,6 +598,19 @@ func (f *Fn) HasStringParam() bool {
598 598
 	return false
599 599
 }
600 600
 
601
+var uniqDllFuncName = make(map[string]bool)
602
+
603
+// IsNotDuplicate is true if f is not a duplicated function
604
+func (f *Fn) IsNotDuplicate() bool {
605
+	funcName := f.DLLFuncName()
606
+	if uniqDllFuncName[funcName] == false {
607
+		uniqDllFuncName[funcName] = true
608
+		return true
609
+	}
610
+
611
+	return false
612
+}
613
+
601 614
 // HelperName returns name of function f helper.
602 615
 func (f *Fn) HelperName() string {
603 616
 	if !f.HasStringParam() {
... ...
@@ -748,6 +761,7 @@ const srcTemplate = `
748 748
 
749 749
 package {{packagename}}
750 750
 
751
+import "github.com/Microsoft/go-winio"
751 752
 import "unsafe"{{if syscalldot}}
752 753
 import "syscall"{{end}}
753 754
 
... ...
@@ -764,7 +778,7 @@ var (
764 764
 {{define "dlls"}}{{range .DLLs}}	mod{{.}} = {{syscalldot}}NewLazyDLL("{{.}}.dll")
765 765
 {{end}}{{end}}
766 766
 
767
-{{define "funcnames"}}{{range .Funcs}}	proc{{.DLLFuncName}} = mod{{.DLLName}}.NewProc("{{.DLLFuncName}}")
767
+{{define "funcnames"}}{{range .Funcs}}{{if .IsNotDuplicate}}	proc{{.DLLFuncName}} = mod{{.DLLName}}.NewProc("{{.DLLFuncName}}"){{end}}
768 768
 {{end}}{{end}}
769 769
 
770 770
 {{define "helperbody"}}
771 771
new file mode 100644
... ...
@@ -0,0 +1,432 @@
0
+package hcsshim
1
+
2
+import (
3
+	"encoding/json"
4
+	"errors"
5
+	"fmt"
6
+	"io"
7
+	"syscall"
8
+	"time"
9
+
10
+	"github.com/Sirupsen/logrus"
11
+)
12
+
13
+var (
14
+	ErrInvalidProcessState = errors.New("the process is in an invalid state for the attempted operation")
15
+)
16
+
17
+type ProcessError struct {
18
+	Process   *process
19
+	Operation string
20
+	Err       error
21
+}
22
+
23
+type process struct {
24
+	handle             hcsProcess
25
+	processID          int
26
+	container          *container
27
+	cachedPipes        *cachedPipes
28
+	killCallbackNumber uintptr
29
+}
30
+
31
+type cachedPipes struct {
32
+	stdIn  syscall.Handle
33
+	stdOut syscall.Handle
34
+	stdErr syscall.Handle
35
+}
36
+
37
+type processModifyRequest struct {
38
+	Operation   string
39
+	ConsoleSize *consoleSize `json:",omitempty"`
40
+	CloseHandle *closeHandle `json:",omitempty"`
41
+}
42
+
43
+type consoleSize struct {
44
+	Height uint16
45
+	Width  uint16
46
+}
47
+
48
+type closeHandle struct {
49
+	Handle string
50
+}
51
+
52
+type processStatus struct {
53
+	ProcessId      uint32
54
+	Exited         bool
55
+	ExitCode       uint32
56
+	LastWaitResult int32
57
+}
58
+
59
+const (
60
+	stdIn  string = "StdIn"
61
+	stdOut string = "StdOut"
62
+	stdErr string = "StdErr"
63
+)
64
+
65
+const (
66
+	modifyConsoleSize string = "ConsoleSize"
67
+	modifyCloseHandle string = "CloseHandle"
68
+)
69
+
70
+// Pid returns the process ID of the process within the container.
71
+func (process *process) Pid() int {
72
+	return process.processID
73
+}
74
+
75
+// Kill signals the process to terminate but does not wait for it to finish terminating.
76
+func (process *process) Kill() error {
77
+	operation := "Kill"
78
+	title := "HCSShim::Process::" + operation
79
+	logrus.Debugf(title+" processid=%d", process.processID)
80
+
81
+	var resultp *uint16
82
+	err := hcsTerminateProcess(process.handle, &resultp)
83
+	err = processHcsResult(err, resultp)
84
+	if err == ErrVmcomputeOperationPending {
85
+		return ErrVmcomputeOperationPending
86
+	} else if err != nil {
87
+		err := &ProcessError{Operation: operation, Process: process, Err: err}
88
+		logrus.Error(err)
89
+		return err
90
+	}
91
+
92
+	logrus.Debugf(title+" succeeded processid=%d", process.processID)
93
+	return nil
94
+}
95
+
96
+// Wait waits for the process to exit.
97
+func (process *process) Wait() error {
98
+	operation := "Wait"
99
+	title := "HCSShim::Process::" + operation
100
+	logrus.Debugf(title+" processid=%d", process.processID)
101
+
102
+	if hcsCallbacksSupported {
103
+		err := registerAndWaitForCallback(process, hcsNotificationProcessExited)
104
+		if err != nil {
105
+			err := &ProcessError{Operation: operation, Process: process, Err: err}
106
+			logrus.Error(err)
107
+			return err
108
+		}
109
+	} else {
110
+		_, err := process.waitTimeoutInternal(syscall.INFINITE)
111
+		if err != nil {
112
+			err := &ProcessError{Operation: operation, Process: process, Err: err}
113
+			logrus.Error(err)
114
+			return err
115
+		}
116
+	}
117
+
118
+	logrus.Debugf(title+" succeeded processid=%d", process.processID)
119
+	return nil
120
+}
121
+
122
+// WaitTimeout waits for the process to exit or the duration to elapse. It returns
123
+// false if timeout occurs.
124
+func (process *process) WaitTimeout(timeout time.Duration) error {
125
+	operation := "WaitTimeout"
126
+	title := "HCSShim::Process::" + operation
127
+	logrus.Debugf(title+" processid=%d", process.processID)
128
+
129
+	if hcsCallbacksSupported {
130
+		err := registerAndWaitForCallbackTimeout(process, hcsNotificationProcessExited, timeout)
131
+		if err == ErrTimeout {
132
+			return ErrTimeout
133
+		} else if err != nil {
134
+			err := &ProcessError{Operation: operation, Process: process, Err: err}
135
+			logrus.Error(err)
136
+			return err
137
+		}
138
+	} else {
139
+		finished, err := waitTimeoutHelper(process, timeout)
140
+		if !finished {
141
+			return ErrTimeout
142
+		} else if err != nil {
143
+			err := &ProcessError{Operation: operation, Process: process, Err: err}
144
+			logrus.Error(err)
145
+			return err
146
+		}
147
+	}
148
+
149
+	logrus.Debugf(title+" succeeded processid=%d", process.processID)
150
+	return nil
151
+}
152
+
153
+func (process *process) hcsWait(timeout uint32) (bool, error) {
154
+	var (
155
+		resultp   *uint16
156
+		exitEvent syscall.Handle
157
+	)
158
+	err := hcsCreateProcessWait(process.handle, &exitEvent, &resultp)
159
+	err = processHcsResult(err, resultp)
160
+	if err != nil {
161
+		return false, err
162
+	}
163
+	defer syscall.CloseHandle(exitEvent)
164
+
165
+	return waitForSingleObject(exitEvent, timeout)
166
+}
167
+
168
+func (process *process) waitTimeoutInternal(timeout uint32) (bool, error) {
169
+	return waitTimeoutInternalHelper(process, timeout)
170
+}
171
+
172
+// ExitCode returns the exit code of the process. The process must have
173
+// already terminated.
174
+func (process *process) ExitCode() (int, error) {
175
+	operation := "ExitCode"
176
+	title := "HCSShim::Process::" + operation
177
+	logrus.Debugf(title+" processid=%d", process.processID)
178
+
179
+	properties, err := process.properties()
180
+	if err != nil {
181
+		err := &ProcessError{Operation: operation, Process: process, Err: err}
182
+		logrus.Error(err)
183
+		return 0, err
184
+	}
185
+
186
+	if properties.Exited == false {
187
+		return 0, ErrInvalidProcessState
188
+	}
189
+
190
+	logrus.Debugf(title+" succeeded processid=%d exitCode=%d", process.processID, properties.ExitCode)
191
+	return int(properties.ExitCode), nil
192
+}
193
+
194
+// ResizeConsole resizes the console of the process.
195
+func (process *process) ResizeConsole(width, height uint16) error {
196
+	operation := "ResizeConsole"
197
+	title := "HCSShim::Process::" + operation
198
+	logrus.Debugf(title+" processid=%d", process.processID)
199
+
200
+	modifyRequest := processModifyRequest{
201
+		Operation: modifyConsoleSize,
202
+		ConsoleSize: &consoleSize{
203
+			Height: height,
204
+			Width:  width,
205
+		},
206
+	}
207
+
208
+	modifyRequestb, err := json.Marshal(modifyRequest)
209
+	if err != nil {
210
+		return err
211
+	}
212
+
213
+	modifyRequestStr := string(modifyRequestb)
214
+
215
+	var resultp *uint16
216
+	err = hcsModifyProcess(process.handle, modifyRequestStr, &resultp)
217
+	err = processHcsResult(err, resultp)
218
+	if err != nil {
219
+		err := &ProcessError{Operation: operation, Process: process, Err: err}
220
+		logrus.Error(err)
221
+		return err
222
+	}
223
+
224
+	logrus.Debugf(title+" succeeded processid=%d", process.processID)
225
+	return nil
226
+}
227
+
228
+func (process *process) properties() (*processStatus, error) {
229
+	operation := "properties"
230
+	title := "HCSShim::Process::" + operation
231
+	logrus.Debugf(title+" processid=%d", process.processID)
232
+
233
+	var (
234
+		resultp     *uint16
235
+		propertiesp *uint16
236
+	)
237
+	err := hcsGetProcessProperties(process.handle, &propertiesp, &resultp)
238
+	err = processHcsResult(err, resultp)
239
+	if err != nil {
240
+		err := &ProcessError{Operation: operation, Process: process, Err: err}
241
+		logrus.Error(err)
242
+		return nil, err
243
+	}
244
+
245
+	if propertiesp == nil {
246
+		return nil, errors.New("Unexpected result from hcsGetProcessProperties, properties should never be nil")
247
+	}
248
+	propertiesRaw := convertAndFreeCoTaskMemBytes(propertiesp)
249
+
250
+	properties := &processStatus{}
251
+	if err := json.Unmarshal(propertiesRaw, properties); err != nil {
252
+		return nil, err
253
+	}
254
+
255
+	logrus.Debugf(title+" succeeded processid=%d, properties=%s", process.processID, propertiesRaw)
256
+	return properties, nil
257
+}
258
+
259
+// Stdio returns the stdin, stdout, and stderr pipes, respectively. Closing
260
+// these pipes does not close the underlying pipes; it should be possible to
261
+// call this multiple times to get multiple interfaces.
262
+func (process *process) Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, error) {
263
+	operation := "Stdio"
264
+	title := "HCSShim::Process::" + operation
265
+	logrus.Debugf(title+" processid=%d", process.processID)
266
+
267
+	var stdIn, stdOut, stdErr syscall.Handle
268
+
269
+	if process.cachedPipes == nil {
270
+		var (
271
+			processInfo hcsProcessInformation
272
+			resultp     *uint16
273
+		)
274
+		err := hcsGetProcessInfo(process.handle, &processInfo, &resultp)
275
+		err = processHcsResult(err, resultp)
276
+		if err != nil {
277
+			err = &ProcessError{Operation: operation, Process: process, Err: err}
278
+			logrus.Error(err)
279
+			return nil, nil, nil, err
280
+		}
281
+
282
+		stdIn, stdOut, stdErr = processInfo.StdInput, processInfo.StdOutput, processInfo.StdError
283
+	} else {
284
+		// Use cached pipes
285
+		stdIn, stdOut, stdErr = process.cachedPipes.stdIn, process.cachedPipes.stdOut, process.cachedPipes.stdErr
286
+
287
+		// Invalidate the cache
288
+		process.cachedPipes = nil
289
+	}
290
+
291
+	pipes, err := makeOpenFiles([]syscall.Handle{stdIn, stdOut, stdErr})
292
+	if err != nil {
293
+		return nil, nil, nil, err
294
+	}
295
+
296
+	logrus.Debugf(title+" succeeded processid=%d", process.processID)
297
+	return pipes[0], pipes[1], pipes[2], nil
298
+}
299
+
300
+// CloseStdin closes the write side of the stdin pipe so that the process is
301
+// notified on the read side that there is no more data in stdin.
302
+func (process *process) CloseStdin() error {
303
+	operation := "CloseStdin"
304
+	title := "HCSShim::Process::" + operation
305
+	logrus.Debugf(title+" processid=%d", process.processID)
306
+
307
+	modifyRequest := processModifyRequest{
308
+		Operation: modifyCloseHandle,
309
+		CloseHandle: &closeHandle{
310
+			Handle: stdIn,
311
+		},
312
+	}
313
+
314
+	modifyRequestb, err := json.Marshal(modifyRequest)
315
+	if err != nil {
316
+		return err
317
+	}
318
+
319
+	modifyRequestStr := string(modifyRequestb)
320
+
321
+	var resultp *uint16
322
+	err = hcsModifyProcess(process.handle, modifyRequestStr, &resultp)
323
+	err = processHcsResult(err, resultp)
324
+	if err != nil {
325
+		err = &ProcessError{Operation: operation, Process: process, Err: err}
326
+		logrus.Error(err)
327
+		return err
328
+	}
329
+
330
+	logrus.Debugf(title+" succeeded processid=%d", process.processID)
331
+	return nil
332
+}
333
+
334
+// Close cleans up any state associated with the process but does not kill
335
+// or wait on it.
336
+func (process *process) Close() error {
337
+	operation := "Close"
338
+	title := "HCSShim::Process::" + operation
339
+	logrus.Debugf(title+" processid=%d", process.processID)
340
+
341
+	// Don't double free this
342
+	if process.handle == 0 {
343
+		return nil
344
+	}
345
+
346
+	if err := hcsCloseProcess(process.handle); err != nil {
347
+		err = &ProcessError{Operation: operation, Process: process, Err: err}
348
+		logrus.Error(err)
349
+		return err
350
+	}
351
+
352
+	process.handle = 0
353
+
354
+	logrus.Debugf(title+" succeeded processid=%d", process.processID)
355
+	return nil
356
+}
357
+
358
+// closeProcess wraps process.Close for use by a finalizer
359
+func closeProcess(process *process) {
360
+	process.Close()
361
+}
362
+
363
+func (process *process) registerCallback(expectedNotification hcsNotification) (uintptr, error) {
364
+	callbackMapLock.Lock()
365
+	defer callbackMapLock.Unlock()
366
+
367
+	callbackNumber := nextCallback
368
+	nextCallback++
369
+
370
+	context := &notifcationWatcherContext{
371
+		expectedNotification: expectedNotification,
372
+		channel:              make(chan error, 1),
373
+	}
374
+	callbackMap[callbackNumber] = context
375
+
376
+	var callbackHandle hcsCallback
377
+	err := hcsRegisterProcessCallback(process.handle, notificationWatcherCallback, callbackNumber, &callbackHandle)
378
+	if err != nil {
379
+		return 0, err
380
+	}
381
+	context.handle = callbackHandle
382
+
383
+	return callbackNumber, nil
384
+}
385
+
386
+func (process *process) unregisterCallback(callbackNumber uintptr) error {
387
+	callbackMapLock.Lock()
388
+	defer callbackMapLock.Unlock()
389
+	handle := callbackMap[callbackNumber].handle
390
+
391
+	if handle == 0 {
392
+		return nil
393
+	}
394
+
395
+	err := hcsUnregisterProcessCallback(handle)
396
+	if err != nil {
397
+		return err
398
+	}
399
+
400
+	callbackMap[callbackNumber] = nil
401
+
402
+	handle = 0
403
+
404
+	return nil
405
+}
406
+
407
+func (e *ProcessError) Error() string {
408
+	if e == nil {
409
+		return "<nil>"
410
+	}
411
+
412
+	if e.Process == nil {
413
+		return "Unexpected nil process for error: " + e.Err.Error()
414
+	}
415
+
416
+	s := fmt.Sprintf("process %d", e.Process.processID)
417
+
418
+	if e.Process.container != nil {
419
+		s += " in container " + e.Process.container.id
420
+	}
421
+
422
+	if e.Operation != "" {
423
+		s += " " + e.Operation
424
+	}
425
+
426
+	if e.Err != nil {
427
+		s += fmt.Sprintf(" failed in Win32: %s (0x%x)", e.Err, win32FromError(e.Err))
428
+	}
429
+
430
+	return s
431
+}
0 432
new file mode 100644
... ...
@@ -0,0 +1,11 @@
0
+package hcsshim
1
+
2
+import (
3
+	"syscall"
4
+)
5
+
6
+var (
7
+	vmcomputedll          = syscall.NewLazyDLL("vmcompute.dll")
8
+	hcsCallbackAPI        = vmcomputedll.NewProc("HcsRegisterComputeSystemCallback")
9
+	hcsCallbacksSupported = hcsCallbackAPI.Find() == nil
10
+)
0 11
new file mode 100644
... ...
@@ -0,0 +1,113 @@
0
+package hcsshim
1
+
2
+import (
3
+	"syscall"
4
+	"time"
5
+)
6
+
7
+type waitable interface {
8
+	waitTimeoutInternal(timeout uint32) (bool, error)
9
+	hcsWait(timeout uint32) (bool, error)
10
+}
11
+
12
+type callbackable interface {
13
+	registerCallback(expectedNotification hcsNotification) (uintptr, error)
14
+	unregisterCallback(callbackNumber uintptr) error
15
+}
16
+
17
+func waitTimeoutHelper(object waitable, timeout time.Duration) (bool, error) {
18
+	var (
19
+		millis uint32
20
+	)
21
+
22
+	for totalMillis := uint64(timeout / time.Millisecond); totalMillis > 0; totalMillis = totalMillis - uint64(millis) {
23
+		if totalMillis >= syscall.INFINITE {
24
+			millis = syscall.INFINITE - 1
25
+		} else {
26
+			millis = uint32(totalMillis)
27
+		}
28
+
29
+		result, err := object.waitTimeoutInternal(millis)
30
+
31
+		if err != nil {
32
+			return result, err
33
+		}
34
+	}
35
+	return true, nil
36
+}
37
+
38
+func waitTimeoutInternalHelper(object waitable, timeout uint32) (bool, error) {
39
+	return object.hcsWait(timeout)
40
+}
41
+
42
+func waitForSingleObject(handle syscall.Handle, timeout uint32) (bool, error) {
43
+	s, e := syscall.WaitForSingleObject(handle, timeout)
44
+	switch s {
45
+	case syscall.WAIT_OBJECT_0:
46
+		return true, nil
47
+	case syscall.WAIT_TIMEOUT:
48
+		return false, nil
49
+	default:
50
+		return false, e
51
+	}
52
+}
53
+
54
+func processAsyncHcsResult(object callbackable, err error, resultp *uint16, expectedNotification hcsNotification, timeout *time.Duration) error {
55
+	err = processHcsResult(err, resultp)
56
+	if err == ErrVmcomputeOperationPending {
57
+		if timeout != nil {
58
+			err = registerAndWaitForCallbackTimeout(object, expectedNotification, *timeout)
59
+		} else {
60
+			err = registerAndWaitForCallback(object, expectedNotification)
61
+		}
62
+	}
63
+
64
+	return err
65
+}
66
+
67
+func registerAndWaitForCallbackTimeout(object callbackable, expectedNotification hcsNotification, timeout time.Duration) error {
68
+	callbackNumber, err := object.registerCallback(expectedNotification)
69
+	if err != nil {
70
+		return err
71
+	}
72
+	defer object.unregisterCallback(callbackNumber)
73
+
74
+	return waitForNotificationTimeout(callbackNumber, timeout)
75
+}
76
+
77
+func registerAndWaitForCallback(object callbackable, expectedNotification hcsNotification) error {
78
+	callbackNumber, err := object.registerCallback(expectedNotification)
79
+	if err != nil {
80
+		return err
81
+	}
82
+	defer object.unregisterCallback(callbackNumber)
83
+
84
+	return waitForNotification(callbackNumber)
85
+}
86
+
87
+func waitForNotificationTimeout(callbackNumber uintptr, timeout time.Duration) error {
88
+	callbackMapLock.RLock()
89
+	channel := callbackMap[callbackNumber].channel
90
+	callbackMapLock.RUnlock()
91
+
92
+	timer := time.NewTimer(timeout)
93
+	defer timer.Stop()
94
+
95
+	select {
96
+	case err := <-channel:
97
+		return err
98
+	case <-timer.C:
99
+		return ErrTimeout
100
+	}
101
+}
102
+
103
+func waitForNotification(callbackNumber uintptr) error {
104
+	callbackMapLock.RLock()
105
+	channel := callbackMap[callbackNumber].channel
106
+	callbackMapLock.RUnlock()
107
+
108
+	select {
109
+	case err := <-channel:
110
+		return err
111
+	}
112
+}
... ...
@@ -2,11 +2,8 @@
2 2
 
3 3
 package hcsshim
4 4
 
5
-import (
6
-	"unsafe"
7
-
8
-	"github.com/Microsoft/go-winio"
9
-)
5
+import "github.com/Microsoft/go-winio"
6
+import "unsafe"
10 7
 import "syscall"
11 8
 
12 9
 var _ unsafe.Pointer
... ...
@@ -49,7 +46,34 @@ var (
49 49
 	procTerminateProcessInComputeSystem            = modvmcompute.NewProc("TerminateProcessInComputeSystem")
50 50
 	procWaitForProcessInComputeSystem              = modvmcompute.NewProc("WaitForProcessInComputeSystem")
51 51
 	procGetComputeSystemProperties                 = modvmcompute.NewProc("GetComputeSystemProperties")
52
-	procHNSCall                                    = modvmcompute.NewProc("HNSCall")
52
+	procHcsEnumerateComputeSystems                 = modvmcompute.NewProc("HcsEnumerateComputeSystems")
53
+	procHcsCreateComputeSystem                     = modvmcompute.NewProc("HcsCreateComputeSystem")
54
+	procHcsOpenComputeSystem                       = modvmcompute.NewProc("HcsOpenComputeSystem")
55
+	procHcsCloseComputeSystem                      = modvmcompute.NewProc("HcsCloseComputeSystem")
56
+	procHcsStartComputeSystem                      = modvmcompute.NewProc("HcsStartComputeSystem")
57
+	procHcsShutdownComputeSystem                   = modvmcompute.NewProc("HcsShutdownComputeSystem")
58
+	procHcsTerminateComputeSystem                  = modvmcompute.NewProc("HcsTerminateComputeSystem")
59
+	procHcsPauseComputeSystem                      = modvmcompute.NewProc("HcsPauseComputeSystem")
60
+	procHcsResumeComputeSystem                     = modvmcompute.NewProc("HcsResumeComputeSystem")
61
+	procHcsGetComputeSystemProperties              = modvmcompute.NewProc("HcsGetComputeSystemProperties")
62
+	procHcsModifyComputeSystem                     = modvmcompute.NewProc("HcsModifyComputeSystem")
63
+	procHcsCreateComputeSystemWait                 = modvmcompute.NewProc("HcsCreateComputeSystemWait")
64
+	procHcsCreateProcess                           = modvmcompute.NewProc("HcsCreateProcess")
65
+	procHcsOpenProcess                             = modvmcompute.NewProc("HcsOpenProcess")
66
+	procHcsCloseProcess                            = modvmcompute.NewProc("HcsCloseProcess")
67
+	procHcsTerminateProcess                        = modvmcompute.NewProc("HcsTerminateProcess")
68
+	procHcsGetProcessInfo                          = modvmcompute.NewProc("HcsGetProcessInfo")
69
+	procHcsGetProcessProperties                    = modvmcompute.NewProc("HcsGetProcessProperties")
70
+	procHcsModifyProcess                           = modvmcompute.NewProc("HcsModifyProcess")
71
+	procHcsCreateProcessWait                       = modvmcompute.NewProc("HcsCreateProcessWait")
72
+	procHcsGetServiceProperties                    = modvmcompute.NewProc("HcsGetServiceProperties")
73
+	procHcsModifyServiceSettings                   = modvmcompute.NewProc("HcsModifyServiceSettings")
74
+
75
+	procHcsRegisterComputeSystemCallback   = modvmcompute.NewProc("HcsRegisterComputeSystemCallback")
76
+	procHcsUnregisterComputeSystemCallback = modvmcompute.NewProc("HcsUnregisterComputeSystemCallback")
77
+	procHcsRegisterProcessCallback         = modvmcompute.NewProc("HcsRegisterProcessCallback")
78
+	procHcsUnregisterProcessCallback       = modvmcompute.NewProc("HcsUnregisterProcessCallback")
79
+	procHNSCall                            = modvmcompute.NewProc("HNSCall")
53 80
 )
54 81
 
55 82
 func coTaskMemFree(buffer unsafe.Pointer) {
... ...
@@ -734,6 +758,503 @@ func _getComputeSystemProperties(id *uint16, flags uint32, properties **uint16)
734 734
 	return
735 735
 }
736 736
 
737
+func hcsEnumerateComputeSystems(query string, computeSystems **uint16, result **uint16) (hr error) {
738
+	var _p0 *uint16
739
+	_p0, hr = syscall.UTF16PtrFromString(query)
740
+	if hr != nil {
741
+		return
742
+	}
743
+	return _hcsEnumerateComputeSystems(_p0, computeSystems, result)
744
+}
745
+
746
+func _hcsEnumerateComputeSystems(query *uint16, computeSystems **uint16, result **uint16) (hr error) {
747
+	if hr = procHcsEnumerateComputeSystems.Find(); hr != nil {
748
+		return
749
+	}
750
+	r0, _, _ := syscall.Syscall(procHcsEnumerateComputeSystems.Addr(), 3, uintptr(unsafe.Pointer(query)), uintptr(unsafe.Pointer(computeSystems)), uintptr(unsafe.Pointer(result)))
751
+	if int32(r0) < 0 {
752
+		hr = syscall.Errno(win32FromHresult(r0))
753
+	}
754
+	return
755
+}
756
+
757
+func hcsCreateComputeSystem(id string, configuration string, identity syscall.Handle, computeSystem *hcsSystem, result **uint16) (hr error) {
758
+	var _p0 *uint16
759
+	_p0, hr = syscall.UTF16PtrFromString(id)
760
+	if hr != nil {
761
+		return
762
+	}
763
+	var _p1 *uint16
764
+	_p1, hr = syscall.UTF16PtrFromString(configuration)
765
+	if hr != nil {
766
+		return
767
+	}
768
+	return _hcsCreateComputeSystem(_p0, _p1, identity, computeSystem, result)
769
+}
770
+
771
+func _hcsCreateComputeSystem(id *uint16, configuration *uint16, identity syscall.Handle, computeSystem *hcsSystem, result **uint16) (hr error) {
772
+	if hr = procHcsCreateComputeSystem.Find(); hr != nil {
773
+		return
774
+	}
775
+	r0, _, _ := syscall.Syscall6(procHcsCreateComputeSystem.Addr(), 5, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(configuration)), uintptr(identity), uintptr(unsafe.Pointer(computeSystem)), uintptr(unsafe.Pointer(result)), 0)
776
+	if int32(r0) < 0 {
777
+		hr = syscall.Errno(win32FromHresult(r0))
778
+	}
779
+	return
780
+}
781
+
782
+func hcsOpenComputeSystem(id string, computeSystem *hcsSystem, result **uint16) (hr error) {
783
+	var _p0 *uint16
784
+	_p0, hr = syscall.UTF16PtrFromString(id)
785
+	if hr != nil {
786
+		return
787
+	}
788
+	return _hcsOpenComputeSystem(_p0, computeSystem, result)
789
+}
790
+
791
+func _hcsOpenComputeSystem(id *uint16, computeSystem *hcsSystem, result **uint16) (hr error) {
792
+	if hr = procHcsOpenComputeSystem.Find(); hr != nil {
793
+		return
794
+	}
795
+	r0, _, _ := syscall.Syscall(procHcsOpenComputeSystem.Addr(), 3, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(computeSystem)), uintptr(unsafe.Pointer(result)))
796
+	if int32(r0) < 0 {
797
+		hr = syscall.Errno(win32FromHresult(r0))
798
+	}
799
+	return
800
+}
801
+
802
+func hcsCloseComputeSystem(computeSystem hcsSystem) (hr error) {
803
+	if hr = procHcsCloseComputeSystem.Find(); hr != nil {
804
+		return
805
+	}
806
+	r0, _, _ := syscall.Syscall(procHcsCloseComputeSystem.Addr(), 1, uintptr(computeSystem), 0, 0)
807
+	if int32(r0) < 0 {
808
+		hr = syscall.Errno(win32FromHresult(r0))
809
+	}
810
+	return
811
+}
812
+
813
+func hcsStartComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) {
814
+	var _p0 *uint16
815
+	_p0, hr = syscall.UTF16PtrFromString(options)
816
+	if hr != nil {
817
+		return
818
+	}
819
+	return _hcsStartComputeSystem(computeSystem, _p0, result)
820
+}
821
+
822
+func _hcsStartComputeSystem(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) {
823
+	if hr = procHcsStartComputeSystem.Find(); hr != nil {
824
+		return
825
+	}
826
+	r0, _, _ := syscall.Syscall(procHcsStartComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
827
+	if int32(r0) < 0 {
828
+		hr = syscall.Errno(win32FromHresult(r0))
829
+	}
830
+	return
831
+}
832
+
833
+func hcsShutdownComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) {
834
+	var _p0 *uint16
835
+	_p0, hr = syscall.UTF16PtrFromString(options)
836
+	if hr != nil {
837
+		return
838
+	}
839
+	return _hcsShutdownComputeSystem(computeSystem, _p0, result)
840
+}
841
+
842
+func _hcsShutdownComputeSystem(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) {
843
+	if hr = procHcsShutdownComputeSystem.Find(); hr != nil {
844
+		return
845
+	}
846
+	r0, _, _ := syscall.Syscall(procHcsShutdownComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
847
+	if int32(r0) < 0 {
848
+		hr = syscall.Errno(win32FromHresult(r0))
849
+	}
850
+	return
851
+}
852
+
853
+func hcsTerminateComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) {
854
+	var _p0 *uint16
855
+	_p0, hr = syscall.UTF16PtrFromString(options)
856
+	if hr != nil {
857
+		return
858
+	}
859
+	return _hcsTerminateComputeSystem(computeSystem, _p0, result)
860
+}
861
+
862
+func _hcsTerminateComputeSystem(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) {
863
+	if hr = procHcsTerminateComputeSystem.Find(); hr != nil {
864
+		return
865
+	}
866
+	r0, _, _ := syscall.Syscall(procHcsTerminateComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
867
+	if int32(r0) < 0 {
868
+		hr = syscall.Errno(win32FromHresult(r0))
869
+	}
870
+	return
871
+}
872
+
873
+func hcsPauseComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) {
874
+	var _p0 *uint16
875
+	_p0, hr = syscall.UTF16PtrFromString(options)
876
+	if hr != nil {
877
+		return
878
+	}
879
+	return _hcsPauseComputeSystem(computeSystem, _p0, result)
880
+}
881
+
882
+func _hcsPauseComputeSystem(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) {
883
+	if hr = procHcsPauseComputeSystem.Find(); hr != nil {
884
+		return
885
+	}
886
+	r0, _, _ := syscall.Syscall(procHcsPauseComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
887
+	if int32(r0) < 0 {
888
+		hr = syscall.Errno(win32FromHresult(r0))
889
+	}
890
+	return
891
+}
892
+
893
+func hcsResumeComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) {
894
+	var _p0 *uint16
895
+	_p0, hr = syscall.UTF16PtrFromString(options)
896
+	if hr != nil {
897
+		return
898
+	}
899
+	return _hcsResumeComputeSystem(computeSystem, _p0, result)
900
+}
901
+
902
+func _hcsResumeComputeSystem(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) {
903
+	if hr = procHcsResumeComputeSystem.Find(); hr != nil {
904
+		return
905
+	}
906
+	r0, _, _ := syscall.Syscall(procHcsResumeComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
907
+	if int32(r0) < 0 {
908
+		hr = syscall.Errno(win32FromHresult(r0))
909
+	}
910
+	return
911
+}
912
+
913
+func hcsGetComputeSystemProperties(computeSystem hcsSystem, propertyQuery string, properties **uint16, result **uint16) (hr error) {
914
+	var _p0 *uint16
915
+	_p0, hr = syscall.UTF16PtrFromString(propertyQuery)
916
+	if hr != nil {
917
+		return
918
+	}
919
+	return _hcsGetComputeSystemProperties(computeSystem, _p0, properties, result)
920
+}
921
+
922
+func _hcsGetComputeSystemProperties(computeSystem hcsSystem, propertyQuery *uint16, properties **uint16, result **uint16) (hr error) {
923
+	if hr = procHcsGetComputeSystemProperties.Find(); hr != nil {
924
+		return
925
+	}
926
+	r0, _, _ := syscall.Syscall6(procHcsGetComputeSystemProperties.Addr(), 4, uintptr(computeSystem), uintptr(unsafe.Pointer(propertyQuery)), uintptr(unsafe.Pointer(properties)), uintptr(unsafe.Pointer(result)), 0, 0)
927
+	if int32(r0) < 0 {
928
+		hr = syscall.Errno(win32FromHresult(r0))
929
+	}
930
+	return
931
+}
932
+
933
+func hcsModifyComputeSystem(computeSystem hcsSystem, configuration string, result **uint16) (hr error) {
934
+	var _p0 *uint16
935
+	_p0, hr = syscall.UTF16PtrFromString(configuration)
936
+	if hr != nil {
937
+		return
938
+	}
939
+	return _hcsModifyComputeSystem(computeSystem, _p0, result)
940
+}
941
+
942
+func _hcsModifyComputeSystem(computeSystem hcsSystem, configuration *uint16, result **uint16) (hr error) {
943
+	if hr = procHcsModifyComputeSystem.Find(); hr != nil {
944
+		return
945
+	}
946
+	r0, _, _ := syscall.Syscall(procHcsModifyComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(configuration)), uintptr(unsafe.Pointer(result)))
947
+	if int32(r0) < 0 {
948
+		hr = syscall.Errno(win32FromHresult(r0))
949
+	}
950
+	return
951
+}
952
+
953
+func hcsCreateComputeSystemWait(computeSystem hcsSystem, exitEvent *syscall.Handle, result **uint16) (hr error) {
954
+	if hr = procHcsCreateComputeSystemWait.Find(); hr != nil {
955
+		return
956
+	}
957
+	r0, _, _ := syscall.Syscall(procHcsCreateComputeSystemWait.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(exitEvent)), uintptr(unsafe.Pointer(result)))
958
+	if int32(r0) < 0 {
959
+		hr = syscall.Errno(win32FromHresult(r0))
960
+	}
961
+	return
962
+}
963
+
964
+func hcsCreateProcess(computeSystem hcsSystem, processParameters string, processInformation *hcsProcessInformation, process *hcsProcess, result **uint16) (hr error) {
965
+	var _p0 *uint16
966
+	_p0, hr = syscall.UTF16PtrFromString(processParameters)
967
+	if hr != nil {
968
+		return
969
+	}
970
+	return _hcsCreateProcess(computeSystem, _p0, processInformation, process, result)
971
+}
972
+
973
+func _hcsCreateProcess(computeSystem hcsSystem, processParameters *uint16, processInformation *hcsProcessInformation, process *hcsProcess, result **uint16) (hr error) {
974
+	if hr = procHcsCreateProcess.Find(); hr != nil {
975
+		return
976
+	}
977
+	r0, _, _ := syscall.Syscall6(procHcsCreateProcess.Addr(), 5, uintptr(computeSystem), uintptr(unsafe.Pointer(processParameters)), uintptr(unsafe.Pointer(processInformation)), uintptr(unsafe.Pointer(process)), uintptr(unsafe.Pointer(result)), 0)
978
+	if int32(r0) < 0 {
979
+		hr = syscall.Errno(win32FromHresult(r0))
980
+	}
981
+	return
982
+}
983
+
984
+func hcsOpenProcess(computeSystem hcsSystem, pid uint32, process *hcsProcess, result **uint16) (hr error) {
985
+	if hr = procHcsOpenProcess.Find(); hr != nil {
986
+		return
987
+	}
988
+	r0, _, _ := syscall.Syscall6(procHcsOpenProcess.Addr(), 4, uintptr(computeSystem), uintptr(pid), uintptr(unsafe.Pointer(process)), uintptr(unsafe.Pointer(result)), 0, 0)
989
+	if int32(r0) < 0 {
990
+		hr = syscall.Errno(win32FromHresult(r0))
991
+	}
992
+	return
993
+}
994
+
995
+func hcsCloseProcess(process hcsProcess) (hr error) {
996
+	if hr = procHcsCloseProcess.Find(); hr != nil {
997
+		return
998
+	}
999
+	r0, _, _ := syscall.Syscall(procHcsCloseProcess.Addr(), 1, uintptr(process), 0, 0)
1000
+	if int32(r0) < 0 {
1001
+		hr = syscall.Errno(win32FromHresult(r0))
1002
+	}
1003
+	return
1004
+}
1005
+
1006
+func hcsTerminateProcess(process hcsProcess, result **uint16) (hr error) {
1007
+	if hr = procHcsTerminateProcess.Find(); hr != nil {
1008
+		return
1009
+	}
1010
+	r0, _, _ := syscall.Syscall(procHcsTerminateProcess.Addr(), 2, uintptr(process), uintptr(unsafe.Pointer(result)), 0)
1011
+	if int32(r0) < 0 {
1012
+		hr = syscall.Errno(win32FromHresult(r0))
1013
+	}
1014
+	return
1015
+}
1016
+
1017
+func hcsGetProcessInfo(process hcsProcess, processInformation *hcsProcessInformation, result **uint16) (hr error) {
1018
+	if hr = procHcsGetProcessInfo.Find(); hr != nil {
1019
+		return
1020
+	}
1021
+	r0, _, _ := syscall.Syscall(procHcsGetProcessInfo.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(processInformation)), uintptr(unsafe.Pointer(result)))
1022
+	if int32(r0) < 0 {
1023
+		hr = syscall.Errno(win32FromHresult(r0))
1024
+	}
1025
+	return
1026
+}
1027
+
1028
+func hcsGetProcessProperties(process hcsProcess, processProperties **uint16, result **uint16) (hr error) {
1029
+	if hr = procHcsGetProcessProperties.Find(); hr != nil {
1030
+		return
1031
+	}
1032
+	r0, _, _ := syscall.Syscall(procHcsGetProcessProperties.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(processProperties)), uintptr(unsafe.Pointer(result)))
1033
+	if int32(r0) < 0 {
1034
+		hr = syscall.Errno(win32FromHresult(r0))
1035
+	}
1036
+	return
1037
+}
1038
+
1039
+func hcsModifyProcess(process hcsProcess, settings string, result **uint16) (hr error) {
1040
+	var _p0 *uint16
1041
+	_p0, hr = syscall.UTF16PtrFromString(settings)
1042
+	if hr != nil {
1043
+		return
1044
+	}
1045
+	return _hcsModifyProcess(process, _p0, result)
1046
+}
1047
+
1048
+func _hcsModifyProcess(process hcsProcess, settings *uint16, result **uint16) (hr error) {
1049
+	if hr = procHcsModifyProcess.Find(); hr != nil {
1050
+		return
1051
+	}
1052
+	r0, _, _ := syscall.Syscall(procHcsModifyProcess.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(result)))
1053
+	if int32(r0) < 0 {
1054
+		hr = syscall.Errno(win32FromHresult(r0))
1055
+	}
1056
+	return
1057
+}
1058
+
1059
+func hcsCreateProcessWait(process hcsProcess, settings *syscall.Handle, result **uint16) (hr error) {
1060
+	if hr = procHcsCreateProcessWait.Find(); hr != nil {
1061
+		return
1062
+	}
1063
+	r0, _, _ := syscall.Syscall(procHcsCreateProcessWait.Addr(), 3, uintptr(process), uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(result)))
1064
+	if int32(r0) < 0 {
1065
+		hr = syscall.Errno(win32FromHresult(r0))
1066
+	}
1067
+	return
1068
+}
1069
+
1070
+func hcsGetServiceProperties(propertyQuery string, properties **uint16, result **uint16) (hr error) {
1071
+	var _p0 *uint16
1072
+	_p0, hr = syscall.UTF16PtrFromString(propertyQuery)
1073
+	if hr != nil {
1074
+		return
1075
+	}
1076
+	return _hcsGetServiceProperties(_p0, properties, result)
1077
+}
1078
+
1079
+func _hcsGetServiceProperties(propertyQuery *uint16, properties **uint16, result **uint16) (hr error) {
1080
+	if hr = procHcsGetServiceProperties.Find(); hr != nil {
1081
+		return
1082
+	}
1083
+	r0, _, _ := syscall.Syscall(procHcsGetServiceProperties.Addr(), 3, uintptr(unsafe.Pointer(propertyQuery)), uintptr(unsafe.Pointer(properties)), uintptr(unsafe.Pointer(result)))
1084
+	if int32(r0) < 0 {
1085
+		hr = syscall.Errno(win32FromHresult(r0))
1086
+	}
1087
+	return
1088
+}
1089
+
1090
+func hcsModifyServiceSettings(settings string, result **uint16) (hr error) {
1091
+	var _p0 *uint16
1092
+	_p0, hr = syscall.UTF16PtrFromString(settings)
1093
+	if hr != nil {
1094
+		return
1095
+	}
1096
+	return _hcsModifyServiceSettings(_p0, result)
1097
+}
1098
+
1099
+func _hcsModifyServiceSettings(settings *uint16, result **uint16) (hr error) {
1100
+	if hr = procHcsModifyServiceSettings.Find(); hr != nil {
1101
+		return
1102
+	}
1103
+	r0, _, _ := syscall.Syscall(procHcsModifyServiceSettings.Addr(), 2, uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(result)), 0)
1104
+	if int32(r0) < 0 {
1105
+		hr = syscall.Errno(win32FromHresult(r0))
1106
+	}
1107
+	return
1108
+}
1109
+
1110
+func hcsCreateComputeSystemTP5(id string, configuration string, computeSystem *hcsSystem, result **uint16) (hr error) {
1111
+	var _p0 *uint16
1112
+	_p0, hr = syscall.UTF16PtrFromString(id)
1113
+	if hr != nil {
1114
+		return
1115
+	}
1116
+	var _p1 *uint16
1117
+	_p1, hr = syscall.UTF16PtrFromString(configuration)
1118
+	if hr != nil {
1119
+		return
1120
+	}
1121
+	return _hcsCreateComputeSystemTP5(_p0, _p1, computeSystem, result)
1122
+}
1123
+
1124
+func _hcsCreateComputeSystemTP5(id *uint16, configuration *uint16, computeSystem *hcsSystem, result **uint16) (hr error) {
1125
+	if hr = procHcsCreateComputeSystem.Find(); hr != nil {
1126
+		return
1127
+	}
1128
+	r0, _, _ := syscall.Syscall6(procHcsCreateComputeSystem.Addr(), 4, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(configuration)), uintptr(unsafe.Pointer(computeSystem)), uintptr(unsafe.Pointer(result)), 0, 0)
1129
+	if int32(r0) < 0 {
1130
+		hr = syscall.Errno(win32FromHresult(r0))
1131
+	}
1132
+	return
1133
+}
1134
+
1135
+func hcsStartComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) {
1136
+	if hr = procHcsStartComputeSystem.Find(); hr != nil {
1137
+		return
1138
+	}
1139
+	r0, _, _ := syscall.Syscall(procHcsStartComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
1140
+	if int32(r0) < 0 {
1141
+		hr = syscall.Errno(win32FromHresult(r0))
1142
+	}
1143
+	return
1144
+}
1145
+
1146
+func hcsShutdownComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) {
1147
+	if hr = procHcsShutdownComputeSystem.Find(); hr != nil {
1148
+		return
1149
+	}
1150
+	r0, _, _ := syscall.Syscall(procHcsShutdownComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
1151
+	if int32(r0) < 0 {
1152
+		hr = syscall.Errno(win32FromHresult(r0))
1153
+	}
1154
+	return
1155
+}
1156
+
1157
+func hcsTerminateComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) {
1158
+	if hr = procHcsTerminateComputeSystem.Find(); hr != nil {
1159
+		return
1160
+	}
1161
+	r0, _, _ := syscall.Syscall(procHcsTerminateComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
1162
+	if int32(r0) < 0 {
1163
+		hr = syscall.Errno(win32FromHresult(r0))
1164
+	}
1165
+	return
1166
+}
1167
+
1168
+func hcsPauseComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) {
1169
+	if hr = procHcsPauseComputeSystem.Find(); hr != nil {
1170
+		return
1171
+	}
1172
+	r0, _, _ := syscall.Syscall(procHcsPauseComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
1173
+	if int32(r0) < 0 {
1174
+		hr = syscall.Errno(win32FromHresult(r0))
1175
+	}
1176
+	return
1177
+}
1178
+
1179
+func hcsResumeComputeSystemTP5(computeSystem hcsSystem, options *uint16, result **uint16) (hr error) {
1180
+	if hr = procHcsResumeComputeSystem.Find(); hr != nil {
1181
+		return
1182
+	}
1183
+	r0, _, _ := syscall.Syscall(procHcsResumeComputeSystem.Addr(), 3, uintptr(computeSystem), uintptr(unsafe.Pointer(options)), uintptr(unsafe.Pointer(result)))
1184
+	if int32(r0) < 0 {
1185
+		hr = syscall.Errno(win32FromHresult(r0))
1186
+	}
1187
+	return
1188
+}
1189
+
1190
+func hcsRegisterComputeSystemCallback(computeSystem hcsSystem, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) {
1191
+	if hr = procHcsRegisterComputeSystemCallback.Find(); hr != nil {
1192
+		return
1193
+	}
1194
+	r0, _, _ := syscall.Syscall6(procHcsRegisterComputeSystemCallback.Addr(), 4, uintptr(computeSystem), uintptr(callback), uintptr(context), uintptr(unsafe.Pointer(callbackHandle)), 0, 0)
1195
+	if int32(r0) < 0 {
1196
+		hr = syscall.Errno(win32FromHresult(r0))
1197
+	}
1198
+	return
1199
+}
1200
+
1201
+func hcsUnregisterComputeSystemCallback(callbackHandle hcsCallback) (hr error) {
1202
+	if hr = procHcsUnregisterComputeSystemCallback.Find(); hr != nil {
1203
+		return
1204
+	}
1205
+	r0, _, _ := syscall.Syscall(procHcsUnregisterComputeSystemCallback.Addr(), 1, uintptr(callbackHandle), 0, 0)
1206
+	if int32(r0) < 0 {
1207
+		hr = syscall.Errno(win32FromHresult(r0))
1208
+	}
1209
+	return
1210
+}
1211
+
1212
+func hcsRegisterProcessCallback(process hcsProcess, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) {
1213
+	if hr = procHcsRegisterProcessCallback.Find(); hr != nil {
1214
+		return
1215
+	}
1216
+	r0, _, _ := syscall.Syscall6(procHcsRegisterProcessCallback.Addr(), 4, uintptr(process), uintptr(callback), uintptr(context), uintptr(unsafe.Pointer(callbackHandle)), 0, 0)
1217
+	if int32(r0) < 0 {
1218
+		hr = syscall.Errno(win32FromHresult(r0))
1219
+	}
1220
+	return
1221
+}
1222
+
1223
+func hcsUnregisterProcessCallback(callbackHandle hcsCallback) (hr error) {
1224
+	if hr = procHcsUnregisterProcessCallback.Find(); hr != nil {
1225
+		return
1226
+	}
1227
+	r0, _, _ := syscall.Syscall(procHcsUnregisterProcessCallback.Addr(), 1, uintptr(callbackHandle), 0, 0)
1228
+	if int32(r0) < 0 {
1229
+		hr = syscall.Errno(win32FromHresult(r0))
1230
+	}
1231
+	return
1232
+}
1233
+
737 1234
 func _hnsCall(method string, path string, object string, response **uint16) (hr error) {
738 1235
 	var _p0 *uint16
739 1236
 	_p0, hr = syscall.UTF16PtrFromString(method)