Browse code

Update vendored hcsshim to v0.3.4

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

Darren Stahl authored on 2016/06/11 07:27:05
Showing 6 changed files
... ...
@@ -43,7 +43,7 @@ esac
43 43
 
44 44
 # the following lines are in sorted order, FYI
45 45
 clone git github.com/Azure/go-ansiterm 388960b655244e76e24c75f48631564eaefade62
46
-clone git github.com/Microsoft/hcsshim v0.3.2
46
+clone git github.com/Microsoft/hcsshim v0.3.4
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 hcsshim
2 2
 
3 3
 import (
4
-	"errors"
5 4
 	"sync"
6 5
 	"syscall"
7 6
 )
... ...
@@ -26,14 +25,6 @@ var (
26 26
 	// Common notifications
27 27
 	hcsNotificationInvalid           hcsNotification = 0x00000000
28 28
 	hcsNotificationServiceDisconnect hcsNotification = 0x01000000
29
-
30
-	// ErrUnexpectedContainerExit is the error returned when a container exits while waiting for
31
-	// a different expected notification
32
-	ErrUnexpectedContainerExit = errors.New("unexpected container exit")
33
-
34
-	// ErrUnexpectedProcessAbort is the error returned when communication with the compute service
35
-	// is lost while waiting for a notification
36
-	ErrUnexpectedProcessAbort = errors.New("lost communication with compute service")
37 29
 )
38 30
 
39 31
 type hcsNotification uint32
... ...
@@ -58,6 +49,15 @@ func newChannels() notificationChannels {
58 58
 	channels[hcsNotificationServiceDisconnect] = make(notificationChannel, 1)
59 59
 	return channels
60 60
 }
61
+func closeChannels(channels notificationChannels) {
62
+	close(channels[hcsNotificationSystemExited])
63
+	close(channels[hcsNotificationSystemCreateCompleted])
64
+	close(channels[hcsNotificationSystemStartCompleted])
65
+	close(channels[hcsNotificationSystemPauseCompleted])
66
+	close(channels[hcsNotificationSystemResumeCompleted])
67
+	close(channels[hcsNotificationProcessExited])
68
+	close(channels[hcsNotificationServiceDisconnect])
69
+}
61 70
 
62 71
 func notificationWatcher(notificationType hcsNotification, callbackNumber uintptr, notificationStatus uintptr, notificationData *uint16) uintptr {
63 72
 	var result error
... ...
@@ -66,10 +66,14 @@ func notificationWatcher(notificationType hcsNotification, callbackNumber uintpt
66 66
 	}
67 67
 
68 68
 	callbackMapLock.RLock()
69
-	channels := callbackMap[callbackNumber].channels
69
+	context := callbackMap[callbackNumber]
70 70
 	callbackMapLock.RUnlock()
71 71
 
72
-	channels[notificationType] <- result
72
+	if context == nil {
73
+		return 0
74
+	}
75
+
76
+	context.channels[notificationType] <- result
73 77
 
74 78
 	return 0
75 79
 }
