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.

386 lines
8.4 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. complete.c
  5. Abstract:
  6. This module contains the Completion handling code for SPUD.
  7. Author:
  8. John Ballard (jballard) 11-Nov-1996
  9. Revision History:
  10. Keith Moore (keithmo) 04-Feb-1998
  11. Cleanup, added much needed comments.
  12. --*/
  13. #include "spudp.h"
  14. //
  15. // Private prototypes.
  16. //
  17. VOID
  18. SpudpCompleteRequest(
  19. IN PKAPC Apc,
  20. IN PKNORMAL_ROUTINE *NormalRoutine,
  21. IN PVOID *NormalContext,
  22. IN PVOID *SystemArgument1,
  23. IN PVOID *SystemArgument2
  24. );
  25. VOID
  26. SpudpNormalApcRoutine(
  27. IN PVOID NormalContext,
  28. IN PVOID SystemArgument1,
  29. IN PVOID SystemArgument2
  30. );
  31. VOID
  32. SpudpRundownRoutine(
  33. IN PKAPC Apc
  34. );
  35. #ifdef ALLOC_PRAGMA
  36. #pragma alloc_text( PAGE, SpudpCompleteRequest )
  37. #pragma alloc_text( PAGE, SpudpNormalApcRoutine )
  38. #pragma alloc_text( PAGE, SpudpRundownRoutine )
  39. #endif
  40. #if 0
  41. NOT PAGEABLE -- SpudCompleteRequest
  42. #endif
  43. //
  44. // Public functions.
  45. //
  46. VOID
  47. SpudCompleteRequest(
  48. IN PSPUD_AFD_REQ_CONTEXT SpudReqContext
  49. )
  50. /*++
  51. Routine Description:
  52. Common completion routine for XxxAndRecv IRPs.
  53. Arguments:
  54. SpudReqContext - The request context associated with the request
  55. to be completed.
  56. Return Value:
  57. None.
  58. --*/
  59. {
  60. PIRP irp;
  61. PETHREAD thread;
  62. PFILE_OBJECT fileObject;
  63. //
  64. // Snag the IRP from the request context, clear the MDL from the
  65. // IRP so IO won't chock. (The MDL is also stored in the request
  66. // context and will be freed in the APC below.)
  67. //
  68. irp = SpudReqContext->Irp;
  69. irp->MdlAddress = NULL;
  70. //
  71. // Snag the target thread and file object from the IRP. The APC
  72. // will be queued against the target thread, and the file object
  73. // will be a parameter to the APC.
  74. //
  75. thread = irp->Tail.Overlay.Thread;
  76. fileObject = irp->Tail.Overlay.OriginalFileObject;
  77. //
  78. // We must pass in a non-NULL function pointer for the NormalRoutine
  79. // parameter to KeInitializeApc(). This is necessary to keep the APC
  80. // a "normal" kernel APC. If we were to pass a NULL NormalRoutine, then
  81. // this would become a "special" APC that could not be blocked via the
  82. // KeEnterCriticalRegion() and KeLeaveCriticalRegion() functions.
  83. //
  84. KeInitializeApc(
  85. &irp->Tail.Apc, // Apc
  86. (PKTHREAD)&thread, // Thread
  87. irp->ApcEnvironment, // Environment
  88. SpudpCompleteRequest, // KernelRoutine
  89. SpudpRundownRoutine, // RundownRoutine
  90. SpudpNormalApcRoutine, // NormalRoutine
  91. KernelMode, // ProcessorMode
  92. NULL // NormalContext
  93. );
  94. KeInsertQueueApc(
  95. &irp->Tail.Apc, // Apc
  96. SpudReqContext, // SystemArgument1
  97. fileObject, // SystemArgument2
  98. SPUD_PRIORITY_BOOST // Increment
  99. );
  100. } // SpudCompleteRequest
  101. //
  102. // Private functions.
  103. //
  104. //
  105. // PREFIX Bug 57653. No way do we want to mess with this. This is
  106. // not on a path that we should be executing based on an initial
  107. // look and the likelyhood of mucking this up with any changes is
  108. // quite high.
  109. //
  110. /* #pragma INTRINSA suppress=all */
  111. VOID
  112. SpudpCompleteRequest(
  113. IN PKAPC Apc,
  114. IN PKNORMAL_ROUTINE *NormalRoutine,
  115. IN PVOID *NormalContext,
  116. IN PVOID *SystemArgument1,
  117. IN PVOID *SystemArgument2
  118. )
  119. /*++
  120. Routine Description:
  121. Kernel APC for SPUD IO completion. This routine is responsible for
  122. writing any final status back to the user-mode code, then signalling
  123. the completion port.
  124. Arguments:
  125. Apc - The APC that is firing. Since we always use the APC embedded in
  126. the IRP, we can use this pointer to get back to the completing IRP.
  127. NormalRoutine - Indirect pointer to the normal APC routine. We'll use
  128. this to "short circuit" normal routine invocation.
  129. NormalContext - Indirect pointer to the normal APC routine context
  130. (unused).
  131. SystemArgument1 - Actually an indirect pointer to the SPUD request
  132. context.
  133. SystemArgument2 - Actually an indirect pointer to the file object
  134. that's being completed.
  135. Return Value:
  136. None.
  137. --*/
  138. {
  139. PSPUD_AFD_REQ_CONTEXT SpudReqContext;
  140. PSPUD_REQ_CONTEXT reqContext;
  141. PIRP irp;
  142. PFILE_OBJECT fileObject;
  143. //
  144. // Sanity check.
  145. //
  146. PAGED_CODE();
  147. #if DBG
  148. if( KeAreApcsDisabled() ) {
  149. DbgPrint(
  150. "SPUD: Thread %08lx has non-zero APC disable\n",
  151. KeGetCurrentThread()
  152. );
  153. KeBugCheckEx(
  154. 0xbaadf00d,
  155. (ULONG_PTR)KeGetCurrentThread(),
  156. 0x77,
  157. (ULONG_PTR)*SystemArgument1,
  158. (ULONG_PTR)*SystemArgument2
  159. );
  160. }
  161. #endif // DBG
  162. //
  163. // Setting *NormalRoutine to NULL tells the kernel to not
  164. // dispatch the normal APC routine.
  165. //
  166. *NormalRoutine = NULL;
  167. UNREFERENCED_PARAMETER( NormalContext );
  168. //
  169. // Snag the IRP from the APC pointer, then retrieve our parameters
  170. // from the SystemArgument pointers.
  171. //
  172. irp = CONTAINING_RECORD( Apc, IRP, Tail.Apc );
  173. SpudReqContext = *SystemArgument1;
  174. fileObject = *SystemArgument2;
  175. reqContext = SpudReqContext->AtqContext;
  176. //
  177. // We're done with the file object.
  178. //
  179. TRACE_OB_DEREFERENCE( fileObject );
  180. ObDereferenceObject( fileObject );
  181. //
  182. // Try to write the final completion status back to the user-mode
  183. // buffer.
  184. //
  185. try {
  186. reqContext->IoStatus1 = SpudReqContext->IoStatus1;
  187. reqContext->IoStatus2 = SpudReqContext->IoStatus2;
  188. reqContext->KernelReqInfo = SPUD_INVALID_REQ_HANDLE;
  189. } except( EXCEPTION_EXECUTE_HANDLER ) {
  190. //
  191. // There's nothing we can do here other than drop the request
  192. // on the floor. We cannot return the exception code to the
  193. // user-mode code. This is OK, as the application will itself
  194. // throw an exception when it tries to touch the request context.
  195. //
  196. }
  197. //
  198. // Cleanup the request context.
  199. //
  200. SpudFreeRequestContext( SpudReqContext );
  201. //
  202. // Post the IRP to the I/O completion port.
  203. //
  204. irp->Tail.CompletionKey = reqContext;
  205. irp->Tail.Overlay.CurrentStackLocation = NULL;
  206. irp->IoStatus.Status = 0;
  207. irp->IoStatus.Information = 0xffffffff;
  208. irp->Overlay.AsynchronousParameters.UserApcContext = NULL;
  209. IopDequeueThreadIrp( irp );
  210. KeInsertQueue(
  211. (PKQUEUE)SpudCompletionPort,
  212. &irp->Tail.Overlay.ListEntry
  213. );
  214. SpudDereferenceCompletionPort();
  215. } // SpudpCompleteRequest
  216. VOID
  217. SpudpNormalApcRoutine(
  218. IN PVOID NormalContext,
  219. IN PVOID SystemArgument1,
  220. IN PVOID SystemArgument2
  221. )
  222. /*++
  223. Routine Description:
  224. "Normal" APC routine for our completion APC. This should never be
  225. invoked.
  226. Arguments:
  227. NormalContext - Unused.
  228. SystemArgument1 - Unused.
  229. SystemArgument2 - Unused.
  230. Return Value:
  231. None.
  232. --*/
  233. {
  234. //
  235. // This routine should never be called. The "*NormalRoutine = NULL"
  236. // line in SpudpCompleteRequest() prevents the kernel from invoking
  237. // this routine.
  238. //
  239. ASSERT( FALSE );
  240. UNREFERENCED_PARAMETER( NormalContext );
  241. UNREFERENCED_PARAMETER( SystemArgument1 );
  242. UNREFERENCED_PARAMETER( SystemArgument2 );
  243. } // SpudpNormalApcRoutine
  244. VOID
  245. SpudpRundownRoutine(
  246. IN PKAPC Apc
  247. )
  248. /*++
  249. Routine Description:
  250. Rundown routine invoked if our APC got queued to a thread, but the
  251. thread terminated before the APC could be delivered.
  252. Arguments:
  253. Apc - The orphaned APC.
  254. Return Value:
  255. None.
  256. --*/
  257. {
  258. PKNORMAL_ROUTINE normalRoutine;
  259. PVOID normalContext;
  260. PVOID systemArgument1;
  261. PVOID systemArgument2;
  262. //
  263. // This routine is invoked by the kernel if an APC is in a thread's
  264. // queue when the thread terminates. We'll just call through to the
  265. // "real" APC routine and let it do its thang (we still want to
  266. // post the request to the completion port, free resources, etc).
  267. //
  268. normalRoutine = Apc->NormalRoutine;
  269. normalContext = Apc->NormalContext;
  270. systemArgument1 = Apc->SystemArgument1;
  271. systemArgument2 = Apc->SystemArgument2;
  272. SpudpCompleteRequest(
  273. Apc,
  274. &normalRoutine,
  275. &normalContext,
  276. &systemArgument1,
  277. &systemArgument2
  278. );
  279. } // SpudpRundownRoutine