Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

475 lines
8.5 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. object.c
  5. Abstract:
  6. This is the NT Watchdog driver implementation.
  7. Author:
  8. Michael Maciesowicz (mmacie) 02-May-2001
  9. Environment:
  10. Kernel mode only.
  11. Notes:
  12. Revision History:
  13. --*/
  14. #include "wd.h"
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text (PAGE, WdFlushRegistryKey)
  17. #pragma alloc_text (PAGE, WdInitializeObject)
  18. #endif
  19. //
  20. // Exports.
  21. //
  22. WATCHDOGAPI
  23. VOID
  24. WdCompleteEvent(
  25. IN PVOID pWatch,
  26. IN PKTHREAD pThread
  27. )
  28. /*++
  29. Routine Description:
  30. This function *MUST* be called from client handler for watchdog timeout event
  31. before exiting. It removes references from watchdog and thread objects.
  32. It also reenables watchdog event generation for deferred watchdog objects.
  33. Arguments:
  34. pWatch - Points to WATCHDOG_OBJECT.
  35. pThread - Points to KTHREAD object for spinning thread.
  36. Return Value:
  37. None.
  38. --*/
  39. {
  40. //
  41. // Note: pThread is NULL for recovery events.
  42. //
  43. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  44. ASSERT_WATCHDOG_OBJECT(pWatch);
  45. //
  46. // Resume event generation for deferred watchdog.
  47. //
  48. if (WdDeferredWatchdog == ((PWATCHDOG_OBJECT)pWatch)->ObjectType)
  49. {
  50. InterlockedExchange(&(((PDEFERRED_WATCHDOG)pWatch)->Trigger), 0);
  51. }
  52. //
  53. // Drop reference counts.
  54. //
  55. if (NULL != pThread)
  56. {
  57. ObDereferenceObject(pThread);
  58. }
  59. WdDereferenceObject(pWatch);
  60. return;
  61. } // WdCompleteEvent()
  62. WATCHDOGAPI
  63. VOID
  64. WdDereferenceObject(
  65. IN PVOID pWatch
  66. )
  67. /*++
  68. Routine Description:
  69. This function decreases reference count of watchdog object.
  70. If remaining count is zero we will remove object here, since it's
  71. been freed already.
  72. Arguments:
  73. pWatch - Points to WATCHDOG_OBJECT.
  74. Return Value:
  75. None.
  76. --*/
  77. {
  78. PWATCHDOG_OBJECT pWatchdogObject;
  79. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  80. ASSERT_WATCHDOG_OBJECT(pWatch);
  81. pWatchdogObject = (PWATCHDOG_OBJECT)pWatch;
  82. ASSERT(pWatchdogObject->ReferenceCount > 0);
  83. //
  84. // Drop reference count and remove the object if fully dereferenced.
  85. //
  86. if (InterlockedDecrement(&(pWatchdogObject->ReferenceCount)) == 0)
  87. {
  88. //
  89. // Object already freed - remove it now.
  90. //
  91. WdRemoveObject(pWatchdogObject);
  92. }
  93. return;
  94. } // WdDereferenceObject()
  95. WATCHDOGAPI
  96. PDEVICE_OBJECT
  97. WdGetDeviceObject(
  98. IN PVOID pWatch
  99. )
  100. /*++
  101. Routine Description:
  102. This function return pointer to device object associated with watchdog object.
  103. This function increases reference count on DEVICE_OBJECT so the caller must call
  104. ObDereferenceObject() once DEVICE_OBJECT pointer is not needed any more.
  105. Arguments:
  106. pWatch - Points to WATCHDOG_OBJECT.
  107. Return Value:
  108. Pointer to DEVICE_OBJECT.
  109. --*/
  110. {
  111. PDEVICE_OBJECT pDeviceObject;
  112. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  113. ASSERT_WATCHDOG_OBJECT(pWatch);
  114. pDeviceObject = ((PWATCHDOG_OBJECT)pWatch)->DeviceObject;
  115. ASSERT(NULL != pDeviceObject);
  116. ObReferenceObject(pDeviceObject);
  117. return pDeviceObject;
  118. } // WdGetDeviceObject()
  119. WATCHDOGAPI
  120. WD_EVENT_TYPE
  121. WdGetLastEvent(
  122. IN PVOID pWatch
  123. )
  124. /*++
  125. Routine Description:
  126. This function return last event associated with watchdog object.
  127. Arguments:
  128. pWatch - Points to WATCHDOG_OBJECT.
  129. Return Value:
  130. Last event type.
  131. --*/
  132. {
  133. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  134. ASSERT_WATCHDOG_OBJECT(pWatch);
  135. return ((PWATCHDOG_OBJECT)pWatch)->LastEvent;
  136. } // WdGetLastEvent()
  137. WATCHDOGAPI
  138. PDEVICE_OBJECT
  139. WdGetLowestDeviceObject(
  140. IN PVOID pWatch
  141. )
  142. /*++
  143. Routine Description:
  144. This function return pointer to the lowest (most likely PDO) DEVICE_OBJECT
  145. associated with watchdog object. This function increases reference count on
  146. returned DEVICE_OBJECT - the caller must call ObDereferenceObject() once
  147. DEVICE_OBJECT pointer is not needed any more.
  148. Arguments:
  149. pWatch - Points to WATCHDOG_OBJECT.
  150. Return Value:
  151. Pointer to DEVICE_OBJECT.
  152. --*/
  153. {
  154. PDEVICE_OBJECT pDeviceObject;
  155. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  156. ASSERT_WATCHDOG_OBJECT(pWatch);
  157. //
  158. // Note: No need to bump reference count here, it is always done when
  159. // watchdog object is created.
  160. //
  161. pDeviceObject = ((PWATCHDOG_OBJECT)pWatch)->DeviceObject;
  162. ASSERT(NULL != pDeviceObject);
  163. //
  164. // Now get the pointer to the lowest device object in the stack.
  165. // Note: This call automatically bumps a reference count on returned object.
  166. //
  167. pDeviceObject = IoGetDeviceAttachmentBaseRef(pDeviceObject);
  168. ASSERT(NULL != pDeviceObject);
  169. return pDeviceObject;
  170. } // WdGetLowestDeviceObject()
  171. WATCHDOGAPI
  172. VOID
  173. WdReferenceObject(
  174. IN PVOID pWatch
  175. )
  176. /*++
  177. Routine Description:
  178. This function increases reference count of watchdog object.
  179. Arguments:
  180. pWatch - Points to WATCHDOG_OBJECT.
  181. Return Value:
  182. None.
  183. --*/
  184. {
  185. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  186. ASSERT_WATCHDOG_OBJECT(pWatch);
  187. if (InterlockedIncrement(&(((PWATCHDOG_OBJECT)pWatch)->ReferenceCount)) == 1)
  188. {
  189. //
  190. // Somebody referenced removed object.
  191. //
  192. ASSERT(FALSE);
  193. }
  194. //
  195. // Check for overflow.
  196. //
  197. ASSERT(((PWATCHDOG_OBJECT)pWatch)->ReferenceCount > 0);
  198. return;
  199. } // WdReferenceObject()
  200. //
  201. // Non-exports.
  202. //
  203. NTSTATUS
  204. WdFlushRegistryKey(
  205. IN PVOID pWatch,
  206. IN PCWSTR pwszKeyName
  207. )
  208. /*++
  209. Routine Description:
  210. This function forces a registry key to be committed to disk.
  211. Arguments:
  212. pWatch - Points to WATCHDOG_OBJECT.
  213. pwszKeyName - Points to key name string.
  214. Return Value:
  215. Status code.
  216. --*/
  217. {
  218. OBJECT_ATTRIBUTES objectAttributes;
  219. UNICODE_STRING unicodeKeyName;
  220. HANDLE keyHandle;
  221. NTSTATUS ntStatus;
  222. PAGED_CODE();
  223. UNREFERENCED_PARAMETER(pWatch);
  224. ASSERT(NULL != pwszKeyName);
  225. RtlInitUnicodeString(&unicodeKeyName, pwszKeyName);
  226. InitializeObjectAttributes(&objectAttributes,
  227. &unicodeKeyName,
  228. OBJ_CASE_INSENSITIVE,
  229. NULL,
  230. NULL);
  231. ntStatus = ZwOpenKey(&keyHandle,
  232. KEY_READ | KEY_WRITE,
  233. &objectAttributes);
  234. if (NT_SUCCESS(ntStatus))
  235. {
  236. ntStatus = ZwFlushKey(keyHandle);
  237. ZwClose(keyHandle);
  238. }
  239. return ntStatus;
  240. } // WdFlushRegistryKey()
  241. VOID
  242. WdInitializeObject(
  243. IN PVOID pWatch,
  244. IN PDEVICE_OBJECT pDeviceObject,
  245. IN WD_OBJECT_TYPE objectType,
  246. IN WD_TIME_TYPE timeType,
  247. IN ULONG ulTag
  248. )
  249. /*++
  250. Routine Description:
  251. This function initializes watchdog object.
  252. Arguments:
  253. pWatch - Points to WATCHDOG_OBJECT.
  254. pDeviceObject - Points to DEVICE_OBJECT associated with watchdog.
  255. objectType - Type of watchdog object.
  256. timeType - Kernel, User, Both thread time to monitor.
  257. ulTag - A tag identifying owner.
  258. Return Value:
  259. None.
  260. --*/
  261. {
  262. PWATCHDOG_OBJECT pWatchdogObject;
  263. PAGED_CODE();
  264. ASSERT(NULL != pWatch);
  265. ASSERT(NULL != pDeviceObject);
  266. ASSERT((objectType == WdStandardWatchdog) || (objectType == WdDeferredWatchdog));
  267. ASSERT((timeType >= WdKernelTime) && (timeType <= WdFullTime));
  268. pWatchdogObject = (PWATCHDOG_OBJECT)pWatch;
  269. //
  270. // Set initial state of watchdog object.
  271. //
  272. pWatchdogObject->ObjectType = objectType;
  273. pWatchdogObject->ReferenceCount = 1;
  274. pWatchdogObject->OwnerTag = ulTag;
  275. pWatchdogObject->DeviceObject = pDeviceObject;
  276. pWatchdogObject->TimeType = timeType;
  277. pWatchdogObject->LastEvent = WdNoEvent;
  278. pWatchdogObject->LastQueuedThread = NULL;
  279. //
  280. // Bump reference count on device object.
  281. //
  282. ObReferenceObject(pDeviceObject);
  283. //
  284. // Initialize encapsulated KSPIN_LOCK object.
  285. //
  286. KeInitializeSpinLock(&(pWatchdogObject->SpinLock));
  287. return;
  288. } // WdInitializeObject()
  289. VOID
  290. WdRemoveObject(
  291. IN PVOID pWatch
  292. )
  293. /*++
  294. Routine Description:
  295. This function unconditionally removes watchdog object.
  296. Arguments:
  297. pWatch - Points to WATCHDOG_OBJECT.
  298. Return Value:
  299. None.
  300. --*/
  301. {
  302. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  303. ASSERT_WATCHDOG_OBJECT(pWatch);
  304. ASSERT(0 == ((PWATCHDOG_OBJECT)pWatch)->ReferenceCount);
  305. //
  306. // Drop reference count on device object.
  307. //
  308. ObDereferenceObject(((PWATCHDOG_OBJECT)pWatch)->DeviceObject);
  309. //
  310. // We are freeing non-paged pool, it's OK to be at IRQL <= DISPATCH_LEVEL.
  311. //
  312. ExFreePool(pWatch);
  313. return;
  314. } // WdRemoveObject()