package hcs import ( "context" "time" "github.com/Microsoft/hcsshim/internal/log" ) func processAsyncHcsResult(ctx context.Context, err error, resultJSON string, callbackNumber uintptr, expectedNotification hcsNotification, timeout *time.Duration) ([]ErrorEvent, error) { events := processHcsResult(ctx, resultJSON) if IsPending(err) { return nil, waitForNotification(ctx, callbackNumber, expectedNotification, timeout) } return events, err } func waitForNotification(ctx context.Context, callbackNumber uintptr, expectedNotification hcsNotification, timeout *time.Duration) error { callbackMapLock.RLock() if _, ok := callbackMap[callbackNumber]; !ok { callbackMapLock.RUnlock() log.G(ctx).WithField("callbackNumber", callbackNumber).Error("failed to waitForNotification: callbackNumber does not exist in callbackMap") return ErrHandleClose } channels := callbackMap[callbackNumber].channels callbackMapLock.RUnlock() expectedChannel := channels[expectedNotification] if expectedChannel == nil { log.G(ctx).WithField("type", expectedNotification).Error("unknown notification type in waitForNotification") return ErrInvalidNotificationType } var c <-chan time.Time if timeout != nil { timer := time.NewTimer(*timeout) c = timer.C defer timer.Stop() } select { case err, ok := <-expectedChannel: if !ok { return ErrHandleClose } return err case err, ok := <-channels[hcsNotificationSystemExited]: if !ok { return ErrHandleClose } // If the expected notification is hcsNotificationSystemExited which of the two selects // chosen is random. Return the raw error if hcsNotificationSystemExited is expected if channels[hcsNotificationSystemExited] == expectedChannel { return err } return ErrUnexpectedContainerExit case _, ok := <-channels[hcsNotificationServiceDisconnect]: if !ok { return ErrHandleClose } // hcsNotificationServiceDisconnect should never be an expected notification // it does not need the same handling as hcsNotificationSystemExited return ErrUnexpectedProcessAbort case <-c: return ErrTimeout } return nil }