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.

251 lines
6.7 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. csq.h
  5. Abstract:
  6. This header exposes the cancel safe queue DDIs for use on Win2K at later.
  7. Drivers that use this header should link to csq.lib. If a driver only needs
  8. to work on XP or later, neither this header or the lib are required (the
  9. XP kernel supports the cancel safe queue DDIs natively.)
  10. Author:
  11. Nar Ganapathy (narg) 1-Jan-1999
  12. Revision History:
  13. --*/
  14. // Cancel SAFE DDI set start
  15. //
  16. // The following DDIs are to help ease the pain of writing queue packages that
  17. // handle the cancellation race well. The idea of this set of DDIs is to not
  18. // force a single queue data structure but allow the cancel logic to be hidden
  19. // from the drivers. A driver implements a queue and as part of its header
  20. // includes the IO_CSQ structure. In its initialization routine it calls
  21. // IoInitializeCsq. Then in the dispatch routine when the driver wants to
  22. // insert an IRP into the queue it calls IoCsqInsertIrp. When the driver wants
  23. // to remove something from the queue it calls IoCsqRemoveIrp. Note that Insert
  24. // can fail if the IRP was cancelled in the meantime. Remove can also fail if
  25. // the IRP was already cancelled.
  26. //
  27. // There are typically two modes where drivers queue IRPs. These two modes are
  28. // covered by the cancel safe queue DDI set.
  29. //
  30. // Mode 1:
  31. // One is where the driver queues the IRP and at some later
  32. // point in time dequeues an IRP and issues the IO request.
  33. // For this mode the driver should use IoCsqInsertIrp and IoCsqRemoveNextIrp.
  34. // The driver in this case is expected to pass NULL to the irp context
  35. // parameter in IoInsertIrp.
  36. //
  37. // Mode 2:
  38. // In this the driver queues theIRP, issues the IO request (like issuing a DMA
  39. // request or writing to a register) and when the IO request completes (either
  40. // using a DPC or timer) the driver dequeues the IRP and completes it. For this
  41. // mode the driver should use IoCsqInsertIrp and IoCsqRemoveIrp. In this case
  42. // the driver should allocate an IRP context and pass it in to IoCsqInsertIrp.
  43. // The cancel DDI code creates an association between the IRP and the context
  44. // and thus ensures that when the time comes to remove the IRP it can ascertain
  45. // correctly.
  46. //
  47. // Note that the cancel DDI set assumes that the field DriverContext[3] is
  48. // always available for use and that the driver does not use it.
  49. //
  50. #ifndef _CSQ_H_
  51. #define _CSQ_H_
  52. #pragma once
  53. #ifdef __cplusplus
  54. extern "C" {
  55. #endif
  56. //
  57. // If the wdm.h/ntddk.h we're including already defines cancel safe DDIs, we
  58. // can skip the structure definitions. Otherwise, we do the rest here:
  59. //
  60. #ifndef IO_TYPE_CSQ_IRP_CONTEXT
  61. //
  62. // Bookkeeping structure. This should be opaque to drivers.
  63. // Drivers typically include this as part of their queue headers.
  64. // Given a CSQ pointer the driver should be able to get its
  65. // queue header using CONTAINING_RECORD macro
  66. //
  67. typedef struct _IO_CSQ IO_CSQ, *PIO_CSQ;
  68. #define IO_TYPE_CSQ_IRP_CONTEXT 1
  69. #define IO_TYPE_CSQ 2
  70. //
  71. // IRP context structure. This structure is necessary if the driver is using
  72. // the second mode.
  73. //
  74. typedef struct _IO_CSQ_IRP_CONTEXT {
  75. ULONG Type;
  76. PIRP Irp;
  77. PIO_CSQ Csq;
  78. } IO_CSQ_IRP_CONTEXT, *PIO_CSQ_IRP_CONTEXT;
  79. //
  80. // Routines that insert/remove IRP
  81. //
  82. typedef VOID
  83. (*PIO_CSQ_INSERT_IRP)(
  84. IN struct _IO_CSQ *Csq,
  85. IN PIRP Irp
  86. );
  87. typedef VOID
  88. (*PIO_CSQ_REMOVE_IRP)(
  89. IN PIO_CSQ Csq,
  90. IN PIRP Irp
  91. );
  92. //
  93. // Retrieves next entry after Irp from the queue.
  94. // Returns NULL if there are no entries in the queue.
  95. // If Irp is NUL, returns the entry in the head of the queue.
  96. // This routine does not remove the IRP from the queue.
  97. //
  98. typedef PIRP
  99. (*PIO_CSQ_PEEK_NEXT_IRP)(
  100. IN PIO_CSQ Csq,
  101. IN PIRP Irp,
  102. IN PVOID PeekContext
  103. );
  104. //
  105. // Lock routine that protects the cancel safe queue.
  106. //
  107. typedef VOID
  108. (*PIO_CSQ_ACQUIRE_LOCK)(
  109. IN PIO_CSQ Csq,
  110. OUT PKIRQL Irql
  111. );
  112. typedef VOID
  113. (*PIO_CSQ_RELEASE_LOCK)(
  114. IN PIO_CSQ Csq,
  115. IN KIRQL Irql
  116. );
  117. //
  118. // Completes the IRP with STATUS_CANCELLED. IRP is guaranteed to be valid
  119. // In most cases this routine just calls IoCompleteRequest(Irp, STATUS_CANCELLED);
  120. //
  121. typedef VOID
  122. (*PIO_CSQ_COMPLETE_CANCELED_IRP)(
  123. IN PIO_CSQ Csq,
  124. IN PIRP Irp
  125. );
  126. //
  127. // Bookkeeping structure. This should be opaque to drivers.
  128. // Drivers typically include this as part of their queue headers.
  129. // Given a CSQ pointer the driver should be able to get its
  130. // queue header using CONTAINING_RECORD macro
  131. //
  132. typedef struct _IO_CSQ {
  133. ULONG Type;
  134. PIO_CSQ_INSERT_IRP CsqInsertIrp;
  135. PIO_CSQ_REMOVE_IRP CsqRemoveIrp;
  136. PIO_CSQ_PEEK_NEXT_IRP CsqPeekNextIrp;
  137. PIO_CSQ_ACQUIRE_LOCK CsqAcquireLock;
  138. PIO_CSQ_RELEASE_LOCK CsqReleaseLock;
  139. PIO_CSQ_COMPLETE_CANCELED_IRP CsqCompleteCanceledIrp;
  140. PVOID ReservePointer; // Future expansion
  141. } IO_CSQ, *PIO_CSQ;
  142. #endif // IO_TYPE_CSQ_IRP_CONTEXT
  143. //
  144. // These defines ensure the backward compatible CSQ library can be used within
  145. // the XP build environment in which the kernel supports the functions natively.
  146. //
  147. #define CSQLIB_DDI(x) Wdmlib##x
  148. #undef IoCsqInitialize
  149. #undef IoCsqInsertIrp
  150. #undef IoCsqRemoveNextIrp
  151. #undef IoCsqRemoveIrp
  152. #define IoCsqInitialize WdmlibIoCsqInitialize
  153. #define IoCsqInsertIrp WdmlibIoCsqInsertIrp
  154. #define IoCsqRemoveNextIrp WdmlibIoCsqRemoveNextIrp
  155. #define IoCsqRemoveIrp WdmlibIoCsqRemoveIrp
  156. //
  157. // Initializes the cancel queue structure.
  158. //
  159. NTSTATUS
  160. CSQLIB_DDI(IoCsqInitialize)(
  161. IN PIO_CSQ Csq,
  162. IN PIO_CSQ_INSERT_IRP CsqInsertIrp,
  163. IN PIO_CSQ_REMOVE_IRP CsqRemoveIrp,
  164. IN PIO_CSQ_PEEK_NEXT_IRP CsqPeekNextIrp,
  165. IN PIO_CSQ_ACQUIRE_LOCK CsqAcquireLock,
  166. IN PIO_CSQ_RELEASE_LOCK CsqReleaseLock,
  167. IN PIO_CSQ_COMPLETE_CANCELED_IRP CsqCompleteCanceledIrp
  168. );
  169. //
  170. // The caller calls this routine to insert the IRP and return STATUS_PENDING.
  171. //
  172. VOID
  173. CSQLIB_DDI(IoCsqInsertIrp)(
  174. IN PIO_CSQ Csq,
  175. IN PIRP Irp,
  176. IN PIO_CSQ_IRP_CONTEXT Context
  177. );
  178. //
  179. // Returns an IRP if one can be found. NULL otherwise.
  180. //
  181. PIRP
  182. CSQLIB_DDI(IoCsqRemoveNextIrp)(
  183. IN PIO_CSQ Csq,
  184. IN PVOID PeekContext
  185. );
  186. //
  187. // This routine is called from timeout or DPCs.
  188. // The context is presumably part of the DPC or timer context.
  189. // If succesfull returns the IRP associated with context.
  190. //
  191. PIRP
  192. CSQLIB_DDI(IoCsqRemoveIrp)(
  193. IN PIO_CSQ Csq,
  194. IN PIO_CSQ_IRP_CONTEXT Context
  195. );
  196. #ifdef __cplusplus
  197. } // extern "C"
  198. #endif
  199. #endif // _CSQ_H_
  200. // Cancel SAFE DDI set end