... ...
@@ -13,11 +13,11 @@ import (
13 13
 
14 14
 var (
15 15
 	defaultTimeout = time.Minute * 4
16
-
17
-	// ErrTimeout is an error encountered when waiting on a notification times out
18
-	ErrTimeout = errors.New("hcsshim: timeout waiting for notification")
19 16
 )
20 17
 
18
+const pendingUpdatesQuery = `{ "PropertyTypes" : ["PendingUpdates"]}`
19
+
20
+// ContainerError is an error encountered in HCS
21 21
 type ContainerError struct {
22 22
 	Container *container
23 23
 	Operation string
... ...
@@ -71,9 +71,7 @@ func CreateContainer(id string, c *ContainerConfig) (Container, error) {
71 71
 
72 72
 		if createError == nil || createError == ErrVmcomputeOperationPending {
73 73
 			if err := container.registerCallback(); err != nil {
74
-				err := &ContainerError{Container: container, Operation: operation, Err: err}
75
-				logrus.Error(err)
76
-				return nil, err
74
+				return nil, makeContainerError(container, operation, "", err)
77 75
 			}
78 76
 		}
79 77
 	} else {
... ...
@@ -82,12 +80,7 @@ func CreateContainer(id string, c *ContainerConfig) (Container, error) {
82 82
 
83 83
 	err = processAsyncHcsResult(createError, resultp, container.callbackNumber, hcsNotificationSystemCreateCompleted, &defaultTimeout)
84 84
 	if err != nil {
85
-		if err == ErrTimeout || err == ErrUnexpectedProcessAbort || err == ErrUnexpectedContainerExit {
86
-			return nil, err
87
-		}
88
-		err := &ContainerError{Container: container, Operation: operation, ExtraInfo: configuration, Err: err}
89
-		logrus.Error(err)
90
-		return nil, err
85
+		return nil, makeContainerError(container, operation, configuration, err)
91 86
 	}
92 87
 
93 88
 	logrus.Debugf(title+" succeeded id=%s handle=%d", id, container.handle)
... ...
@@ -112,9 +105,7 @@ func OpenContainer(id string) (Container, error) {
112 112
 	err := hcsOpenComputeSystem(id, &handle, &resultp)
113 113
 	err = processHcsResult(err, resultp)
114 114
 	if err != nil {
115
-		err = &ContainerError{Container: container, Operation: operation, Err: err}
116
-		logrus.Error(err)
117
-		return nil, err
115
+		return nil, makeContainerError(container, operation, "", err)
118 116
 	}
119 117
 
120 118
 	container.handle = handle
... ...
@@ -134,12 +125,7 @@ func (container *container) Start() error {
134 134
 	err := hcsStartComputeSystemTP5(container.handle, nil, &resultp)
135 135
 	err = processAsyncHcsResult(err, resultp, container.callbackNumber, hcsNotificationSystemStartCompleted, &defaultTimeout)
136 136
 	if err != nil {
137
-		if err == ErrTimeout || err == ErrUnexpectedProcessAbort || err == ErrUnexpectedContainerExit {
138
-			return err
139
-		}
140
-		err := &ContainerError{Container: container, Operation: operation, Err: err}
141
-		logrus.Error(err)
142
-		return err
137
+		return makeContainerError(container, operation, "", err)
143 138
 	}
144 139
 
145 140
 	logrus.Debugf(title+" succeeded id=%s", container.id)
... ...
@@ -160,9 +146,7 @@ func (container *container) Shutdown() error {
160 160
 		if err == ErrVmcomputeOperationPending {
161 161
 			return ErrVmcomputeOperationPending
162 162
 		}
163
-		err = &ContainerError{Container: container, Operation: operation, Err: err}
164
-		logrus.Error(err)
165
-		return err
163
+		return makeContainerError(container, operation, "", err)
166 164
 	}
167 165
 
168 166
 	logrus.Debugf(title+" succeeded id=%s", container.id)
... ...
@@ -183,9 +167,7 @@ func (container *container) Terminate() error {
183 183
 		if err == ErrVmcomputeOperationPending {
184 184
 			return ErrVmcomputeOperationPending
185 185
 		}
186
-		err = &ContainerError{Container: container, Operation: operation, Err: err}
187
-		logrus.Error(err)
188
-		return err
186
+		return makeContainerError(container, operation, "", err)
189 187
 	}
190 188
 
191 189
 	logrus.Debugf(title+" succeeded id=%s", container.id)
... ...
@@ -201,19 +183,12 @@ func (container *container) Wait() error {
201 201
 	if hcsCallbacksSupported {
202 202
 		err := waitForNotification(container.callbackNumber, hcsNotificationSystemExited, nil)
203 203
 		if err != nil {
204
-			if err == ErrUnexpectedProcessAbort || err == ErrUnexpectedContainerExit {
205
-				return err
206
-			}
207
-			err := &ContainerError{Container: container, Operation: operation, Err: err}
208
-			logrus.Error(err)
209
-			return err
204
+			return makeContainerError(container, operation, "", err)
210 205
 		}
211 206
 	} else {
212 207
 		_, err := container.waitTimeoutInternal(syscall.INFINITE)
213 208
 		if err != nil {
214
-			err := &ContainerError{Container: container, Operation: operation, Err: err}
215
-			logrus.Error(err)
216
-			return err
209
+			return makeContainerError(container, operation, "", err)
217 210
 		}
218 211
 	}
219 212
 
... ...
@@ -235,21 +210,14 @@ func (container *container) WaitTimeout(timeout time.Duration) error {
235 235
 	if hcsCallbacksSupported {
236 236
 		err := waitForNotification(container.callbackNumber, hcsNotificationSystemExited, &timeout)
237 237
 		if err != nil {
238
-			if err == ErrTimeout || err == ErrUnexpectedProcessAbort || err == ErrUnexpectedContainerExit {
239
-				return err
240
-			}
241
-			err := &ContainerError{Container: container, Operation: operation, Err: err}
242
-			logrus.Error(err)
243
-			return err
238
+			return makeContainerError(container, operation, "", err)
244 239
 		}
245 240
 	} else {
246 241
 		finished, err := waitTimeoutHelper(container, timeout)
247 242
 		if !finished {
248 243
 			return ErrTimeout
249 244
 		} else if err != nil {
250
-			err := &ContainerError{Container: container, Operation: operation, Err: err}
251
-			logrus.Error(err)
252
-			return err
245
+			return makeContainerError(container, operation, "", err)
253 246
 		}
254 247
 	}
255 248
 
... ...
@@ -273,12 +241,12 @@ func (container *container) hcsWait(timeout uint32) (bool, error) {
273 273
 	return waitForSingleObject(exitEvent, timeout)
274 274
 }
275 275
 
276
-func (container *container) properties() (*containerProperties, error) {
276
+func (container *container) properties(query string) (*containerProperties, error) {
277 277
 	var (
278 278
 		resultp     *uint16
279 279
 		propertiesp *uint16
280 280
 	)
281
-	err := hcsGetComputeSystemProperties(container.handle, "", &propertiesp, &resultp)
281
+	err := hcsGetComputeSystemProperties(container.handle, query, &propertiesp, &resultp)
282 282
 	err = processHcsResult(err, resultp)
283 283
 	if err != nil {
284 284
 		return nil, err
... ...
@@ -302,11 +270,9 @@ func (container *container) HasPendingUpdates() (bool, error) {
302 302
 	operation := "HasPendingUpdates"
303 303
 	title := "HCSShim::Container::" + operation
304 304
 	logrus.Debugf(title+" id=%s", container.id)
305
-	properties, err := container.properties()
305
+	properties, err := container.properties(pendingUpdatesQuery)
306 306
 	if err != nil {
307
-		err := &ContainerError{Container: container, Operation: operation, Err: err}
308
-		logrus.Error(err)
309
-		return false, err
307
+		return false, makeContainerError(container, operation, "", err)
310 308
 	}
311 309
 
312 310
 	logrus.Debugf(title+" succeeded id=%s", container.id)
... ...
@@ -323,12 +289,7 @@ func (container *container) Pause() error {
323 323
 	err := hcsPauseComputeSystemTP5(container.handle, nil, &resultp)
324 324
 	err = processAsyncHcsResult(err, resultp, container.callbackNumber, hcsNotificationSystemPauseCompleted, &defaultTimeout)
325 325
 	if err != nil {
326
-		if err == ErrTimeout || err == ErrUnexpectedProcessAbort || err == ErrUnexpectedContainerExit {
327
-			return err
328
-		}
329
-		err := &ContainerError{Container: container, Operation: operation, Err: err}
330
-		logrus.Error(err)
331
-		return err
326
+		return makeContainerError(container, operation, "", err)
332 327
 	}
333 328
 
334 329
 	logrus.Debugf(title+" succeeded id=%s", container.id)
... ...
@@ -347,12 +308,7 @@ func (container *container) Resume() error {
347 347
 	err := hcsResumeComputeSystemTP5(container.handle, nil, &resultp)
348 348
 	err = processAsyncHcsResult(err, resultp, container.callbackNumber, hcsNotificationSystemResumeCompleted, &defaultTimeout)
349 349
 	if err != nil {
350
-		if err == ErrTimeout || err == ErrUnexpectedProcessAbort || err == ErrUnexpectedContainerExit {
351
-			return err
352
-		}
353
-		err := &ContainerError{Container: container, Operation: operation, Err: err}
354
-		logrus.Error(err)
355
-		return err
350
+		return makeContainerError(container, operation, "", err)
356 351
 	}
357 352
 
358 353
 	logrus.Debugf(title+" succeeded id=%s", container.id)
... ...
@@ -386,9 +342,7 @@ func (container *container) CreateProcess(c *ProcessConfig) (Process, error) {
386 386
 	err = hcsCreateProcess(container.handle, configuration, &processInfo, &processHandle, &resultp)
387 387
 	err = processHcsResult(err, resultp)
388 388
 	if err != nil {
389
-		err = &ContainerError{Container: container, Operation: operation, ExtraInfo: configuration, Err: err}
390
-		logrus.Error(err)
391
-		return nil, err
389
+		return nil, makeContainerError(container, operation, configuration, err)
392 390
 	}
393 391
 
394 392
 	process := &process{
... ...
@@ -404,9 +358,7 @@ func (container *container) CreateProcess(c *ProcessConfig) (Process, error) {
404 404
 
405 405
 	if hcsCallbacksSupported {
406 406
 		if err := process.registerCallback(); err != nil {
407
-			err = &ContainerError{Container: container, Operation: operation, Err: err}
408
-			logrus.Error(err)
409
-			return nil, err
407
+			return nil, makeContainerError(container, operation, "", err)
410 408
 		}
411 409
 	}
412 410
 
... ...
@@ -428,9 +380,7 @@ func (container *container) OpenProcess(pid int) (Process, error) {
428 428
 	err := hcsOpenProcess(container.handle, uint32(pid), &processHandle, &resultp)
429 429
 	err = processHcsResult(err, resultp)
430 430
 	if err != nil {
431
-		err = &ContainerError{Container: container, Operation: operation, Err: err}
432
-		logrus.Error(err)
433
-		return nil, err
431
+		return nil, makeContainerError(container, operation, "", err)
434 432
 	}
435 433
 
436 434
 	process := &process{
... ...
@@ -440,9 +390,7 @@ func (container *container) OpenProcess(pid int) (Process, error) {
440 440
 	}
441 441
 
442 442
 	if err := process.registerCallback(); err != nil {
443
-		err = &ContainerError{Container: container, Operation: operation, Err: err}
444
-		logrus.Error(err)
445
-		return nil, err
443
+		return nil, makeContainerError(container, operation, "", err)
446 444
 	}
447 445
 
448 446
 	logrus.Debugf(title+" succeeded id=%s processid=%s", container.id, process.processID)
... ...
@@ -463,16 +411,12 @@ func (container *container) Close() error {
463 463
 
464 464
 	if hcsCallbacksSupported {
465 465
 		if err := container.unregisterCallback(); err != nil {
466
-			err = &ContainerError{Container: container, Operation: operation, Err: err}
467
-			logrus.Error(err)
468
-			return err
466
+			return makeContainerError(container, operation, "", err)
469 467
 		}
470 468
 	}
471 469
 
472 470
 	if err := hcsCloseComputeSystem(container.handle); err != nil {
473
-		err = &ContainerError{Container: container, Operation: operation, Err: err}
474
-		logrus.Error(err)
475
-		return err
471
+		return makeContainerError(container, operation, "", err)
476 472
 	}
477 473
 
478 474
 	container.handle = 0
... ...
@@ -487,16 +431,15 @@ func closeContainer(container *container) {
487 487
 }
488 488
 
489 489
 func (container *container) registerCallback() error {
490
-	callbackMapLock.Lock()
491
-	defer callbackMapLock.Unlock()
492
-
493
-	callbackNumber := nextCallback
494
-	nextCallback++
495
-
496 490
 	context := &notifcationWatcherContext{
497 491
 		channels: newChannels(),
498 492
 	}
493
+
494
+	callbackMapLock.Lock()
495
+	callbackNumber := nextCallback
496
+	nextCallback++
499 497
 	callbackMap[callbackNumber] = context
498
+	callbackMapLock.Unlock()
500 499
 
501 500
 	var callbackHandle hcsCallback
502 501
 	err := hcsRegisterComputeSystemCallback(container.handle, notificationWatcherCallback, callbackNumber, &callbackHandle)
... ...
@@ -512,21 +455,32 @@ func (container *container) registerCallback() error {
512 512
 func (container *container) unregisterCallback() error {
513 513
 	callbackNumber := container.callbackNumber
514 514
 
515
-	callbackMapLock.Lock()
516
-	defer callbackMapLock.Unlock()
515
+	callbackMapLock.RLock()
516
+	context := callbackMap[callbackNumber]
517
+	callbackMapLock.RUnlock()
517 518
 
518
-	handle := callbackMap[callbackNumber].handle
519
+	if context == nil {
520
+		return nil
521
+	}
522
+
523
+	handle := context.handle
519 524
 
520 525
 	if handle == 0 {
521 526
 		return nil
522 527
 	}
523 528
 
529
+	// hcsUnregisterComputeSystemCallback has its own syncronization
530
+	// to wait for all callbacks to complete. We must NOT hold the callbackMapLock.
524 531
 	err := hcsUnregisterComputeSystemCallback(handle)
525 532
 	if err != nil {
526 533
 		return err
527 534
 	}
528 535
 
536
+	closeChannels(context.channels)
537
+
538
+	callbackMapLock.Lock()
529 539
 	callbackMap[callbackNumber] = nil
540
+	callbackMapLock.Unlock()
530 541
 
531 542
 	handle = 0
532 543
 
... ...
@@ -558,3 +512,20 @@ func (e *ContainerError) Error() string {
558 558
 
559 559
 	return s
560 560
 }
561
+
562
+func makeContainerError(container *container, operation string, extraInfo string, err error) error {
563
+	// Don't wrap errors created in hcsshim
564
+	if err == ErrTimeout ||
565
+		err == ErrUnexpectedProcessAbort ||
566
+		err == ErrUnexpectedContainerExit ||
567
+		err == ErrHandleClose ||
568
+		err == ErrInvalidProcessState ||
569
+		err == ErrInvalidNotificationType ||
570
+		err == ErrVmcomputeOperationPending {
571
+		return err
572
+	}
573
+
574
+	containerError := &ContainerError{Container: container, Operation: operation, ExtraInfo: extraInfo, Err: err}
575
+	logrus.Error(containerError)
576
+	return containerError
577
+}
... ...
@@ -1,10 +1,33 @@
1 1
 package hcsshim
2 2
 
3 3
 import (
4
+	"errors"
4 5
 	"io"
5 6
 	"time"
6 7
 )
7 8
 
9
+var (
10
+	// ErrInvalidNotificationType is an error encountered when an invalid notification type is used
11
+	ErrInvalidNotificationType = errors.New("hcsshim: invalid notification type")
12
+
13
+	// ErrTimeout is an error encountered when waiting on a notification times out
14
+	ErrTimeout = errors.New("hcsshim: timeout waiting for notification")
15
+
16
+	// ErrHandleClose is an error returned when the handle generating the notification being waited on has been closed
17
+	ErrHandleClose = errors.New("hcsshim: the handle generating this notification has been closed")
18
+
19
+	// ErrInvalidProcessState is an error encountered when the process is not in a valid state for the requested operation
20
+	ErrInvalidProcessState = errors.New("the process is in an invalid state for the attempted operation")
21
+
22
+	// ErrUnexpectedContainerExit is the error returned when a container exits while waiting for
23
+	// a different expected notification
24
+	ErrUnexpectedContainerExit = errors.New("unexpected container exit")
25
+
26
+	// ErrUnexpectedProcessAbort is the error returned when communication with the compute service
27
+	// is lost while waiting for a notification
28
+	ErrUnexpectedProcessAbort = errors.New("lost communication with compute service")
29
+)
30
+
8 31
 // ProcessConfig is used as both the input of Container.CreateProcess
9 32
 // and to convert the parameters to JSON for passing onto the HCS
10 33
 type ProcessConfig struct {
... ...
@@ -11,13 +11,10 @@ import (
11 11
 	"github.com/Sirupsen/logrus"
12 12
 )
13 13
 
14
-var (
15
-	ErrInvalidProcessState = errors.New("the process is in an invalid state for the attempted operation")
16
-)
17
-
18 14
 type ProcessError struct {
19 15
 	Process   *process
20 16
 	Operation string
17
+	ExtraInfo string
21 18
 	Err       error
22 19
 }
23 20
 
... ...
@@ -85,9 +82,7 @@ func (process *process) Kill() error {
85 85
 	if err == ErrVmcomputeOperationPending {
86 86
 		return ErrVmcomputeOperationPending
87 87
 	} else if err != nil {
88
-		err := &ProcessError{Operation: operation, Process: process, Err: err}
89
-		logrus.Error(err)
90
-		return err
88
+		return makeProcessError(process, operation, "", err)
91 89
 	}
92 90
 
93 91
 	logrus.Debugf(title+" succeeded processid=%d", process.processID)
... ...
@@ -103,19 +98,12 @@ func (process *process) Wait() error {
103 103
 	if hcsCallbacksSupported {
104 104
 		err := waitForNotification(process.callbackNumber, hcsNotificationProcessExited, nil)
105 105
 		if err != nil {
106
-			if err == ErrUnexpectedProcessAbort || err == ErrUnexpectedContainerExit {
107
-				return err
108
-			}
109
-			err := &ProcessError{Operation: operation, Process: process, Err: err}
110
-			logrus.Error(err)
111
-			return err
106
+			return makeProcessError(process, operation, "", err)
112 107
 		}
113 108
 	} else {
114 109
 		_, err := process.waitTimeoutInternal(syscall.INFINITE)
115 110
 		if err != nil {
116
-			err := &ProcessError{Operation: operation, Process: process, Err: err}
117
-			logrus.Error(err)
118
-			return err
111
+			return makeProcessError(process, operation, "", err)
119 112
 		}
120 113
 	}
121 114
 
... ...
@@ -133,21 +121,14 @@ func (process *process) WaitTimeout(timeout time.Duration) error {
133 133
 	if hcsCallbacksSupported {
134 134
 		err := waitForNotification(process.callbackNumber, hcsNotificationProcessExited, &timeout)
135 135
 		if err != nil {
136
-			if err == ErrTimeout || err == ErrUnexpectedProcessAbort || err == ErrUnexpectedContainerExit {
137
-				return err
138
-			}
139
-			err := &ProcessError{Operation: operation, Process: process, Err: err}
140
-			logrus.Error(err)
141
-			return err
136
+			return makeProcessError(process, operation, "", err)
142 137
 		}
143 138
 	} else {
144 139
 		finished, err := waitTimeoutHelper(process, timeout)
145 140
 		if !finished {
146 141
 			return ErrTimeout
147 142
 		} else if err != nil {
148
-			err := &ProcessError{Operation: operation, Process: process, Err: err}
149
-			logrus.Error(err)
150
-			return err
143
+			return makeProcessError(process, operation, "", err)
151 144
 		}
152 145
 	}
153 146
 
... ...
@@ -183,9 +164,7 @@ func (process *process) ExitCode() (int, error) {
183 183
 
184 184
 	properties, err := process.properties()
185 185
 	if err != nil {
186
-		err := &ProcessError{Operation: operation, Process: process, Err: err}
187
-		logrus.Error(err)
188
-		return 0, err
186
+		return 0, makeProcessError(process, operation, "", err)
189 187
 	}
190 188
 
191 189
 	if properties.Exited == false {
... ...
@@ -221,9 +200,7 @@ func (process *process) ResizeConsole(width, height uint16) error {
221 221
 	err = hcsModifyProcess(process.handle, modifyRequestStr, &resultp)
222 222
 	err = processHcsResult(err, resultp)
223 223
 	if err != nil {
224
-		err := &ProcessError{Operation: operation, Process: process, Err: err}
225
-		logrus.Error(err)
226
-		return err
224
+		return makeProcessError(process, operation, "", err)
227 225
 	}
228 226
 
229 227
 	logrus.Debugf(title+" succeeded processid=%d", process.processID)
... ...
@@ -242,9 +219,7 @@ func (process *process) properties() (*processStatus, error) {
242 242
 	err := hcsGetProcessProperties(process.handle, &propertiesp, &resultp)
243 243
 	err = processHcsResult(err, resultp)
244 244
 	if err != nil {
245
-		err := &ProcessError{Operation: operation, Process: process, Err: err}
246
-		logrus.Error(err)
247
-		return nil, err
245
+		return nil, makeProcessError(process, operation, "", err)
248 246
 	}
249 247
 
250 248
 	if propertiesp == nil {
... ...
@@ -279,9 +254,7 @@ func (process *process) Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, e
279 279
 		err := hcsGetProcessInfo(process.handle, &processInfo, &resultp)
280 280
 		err = processHcsResult(err, resultp)
281 281
 		if err != nil {
282
-			err = &ProcessError{Operation: operation, Process: process, Err: err}
283
-			logrus.Error(err)
284
-			return nil, nil, nil, err
282
+			return nil, nil, nil, makeProcessError(process, operation, "", err)
285 283
 		}
286 284
 
287 285
 		stdIn, stdOut, stdErr = processInfo.StdInput, processInfo.StdOutput, processInfo.StdError
... ...
@@ -327,9 +300,7 @@ func (process *process) CloseStdin() error {
327 327
 	err = hcsModifyProcess(process.handle, modifyRequestStr, &resultp)
328 328
 	err = processHcsResult(err, resultp)
329 329
 	if err != nil {
330
-		err = &ProcessError{Operation: operation, Process: process, Err: err}
331
-		logrus.Error(err)
332
-		return err
330
+		return makeProcessError(process, operation, "", err)
333 331
 	}
334 332
 
335 333
 	logrus.Debugf(title+" succeeded processid=%d", process.processID)
... ...
@@ -350,16 +321,12 @@ func (process *process) Close() error {
350 350
 
351 351
 	if hcsCallbacksSupported {
352 352
 		if err := process.unregisterCallback(); err != nil {
353
-			err = &ProcessError{Operation: operation, Process: process, Err: err}
354
-			logrus.Error(err)
355
-			return err
353
+			return makeProcessError(process, operation, "", err)
356 354
 		}
357 355
 	}
358 356
 
359 357
 	if err := hcsCloseProcess(process.handle); err != nil {
360
-		err = &ProcessError{Operation: operation, Process: process, Err: err}
361
-		logrus.Error(err)
362
-		return err
358
+		return makeProcessError(process, operation, "", err)
363 359
 	}
364 360
 
365 361
 	process.handle = 0
... ...
@@ -374,16 +341,15 @@ func closeProcess(process *process) {
374 374
 }
375 375
 
376 376
 func (process *process) registerCallback() error {
377
-	callbackMapLock.Lock()
378
-	defer callbackMapLock.Unlock()
379
-
380
-	callbackNumber := nextCallback
381
-	nextCallback++
382
-
383 377
 	context := &notifcationWatcherContext{
384 378
 		channels: newChannels(),
385 379
 	}
380
+
381
+	callbackMapLock.Lock()
382
+	callbackNumber := nextCallback
383
+	nextCallback++
386 384
 	callbackMap[callbackNumber] = context
385
+	callbackMapLock.Unlock()
387 386
 
388 387
 	var callbackHandle hcsCallback
389 388
 	err := hcsRegisterProcessCallback(process.handle, notificationWatcherCallback, callbackNumber, &callbackHandle)
... ...
@@ -399,20 +365,32 @@ func (process *process) registerCallback() error {
399 399
 func (process *process) unregisterCallback() error {
400 400
 	callbackNumber := process.callbackNumber
401 401
 
402
-	callbackMapLock.Lock()
403
-	defer callbackMapLock.Unlock()
404
-	handle := callbackMap[callbackNumber].handle
402
+	callbackMapLock.RLock()
403
+	context := callbackMap[callbackNumber]
404
+	callbackMapLock.RUnlock()
405
+
406
+	if context == nil {
407
+		return nil
408
+	}
409
+
410
+	handle := context.handle
405 411
 
406 412
 	if handle == 0 {
407 413
 		return nil
408 414
 	}
409 415
 
416
+	// hcsUnregisterProcessCallback has its own syncronization
417
+	// to wait for all callbacks to complete. We must NOT hold the callbackMapLock.
410 418
 	err := hcsUnregisterProcessCallback(handle)
411 419
 	if err != nil {
412 420
 		return err
413 421
 	}
414 422
 
423
+	closeChannels(context.channels)
424
+
425
+	callbackMapLock.Lock()
415 426
 	callbackMap[callbackNumber] = nil
427
+	callbackMapLock.Unlock()
416 428
 
417 429
 	handle = 0
418 430
 
... ...
@@ -444,3 +422,20 @@ func (e *ProcessError) Error() string {
444 444
 
445 445
 	return s
446 446
 }
447
+
448
+func makeProcessError(process *process, operation string, extraInfo string, err error) error {
449
+	// Don't wrap errors created in hcsshim
450
+	if err == ErrTimeout ||
451
+		err == ErrUnexpectedProcessAbort ||
452
+		err == ErrUnexpectedContainerExit ||
453
+		err == ErrHandleClose ||
454
+		err == ErrInvalidProcessState ||
455
+		err == ErrInvalidNotificationType ||
456
+		err == ErrVmcomputeOperationPending {
457
+		return err
458
+	}
459
+
460
+	processError := &ProcessError{Process: process, Operation: operation, ExtraInfo: extraInfo, Err: err}
461
+	logrus.Error(processError)
462
+	return processError
463
+}
... ...
@@ -65,6 +65,7 @@ func waitForNotification(callbackNumber uintptr, expectedNotification hcsNotific
65 65
 	expectedChannel := channels[expectedNotification]
66 66
 	if expectedChannel == nil {
67 67
 		logrus.Errorf("unknown notification type in waitForNotification %x", expectedNotification)
68
+		return ErrInvalidNotificationType
68 69
 	}
69 70
 
70 71
 	if timeout != nil {
... ...
@@ -72,38 +73,54 @@ func waitForNotification(callbackNumber uintptr, expectedNotification hcsNotific
72 72
 		defer timer.Stop()
73 73
 
74 74
 		select {
75
-		case err := <-expectedChannel:
75
+		case err, ok := <-expectedChannel:
76
+			if !ok {
77
+				return ErrHandleClose
78
+			}
76 79
 			return err
77
-		case err := <-channels[hcsNotificationSystemExited]:
80
+		case err, ok := <-channels[hcsNotificationSystemExited]:
81
+			if !ok {
82
+				return ErrHandleClose
83
+			}
78 84
 			// If the expected notification is hcsNotificationSystemExited which of the two selects
79 85
 			// chosen is random. Return the raw error if hcsNotificationSystemExited is expected
80 86
 			if channels[hcsNotificationSystemExited] == expectedChannel {
81 87
 				return err
82 88
 			}
83 89
 			return ErrUnexpectedContainerExit
84
-		case err := <-channels[hcsNotificationServiceDisconnect]:
90
+		case _, ok := <-channels[hcsNotificationServiceDisconnect]:
91
+			if !ok {
92
+				return ErrHandleClose
93
+			}
85 94
 			// hcsNotificationServiceDisconnect should never be an expected notification
86 95
 			// it does not need the same handling as hcsNotificationSystemExited
87
-			logrus.Error(err)
88 96
 			return ErrUnexpectedProcessAbort
89 97
 		case <-timer.C:
90 98
 			return ErrTimeout
91 99
 		}
92 100
 	}
93 101
 	select {
94
-	case err := <-expectedChannel:
102
+	case err, ok := <-expectedChannel:
103
+		if !ok {
104
+			return ErrHandleClose
105
+		}
95 106
 		return err
96
-	case err := <-channels[hcsNotificationSystemExited]:
107
+	case err, ok := <-channels[hcsNotificationSystemExited]:
108
+		if !ok {
109
+			return ErrHandleClose
110
+		}
97 111
 		// If the expected notification is hcsNotificationSystemExited which of the two selects
98 112
 		// chosen is random. Return the raw error if hcsNotificationSystemExited is expected
99 113
 		if channels[hcsNotificationSystemExited] == expectedChannel {
100 114
 			return err
101 115
 		}
102 116
 		return ErrUnexpectedContainerExit
103
-	case err := <-channels[hcsNotificationServiceDisconnect]:
117
+	case _, ok := <-channels[hcsNotificationServiceDisconnect]:
118
+		if !ok {
119
+			return ErrHandleClose
120
+		}
104 121
 		// hcsNotificationServiceDisconnect should never be an expected notification
105 122
 		// it does not need the same handling as hcsNotificationSystemExited
106
-		logrus.Error(err)
107 123
 		return ErrUnexpectedProcessAbort
108 124
 	}
109 125
 }