callback.go 5.0 KB

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