...
1
2
3 package hcs
4
5 import (
6 "fmt"
7 "sync"
8 "syscall"
9
10 "github.com/Microsoft/hcsshim/internal/interop"
11 "github.com/Microsoft/hcsshim/internal/logfields"
12 "github.com/Microsoft/hcsshim/internal/vmcompute"
13 "github.com/sirupsen/logrus"
14 )
15
16 var (
17 nextCallback uintptr
18 callbackMap = map[uintptr]*notificationWatcherContext{}
19 callbackMapLock = sync.RWMutex{}
20
21 notificationWatcherCallback = syscall.NewCallback(notificationWatcher)
22
23
24 hcsNotificationSystemExited hcsNotification = 0x00000001
25 hcsNotificationSystemCreateCompleted hcsNotification = 0x00000002
26 hcsNotificationSystemStartCompleted hcsNotification = 0x00000003
27 hcsNotificationSystemPauseCompleted hcsNotification = 0x00000004
28 hcsNotificationSystemResumeCompleted hcsNotification = 0x00000005
29 hcsNotificationSystemCrashReport hcsNotification = 0x00000006
30 hcsNotificationSystemSiloJobCreated hcsNotification = 0x00000007
31 hcsNotificationSystemSaveCompleted hcsNotification = 0x00000008
32 hcsNotificationSystemRdpEnhancedModeStateChanged hcsNotification = 0x00000009
33 hcsNotificationSystemShutdownFailed hcsNotification = 0x0000000A
34 hcsNotificationSystemGetPropertiesCompleted hcsNotification = 0x0000000B
35 hcsNotificationSystemModifyCompleted hcsNotification = 0x0000000C
36 hcsNotificationSystemCrashInitiated hcsNotification = 0x0000000D
37 hcsNotificationSystemGuestConnectionClosed hcsNotification = 0x0000000E
38
39
40 hcsNotificationProcessExited hcsNotification = 0x00010000
41
42
43 hcsNotificationInvalid hcsNotification = 0x00000000
44 hcsNotificationServiceDisconnect hcsNotification = 0x01000000
45 )
46
47 type hcsNotification uint32
48
49 func (hn hcsNotification) String() string {
50 switch hn {
51 case hcsNotificationSystemExited:
52 return "SystemExited"
53 case hcsNotificationSystemCreateCompleted:
54 return "SystemCreateCompleted"
55 case hcsNotificationSystemStartCompleted:
56 return "SystemStartCompleted"
57 case hcsNotificationSystemPauseCompleted:
58 return "SystemPauseCompleted"
59 case hcsNotificationSystemResumeCompleted:
60 return "SystemResumeCompleted"
61 case hcsNotificationSystemCrashReport:
62 return "SystemCrashReport"
63 case hcsNotificationSystemSiloJobCreated:
64 return "SystemSiloJobCreated"
65 case hcsNotificationSystemSaveCompleted:
66 return "SystemSaveCompleted"
67 case hcsNotificationSystemRdpEnhancedModeStateChanged:
68 return "SystemRdpEnhancedModeStateChanged"
69 case hcsNotificationSystemShutdownFailed:
70 return "SystemShutdownFailed"
71 case hcsNotificationSystemGetPropertiesCompleted:
72 return "SystemGetPropertiesCompleted"
73 case hcsNotificationSystemModifyCompleted:
74 return "SystemModifyCompleted"
75 case hcsNotificationSystemCrashInitiated:
76 return "SystemCrashInitiated"
77 case hcsNotificationSystemGuestConnectionClosed:
78 return "SystemGuestConnectionClosed"
79 case hcsNotificationProcessExited:
80 return "ProcessExited"
81 case hcsNotificationInvalid:
82 return "Invalid"
83 case hcsNotificationServiceDisconnect:
84 return "ServiceDisconnect"
85 default:
86 return fmt.Sprintf("Unknown: %d", hn)
87 }
88 }
89
90 type notificationChannel chan error
91
92 type notificationWatcherContext struct {
93 channels notificationChannels
94 handle vmcompute.HcsCallback
95
96 systemID string
97 processID int
98 }
99
100 type notificationChannels map[hcsNotification]notificationChannel
101
102 func newSystemChannels() notificationChannels {
103 channels := make(notificationChannels)
104 for _, notif := range []hcsNotification{
105 hcsNotificationServiceDisconnect,
106 hcsNotificationSystemExited,
107 hcsNotificationSystemCreateCompleted,
108 hcsNotificationSystemStartCompleted,
109 hcsNotificationSystemPauseCompleted,
110 hcsNotificationSystemResumeCompleted,
111 hcsNotificationSystemSaveCompleted,
112 } {
113 channels[notif] = make(notificationChannel, 1)
114 }
115 return channels
116 }
117
118 func newProcessChannels() notificationChannels {
119 channels := make(notificationChannels)
120 for _, notif := range []hcsNotification{
121 hcsNotificationServiceDisconnect,
122 hcsNotificationProcessExited,
123 } {
124 channels[notif] = make(notificationChannel, 1)
125 }
126 return channels
127 }
128
129 func closeChannels(channels notificationChannels) {
130 for _, c := range channels {
131 close(c)
132 }
133 }
134
135 func notificationWatcher(notificationType hcsNotification, callbackNumber uintptr, notificationStatus uintptr, notificationData *uint16) uintptr {
136 var result error
137 if int32(notificationStatus) < 0 {
138 result = interop.Win32FromHresult(notificationStatus)
139 }
140
141 callbackMapLock.RLock()
142 context := callbackMap[callbackNumber]
143 callbackMapLock.RUnlock()
144
145 if context == nil {
146 return 0
147 }
148
149 log := logrus.WithFields(logrus.Fields{
150 "notification-type": notificationType.String(),
151 "system-id": context.systemID,
152 })
153 if context.processID != 0 {
154 log.Data[logfields.ProcessID] = context.processID
155 }
156 log.Debug("HCS notification")
157
158 if channel, ok := context.channels[notificationType]; ok {
159 channel <- result
160 }
161
162 return 0
163 }
164
View as plain text