Signed-off-by: Darren Stahl <darst@microsoft.com>
| ... | ... |
@@ -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 := ¬ifcationWatcherContext{
|
|
| 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 := ¬ifcationWatcherContext{
|
|
| 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) |