callback.go 5.3 KB

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