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