1package hcsshim
2
3import (
4	"time"
5
6	"github.com/sirupsen/logrus"
7)
8
9func processAsyncHcsResult(err error, resultp *uint16, callbackNumber uintptr, expectedNotification hcsNotification, timeout *time.Duration) error {
10	err = processHcsResult(err, resultp)
11	if IsPending(err) {
12		return waitForNotification(callbackNumber, expectedNotification, timeout)
13	}
14
15	return err
16}
17
18func waitForNotification(callbackNumber uintptr, expectedNotification hcsNotification, timeout *time.Duration) error {
19	callbackMapLock.RLock()
20	channels := callbackMap[callbackNumber].channels
21	callbackMapLock.RUnlock()
22
23	expectedChannel := channels[expectedNotification]
24	if expectedChannel == nil {
25		logrus.Errorf("unknown notification type in waitForNotification %x", expectedNotification)
26		return ErrInvalidNotificationType
27	}
28
29	var c <-chan time.Time
30	if timeout != nil {
31		timer := time.NewTimer(*timeout)
32		c = timer.C
33		defer timer.Stop()
34	}
35
36	select {
37	case err, ok := <-expectedChannel:
38		if !ok {
39			return ErrHandleClose
40		}
41		return err
42	case err, ok := <-channels[hcsNotificationSystemExited]:
43		if !ok {
44			return ErrHandleClose
45		}
46		// If the expected notification is hcsNotificationSystemExited which of the two selects
47		// chosen is random. Return the raw error if hcsNotificationSystemExited is expected
48		if channels[hcsNotificationSystemExited] == expectedChannel {
49			return err
50		}
51		return ErrUnexpectedContainerExit
52	case _, ok := <-channels[hcsNotificationServiceDisconnect]:
53		if !ok {
54			return ErrHandleClose
55		}
56		// hcsNotificationServiceDisconnect should never be an expected notification
57		// it does not need the same handling as hcsNotificationSystemExited
58		return ErrUnexpectedProcessAbort
59	case <-c:
60		return ErrTimeout
61	}
62	return nil
63}
64