csq.h 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. /*
  2. * Cancel-Safe Queue Library
  3. * Created in 2004 by Vizzini (vizzini@plasmic.com)
  4. *
  5. * THIS SOFTWARE IS NOT COPYRIGHTED
  6. *
  7. * This source code is offered for use in the public domain. You may
  8. * use, modify or distribute it freely.
  9. *
  10. * This code is distributed in the hope that it will be useful but
  11. * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
  12. * DISCLAIMED. This includes but is not limited to warranties of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  14. *
  15. *
  16. * This header defines the interface to the ReactOS Cancel-Safe Queue library.
  17. * This interface is based on and is similar to the Microsoft Cancel-Safe
  18. * Queue interface.
  19. *
  20. * BACKGROUND
  21. *
  22. * IRP queuing is a royal pain in the butt, due to the fact that there are
  23. * tons of built-in race conditions. IRP handling is difficult in general,
  24. * but the cancel logic has been particularly complicated due to some subtle
  25. * races, coupled with the fact that the system interfaces have changed over
  26. * time.
  27. *
  28. * Walter Oney (2nd. Ed. of Programming the Windows Driver Model) states a
  29. * common opinion among driver developers when he says that it is foolish
  30. * to try to roll your own cancel logic. There are only a very few people
  31. * who have gotten it right in the past. He suggests, instead, that you
  32. * either use his own well-tested code, or use the code in the Microsoft
  33. * Cancel-Safe Queue Library.
  34. *
  35. * We cannot do either, of course, due to copyright issues. I have therefore
  36. * created this clone of the Microsoft library in order to concentrate all
  37. * of the IRP-queuing bugs in one place. I'm quite sure there are problems
  38. * here, so if you are a driver writer, I'd be glad to hear your feedback.
  39. *
  40. * Apart from that, please try to use these routines, rather than building
  41. * your own. If you think you have found a bug, please bring it up with me
  42. * or on-list, as this is complicated and non-obvious stuff. Don't just
  43. * change this and hope for the best!
  44. *
  45. * USAGE
  46. *
  47. * This library follows exactly the same interface as the Microsoft Cancel-Safe
  48. * Queue routines (IoCsqXxx()). As such, the authoritative reference is the
  49. * current DDK. There is also a DDK sample called "cancel" that has an
  50. * example of how to use this code. I have also provided a sample driver
  51. * that makes use of this queue. Finally, please do read the header and the
  52. * source if you're curious about the inner workings of these routines.
  53. */
  54. #pragma once
  55. #define _CSQ_H_
  56. #ifdef __cplusplus
  57. extern "C" {
  58. #endif
  59. /*
  60. * Prevent including the CSQ definitions twice. They're present in NTDDK
  61. * now too, except the *_EX versions.
  62. */
  63. #ifndef IO_TYPE_CSQ_IRP_CONTEXT
  64. typedef struct _IO_CSQ IO_CSQ, *PIO_CSQ;
  65. /*
  66. * STRUCTURES
  67. *
  68. * NOTE: Please do not use these directly. You will make incompatible code
  69. * if you do. Always only use the documented IoCsqXxx() interfaces and you
  70. * will amass much Good Karma.
  71. */
  72. #define IO_TYPE_CSQ_IRP_CONTEXT 1
  73. #define IO_TYPE_CSQ 2
  74. /*
  75. * IO_CSQ_IRP_CONTEXT - Context used to track an IRP in the CSQ
  76. */
  77. typedef struct _IO_CSQ_IRP_CONTEXT {
  78. ULONG Type;
  79. PIRP Irp;
  80. PIO_CSQ Csq;
  81. } IO_CSQ_IRP_CONTEXT, *PIO_CSQ_IRP_CONTEXT;
  82. /*
  83. * CSQ Callbacks
  84. *
  85. * The cancel-safe queue is implemented as a set of IoCsqXxx() OS routines
  86. * copuled with a set of driver callbacks to handle the basic operations of
  87. * the queue. You need to supply one of each of these functions in your own
  88. * driver. These routines are also documented in the DDK under CsqXxx().
  89. * That is the authoritative documentation.
  90. */
  91. /*
  92. * Function to insert an IRP in the queue. No need to worry about locking;
  93. * just tack it onto your list or something.
  94. *
  95. * Sample implementation:
  96. *
  97. VOID NTAPI CsqInsertIrp(PIO_CSQ Csq, PIRP Irp)
  98. {
  99. KdPrint(("Inserting IRP 0x%x into CSQ\n", Irp));
  100. InsertTailList(&IrpQueue, &Irp->Tail.Overlay.ListEntry);
  101. }
  102. *
  103. */
  104. typedef VOID
  105. (NTAPI IO_CSQ_INSERT_IRP)(
  106. IN struct _IO_CSQ *Csq,
  107. IN PIRP Irp);
  108. typedef IO_CSQ_INSERT_IRP *PIO_CSQ_INSERT_IRP;
  109. /*
  110. * Function to remove an IRP from the queue.
  111. *
  112. * Sample:
  113. *
  114. VOID NTAPI CsqRemoveIrp(PIO_CSQ Csq, PIRP Irp)
  115. {
  116. KdPrint(("Removing IRP 0x%x from CSQ\n", Irp));
  117. RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
  118. }
  119. *
  120. */
  121. typedef VOID
  122. (NTAPI IO_CSQ_REMOVE_IRP)(
  123. IN struct _IO_CSQ *Csq,
  124. IN PIRP Irp);
  125. typedef IO_CSQ_REMOVE_IRP *PIO_CSQ_REMOVE_IRP;
  126. /*
  127. * Function to look for an IRP in the queue
  128. *
  129. * Sample:
  130. *
  131. PIRP NTAPI CsqPeekNextIrp(PIO_CSQ Csq, PIRP Irp, PVOID PeekContext)
  132. {
  133. KdPrint(("Peeking for next IRP\n"));
  134. if(Irp)
  135. return CONTAINING_RECORD(&Irp->Tail.Overlay.ListEntry.Flink, IRP, Tail.Overlay.ListEntry);
  136. if(IsListEmpty(&IrpQueue))
  137. return NULL;
  138. return CONTAINING_RECORD(IrpQueue.Flink, IRP, Tail.Overlay.ListEntry);
  139. }
  140. *
  141. */
  142. typedef PIRP
  143. (NTAPI IO_CSQ_PEEK_NEXT_IRP)(
  144. IN struct _IO_CSQ *Csq,
  145. IN PIRP Irp,
  146. IN PVOID PeekContext);
  147. typedef IO_CSQ_PEEK_NEXT_IRP *PIO_CSQ_PEEK_NEXT_IRP;
  148. /*
  149. * Lock the queue. This can be a spinlock, a mutex, or whatever
  150. * else floats your boat.
  151. *
  152. * Sample:
  153. *
  154. VOID NTAPI CsqAcquireLock(PIO_CSQ Csq, PKIRQL Irql)
  155. {
  156. KdPrint(("Acquiring spin lock\n"));
  157. KeAcquireSpinLock(&IrpQueueLock, Irql);
  158. }
  159. *
  160. */
  161. typedef VOID
  162. (NTAPI IO_CSQ_ACQUIRE_LOCK)(
  163. IN struct _IO_CSQ *Csq,
  164. OUT PKIRQL Irql);
  165. typedef IO_CSQ_ACQUIRE_LOCK *PIO_CSQ_ACQUIRE_LOCK;
  166. /*
  167. * Unlock the queue:
  168. *
  169. VOID NTAPI CsqReleaseLock(PIO_CSQ Csq, KIRQL Irql)
  170. {
  171. KdPrint(("Releasing spin lock\n"));
  172. KeReleaseSpinLock(&IrpQueueLock, Irql);
  173. }
  174. *
  175. */
  176. typedef VOID
  177. (NTAPI IO_CSQ_RELEASE_LOCK)(
  178. IN struct _IO_CSQ *Csq,
  179. IN KIRQL Irql);
  180. typedef IO_CSQ_RELEASE_LOCK *PIO_CSQ_RELEASE_LOCK;
  181. /*
  182. * Finally, this is called by the queue library when it wants to complete
  183. * a canceled IRP.
  184. *
  185. * Sample:
  186. *
  187. VOID NTAPI CsqCompleteCancelledIrp(PIO_CSQ Csq, PIRP Irp)
  188. {
  189. KdPrint(("cancelling irp 0x%x\n", Irp));
  190. Irp->IoStatus.Status = STATUS_CANCELLED;
  191. Irp->IoStatus.Information = 0;
  192. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  193. }
  194. *
  195. */
  196. typedef VOID
  197. (NTAPI IO_CSQ_COMPLETE_CANCELED_IRP)(
  198. IN struct _IO_CSQ *Csq,
  199. IN PIRP Irp);
  200. typedef IO_CSQ_COMPLETE_CANCELED_IRP *PIO_CSQ_COMPLETE_CANCELED_IRP;
  201. /*
  202. * IO_CSQ - Queue control structure
  203. */
  204. typedef struct _IO_CSQ {
  205. ULONG Type;
  206. PIO_CSQ_INSERT_IRP CsqInsertIrp;
  207. PIO_CSQ_REMOVE_IRP CsqRemoveIrp;
  208. PIO_CSQ_PEEK_NEXT_IRP CsqPeekNextIrp;
  209. PIO_CSQ_ACQUIRE_LOCK CsqAcquireLock;
  210. PIO_CSQ_RELEASE_LOCK CsqReleaseLock;
  211. PIO_CSQ_COMPLETE_CANCELED_IRP CsqCompleteCanceledIrp;
  212. PVOID ReservePointer; /* must be NULL */
  213. } IO_CSQ, *PIO_CSQ;
  214. #endif /* IO_TYPE_CSQ_IRP_CONTEXT */
  215. #ifndef IO_TYPE_CSQ_EX
  216. /* See IO_TYPE_CSQ_* above */
  217. #define IO_TYPE_CSQ_EX 3
  218. /*
  219. * Function to insert an IRP into the queue with extended context information.
  220. * This is useful if you need to be able to de-queue particular IRPs more
  221. * easily in some cases.
  222. *
  223. * Same deal as above; sample implementation:
  224. *
  225. NTSTATUS NTAPI CsqInsertIrpEx(PIO_CSQ Csq, PIRP Irp, PVOID InsertContext)
  226. {
  227. CsqInsertIrp(Csq, Irp);
  228. return STATUS_PENDING;
  229. }
  230. *
  231. */
  232. typedef NTSTATUS
  233. (NTAPI IO_CSQ_INSERT_IRP_EX)(
  234. IN struct _IO_CSQ *Csq,
  235. IN PIRP Irp,
  236. IN PVOID InsertContext);
  237. typedef IO_CSQ_INSERT_IRP_EX *PIO_CSQ_INSERT_IRP_EX;
  238. #endif /* IO_TYPE_CSQ_EX */
  239. /*
  240. * CANCEL-SAFE QUEUE DDIs
  241. *
  242. * These device driver interfaces are called to make use of the queue. Again,
  243. * authoritative documentation for these functions is in the DDK. The csqtest
  244. * driver also makes use of some of them.
  245. */
  246. /*
  247. * Call this in DriverEntry or similar in order to set up the Csq structure.
  248. * As long as the Csq struct and the functions you pass in are resident,
  249. * there are no IRQL restrictions.
  250. */
  251. NTKERNELAPI
  252. NTSTATUS NTAPI IoCsqInitialize(PIO_CSQ Csq,
  253. PIO_CSQ_INSERT_IRP CsqInsertIrp,
  254. PIO_CSQ_REMOVE_IRP CsqRemoveIrp,
  255. PIO_CSQ_PEEK_NEXT_IRP CsqPeekNextIrp,
  256. PIO_CSQ_ACQUIRE_LOCK CsqAcquireLock,
  257. PIO_CSQ_RELEASE_LOCK CsqReleaseLock,
  258. PIO_CSQ_COMPLETE_CANCELED_IRP CsqCompleteCanceledIrp);
  259. /*
  260. * Same as above, except you provide a CsqInsertIrpEx routine instead of
  261. * CsqInsertIrp. This eventually allows you to supply extra tracking
  262. * information for use with the queue.
  263. */
  264. NTKERNELAPI
  265. NTSTATUS NTAPI IoCsqInitializeEx(PIO_CSQ Csq,
  266. PIO_CSQ_INSERT_IRP_EX CsqInsertIrpEx,
  267. PIO_CSQ_REMOVE_IRP CsqRemoveIrp,
  268. PIO_CSQ_PEEK_NEXT_IRP CsqPeekNextIrp,
  269. PIO_CSQ_ACQUIRE_LOCK CsqAcquireLock,
  270. PIO_CSQ_RELEASE_LOCK CsqReleaseLock,
  271. PIO_CSQ_COMPLETE_CANCELED_IRP CsqCompleteCanceledIrp);
  272. /*
  273. * Insert an IRP into the queue
  274. */
  275. NTKERNELAPI
  276. VOID NTAPI IoCsqInsertIrp(PIO_CSQ Csq,
  277. PIRP Irp,
  278. PIO_CSQ_IRP_CONTEXT Context);
  279. /*
  280. * Insert an IRP into the queue, with special context maintained that
  281. * makes it easy to find IRPs in the queue
  282. */
  283. NTKERNELAPI
  284. NTSTATUS NTAPI IoCsqInsertIrpEx(PIO_CSQ Csq,
  285. PIRP Irp,
  286. PIO_CSQ_IRP_CONTEXT Context,
  287. PVOID InsertContext);
  288. /*
  289. * Remove a particular IRP from the queue
  290. */
  291. NTKERNELAPI
  292. PIRP NTAPI IoCsqRemoveIrp(PIO_CSQ Csq,
  293. PIO_CSQ_IRP_CONTEXT Context);
  294. /*
  295. * Remove the next IRP from the queue
  296. */
  297. NTKERNELAPI
  298. PIRP NTAPI IoCsqRemoveNextIrp(PIO_CSQ Csq,
  299. PVOID PeekContext);
  300. #ifdef __cplusplus
  301. }
  302. #endif