Leaked source code of windows server 2003
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.

321 lines
8.4 KiB

  1. /*****************************************************************************
  2. * callback.cpp - Generic unload safe callbacks (where possible)
  3. *****************************************************************************
  4. * Copyright (c) 1999-2000 Microsoft Corporation. All rights reserved.
  5. */
  6. #include "private.h"
  7. VOID
  8. EnqueuedIoWorkItemCallback(
  9. IN PDEVICE_OBJECT DeviceObject,
  10. IN PVOID Context
  11. );
  12. VOID
  13. EnqueuedDpcCallback(
  14. IN PKDPC Dpc,
  15. IN PVOID DeferredContext,
  16. IN PVOID SystemArgument1,
  17. IN PVOID SystemArgument2
  18. );
  19. #pragma code_seg()
  20. NTSTATUS
  21. CallbackEnqueue(
  22. IN OUT PVOID *pCallbackHandle OPTIONAL,
  23. IN PFNQUEUED_CALLBACK CallbackRoutine,
  24. IN PDEVICE_OBJECT DeviceObject,
  25. IN PVOID Context,
  26. IN KIRQL Irql,
  27. IN ULONG Flags
  28. )
  29. {
  30. PQUEUED_CALLBACK_ITEM pQueuedCallbackItem;
  31. //
  32. // Check the flags we understand. If it's not understood, and this is the
  33. // class of flags support is required for, bail immediately.
  34. //
  35. if ((Flags & (~EQCM_SUPPORTED_FLAGS)) & EQCM_SUPPORT_OR_FAIL_FLAGS) {
  36. return STATUS_NOT_SUPPORTED;
  37. }
  38. if ((Irql != PASSIVE_LEVEL) && (Irql != DISPATCH_LEVEL)) {
  39. ASSERT(0);
  40. return STATUS_NOT_SUPPORTED;
  41. }
  42. if (Flags & EQCF_REUSE_HANDLE) {
  43. ASSERT(pCallbackHandle);
  44. pQueuedCallbackItem = (PQUEUED_CALLBACK_ITEM) *pCallbackHandle;
  45. //
  46. // Shouldn't already be enqueued.
  47. //
  48. ASSERT(pQueuedCallbackItem->Enqueued == 0);
  49. } else {
  50. pQueuedCallbackItem = (PQUEUED_CALLBACK_ITEM) ExAllocatePoolWithTag(
  51. ((KeGetCurrentIrql() == PASSIVE_LEVEL) && (Irql == PASSIVE_LEVEL)) ?
  52. PagedPool : NonPagedPool,
  53. sizeof(QUEUED_CALLBACK_ITEM),
  54. 'bCcP'
  55. ); // 'PcCb'
  56. if (pQueuedCallbackItem) {
  57. pQueuedCallbackItem->ReentrancyCount = 0;
  58. pQueuedCallbackItem->IoWorkItem = IoAllocateWorkItem(
  59. DeviceObject
  60. );
  61. if (pQueuedCallbackItem->IoWorkItem == NULL) {
  62. ExFreePool(pQueuedCallbackItem);
  63. pQueuedCallbackItem = NULL;
  64. }
  65. }
  66. }
  67. if (ARGUMENT_PRESENT(pCallbackHandle)) {
  68. *pCallbackHandle = pQueuedCallbackItem;
  69. }
  70. if (pQueuedCallbackItem) {
  71. pQueuedCallbackItem->QueuedCallback = CallbackRoutine;
  72. pQueuedCallbackItem->DeviceObject = DeviceObject;
  73. pQueuedCallbackItem->Context = Context;
  74. pQueuedCallbackItem->Flags = Flags;
  75. pQueuedCallbackItem->Irql = Irql;
  76. pQueuedCallbackItem->Enqueued = 1;
  77. if ((!(Flags&EQCF_DIFFERENT_THREAD_REQUIRED)) &&
  78. (KeGetCurrentIrql() == Irql)&&
  79. (pQueuedCallbackItem->ReentrancyCount < MAX_THREAD_REENTRANCY)) {
  80. pQueuedCallbackItem->ReentrancyCount++;
  81. EnqueuedIoWorkItemCallback(DeviceObject, (PVOID) pQueuedCallbackItem);
  82. } else {
  83. pQueuedCallbackItem->ReentrancyCount = 0;
  84. if (Irql == PASSIVE_LEVEL) {
  85. IoQueueWorkItem(
  86. pQueuedCallbackItem->IoWorkItem,
  87. EnqueuedIoWorkItemCallback,
  88. DelayedWorkQueue,
  89. pQueuedCallbackItem
  90. );
  91. } else {
  92. ASSERT(Irql == DISPATCH_LEVEL);
  93. KeInitializeDpc(
  94. &pQueuedCallbackItem->Dpc,
  95. EnqueuedDpcCallback,
  96. pQueuedCallbackItem
  97. );
  98. KeInsertQueueDpc(
  99. &pQueuedCallbackItem->Dpc,
  100. NULL,
  101. NULL
  102. );
  103. }
  104. }
  105. return STATUS_SUCCESS;
  106. } else {
  107. return STATUS_INSUFFICIENT_RESOURCES;
  108. }
  109. }
  110. NTSTATUS
  111. CallbackCancel(
  112. IN PVOID pCallbackHandle
  113. )
  114. {
  115. PQUEUED_CALLBACK_ITEM pQueuedCallbackItem;
  116. pQueuedCallbackItem = (PQUEUED_CALLBACK_ITEM) pCallbackHandle;
  117. if (InterlockedExchange(&pQueuedCallbackItem->Enqueued, 0) == 1) {
  118. //
  119. // We got it. If it's DPC, also try to yank it from the queue.
  120. //
  121. if (pQueuedCallbackItem->Irql == DISPATCH_LEVEL) {
  122. KeRemoveQueueDpc(&pQueuedCallbackItem->Dpc);
  123. }
  124. return STATUS_SUCCESS;
  125. } else {
  126. //
  127. // Caller beat us to it...
  128. //
  129. return STATUS_UNSUCCESSFUL;
  130. }
  131. }
  132. VOID
  133. CallbackFree(
  134. IN PVOID pCallbackHandle
  135. )
  136. {
  137. PQUEUED_CALLBACK_ITEM pQueuedCallbackItem;
  138. pQueuedCallbackItem = (PQUEUED_CALLBACK_ITEM) pCallbackHandle;
  139. ASSERT(pQueuedCallbackItem->Enqueued == 0);
  140. IoFreeWorkItem(pQueuedCallbackItem->IoWorkItem);
  141. ExFreePool(pQueuedCallbackItem);
  142. }
  143. VOID
  144. EnqueuedDpcCallback(
  145. IN PKDPC Dpc,
  146. IN PVOID DeferredContext,
  147. IN PVOID SystemArgument1,
  148. IN PVOID SystemArgument2
  149. )
  150. {
  151. PQUEUED_CALLBACK_ITEM pQueuedCallbackItem;
  152. QUEUED_CALLBACK_RETURN returnValue;
  153. NTSTATUS ntStatus;
  154. pQueuedCallbackItem = (PQUEUED_CALLBACK_ITEM) DeferredContext;
  155. if (InterlockedExchange(&pQueuedCallbackItem->Enqueued, 0) == 1) {
  156. returnValue = pQueuedCallbackItem->QueuedCallback(
  157. pQueuedCallbackItem->DeviceObject,
  158. pQueuedCallbackItem->Context
  159. );
  160. } else {
  161. returnValue = QUEUED_CALLBACK_RETAIN;
  162. }
  163. switch(returnValue) {
  164. case QUEUED_CALLBACK_FREE:
  165. CallbackFree((PVOID) pQueuedCallbackItem);
  166. break;
  167. case QUEUED_CALLBACK_RETAIN:
  168. //
  169. // Nothing to do in this case, in fact we don't dare touch anything
  170. // in the structure lest it be already freed.
  171. //
  172. break;
  173. case QUEUED_CALLBACK_REISSUE:
  174. //
  175. // Re-enqueue it with the same handle to avoid reallocation.
  176. //
  177. ntStatus = CallbackEnqueue(
  178. (PVOID *) &pQueuedCallbackItem,
  179. pQueuedCallbackItem->QueuedCallback,
  180. pQueuedCallbackItem->DeviceObject,
  181. pQueuedCallbackItem->Context,
  182. pQueuedCallbackItem->Irql,
  183. pQueuedCallbackItem->Flags | EQCF_REUSE_HANDLE
  184. );
  185. ASSERT(NT_SUCCESS(ntStatus));
  186. break;
  187. default:
  188. ASSERT(0);
  189. break;
  190. }
  191. }
  192. #pragma code_seg("PAGE")
  193. VOID
  194. EnqueuedIoWorkItemCallback(
  195. IN PDEVICE_OBJECT DeviceObject,
  196. IN PVOID Context
  197. )
  198. {
  199. PQUEUED_CALLBACK_ITEM pQueuedCallbackItem;
  200. QUEUED_CALLBACK_RETURN returnValue;
  201. NTSTATUS ntStatus;
  202. PAGED_CODE();
  203. pQueuedCallbackItem = (PQUEUED_CALLBACK_ITEM) Context;
  204. ASSERT(pQueuedCallbackItem->DeviceObject == DeviceObject);
  205. if (InterlockedExchange(&pQueuedCallbackItem->Enqueued, 0) == 1) {
  206. returnValue = pQueuedCallbackItem->QueuedCallback(
  207. pQueuedCallbackItem->DeviceObject,
  208. pQueuedCallbackItem->Context
  209. );
  210. } else {
  211. returnValue = QUEUED_CALLBACK_RETAIN;
  212. }
  213. switch(returnValue) {
  214. case QUEUED_CALLBACK_FREE:
  215. CallbackFree((PVOID) pQueuedCallbackItem);
  216. break;
  217. case QUEUED_CALLBACK_RETAIN:
  218. //
  219. // Nothing to do in this case, in fact we don't dare touch anything
  220. // in the structure lest it be already freed.
  221. //
  222. break;
  223. case QUEUED_CALLBACK_REISSUE:
  224. //
  225. // Re-enqueue it with the same handle to avoid reallocation.
  226. //
  227. ntStatus = CallbackEnqueue(
  228. (PVOID *) &pQueuedCallbackItem,
  229. pQueuedCallbackItem->QueuedCallback,
  230. pQueuedCallbackItem->DeviceObject,
  231. pQueuedCallbackItem->Context,
  232. pQueuedCallbackItem->Irql,
  233. pQueuedCallbackItem->Flags | EQCF_REUSE_HANDLE
  234. );
  235. ASSERT(NT_SUCCESS(ntStatus));
  236. break;
  237. default:
  238. ASSERT(0);
  239. break;
  240. }
  241. }