ReactOS  0.4.13-dev-249-gcba1a2f
csq.h
Go to the documentation of this file.
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 
55 #pragma once
56 
57 #define _CSQ_H_
58 
59 #ifdef __cplusplus
60 extern "C" {
61 #endif
62 
63 /*
64  * Prevent including the CSQ definitions twice. They're present in NTDDK
65  * now too, except the *_EX versions.
66  */
67 #ifndef IO_TYPE_CSQ_IRP_CONTEXT
68 
69 typedef struct _IO_CSQ IO_CSQ, *PIO_CSQ;
70 
71 /*
72  * STRUCTURES
73  *
74  * NOTE: Please do not use these directly. You will make incompatible code
75  * if you do. Always only use the documented IoCsqXxx() interfaces and you
76  * will amass much Good Karma.
77  */
78 #define IO_TYPE_CSQ_IRP_CONTEXT 1
79 #define IO_TYPE_CSQ 2
80 
81 /*
82  * IO_CSQ_IRP_CONTEXT - Context used to track an IRP in the CSQ
83  */
84 typedef struct _IO_CSQ_IRP_CONTEXT {
89 
90 /*
91  * CSQ Callbacks
92  *
93  * The cancel-safe queue is implemented as a set of IoCsqXxx() OS routines
94  * copuled with a set of driver callbacks to handle the basic operations of
95  * the queue. You need to supply one of each of these functions in your own
96  * driver. These routines are also documented in the DDK under CsqXxx().
97  * That is the authoritative documentation.
98  */
99 
100 /*
101  * Function to insert an IRP in the queue. No need to worry about locking;
102  * just tack it onto your list or something.
103  *
104  * Sample implementation:
105  *
106  VOID NTAPI CsqInsertIrp(PIO_CSQ Csq, PIRP Irp)
107  {
108  KdPrint(("Inserting IRP 0x%x into CSQ\n", Irp));
109  InsertTailList(&IrpQueue, &Irp->Tail.Overlay.ListEntry);
110  }
111  *
112  */
113 typedef VOID
114 (NTAPI IO_CSQ_INSERT_IRP)(
115  _In_ struct _IO_CSQ *Csq,
117 typedef IO_CSQ_INSERT_IRP *PIO_CSQ_INSERT_IRP;
118 
119 /*
120  * Function to remove an IRP from the queue.
121  *
122  * Sample:
123  *
124  VOID NTAPI CsqRemoveIrp(PIO_CSQ Csq, PIRP Irp)
125  {
126  KdPrint(("Removing IRP 0x%x from CSQ\n", Irp));
127  RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
128  }
129  *
130  */
131 typedef VOID
132 (NTAPI IO_CSQ_REMOVE_IRP)(
133  _In_ struct _IO_CSQ *Csq,
134  _In_ PIRP Irp);
135 typedef IO_CSQ_REMOVE_IRP *PIO_CSQ_REMOVE_IRP;
136 
137 /*
138  * Function to look for an IRP in the queue
139  *
140  * Sample:
141  *
142  PIRP NTAPI CsqPeekNextIrp(PIO_CSQ Csq, PIRP Irp, PVOID PeekContext)
143  {
144  KdPrint(("Peeking for next IRP\n"));
145 
146  if(Irp)
147  return CONTAINING_RECORD(&Irp->Tail.Overlay.ListEntry.Flink, IRP, Tail.Overlay.ListEntry);
148 
149  if(IsListEmpty(&IrpQueue))
150  return NULL;
151 
152  return CONTAINING_RECORD(IrpQueue.Flink, IRP, Tail.Overlay.ListEntry);
153  }
154  *
155  */
156 typedef PIRP
157 (NTAPI IO_CSQ_PEEK_NEXT_IRP)(
158  _In_ struct _IO_CSQ *Csq,
161 typedef IO_CSQ_PEEK_NEXT_IRP *PIO_CSQ_PEEK_NEXT_IRP;
162 
163 /*
164  * Lock the queue. This can be a spinlock, a mutex, or whatever
165  * else floats your boat.
166  *
167  * Sample:
168  *
169  VOID NTAPI CsqAcquireLock(PIO_CSQ Csq, PKIRQL Irql)
170  {
171  KdPrint(("Acquiring spin lock\n"));
172  KeAcquireSpinLock(&IrpQueueLock, Irql);
173  }
174  *
175  */
176 typedef VOID
177 (NTAPI IO_CSQ_ACQUIRE_LOCK)(
178  _In_ struct _IO_CSQ *Csq,
180 typedef IO_CSQ_ACQUIRE_LOCK *PIO_CSQ_ACQUIRE_LOCK;
181 
182 /*
183  * Unlock the queue:
184  *
185  VOID NTAPI CsqReleaseLock(PIO_CSQ Csq, KIRQL Irql)
186  {
187  KdPrint(("Releasing spin lock\n"));
188  KeReleaseSpinLock(&IrpQueueLock, Irql);
189  }
190  *
191  */
192 typedef VOID
193 (NTAPI IO_CSQ_RELEASE_LOCK)(
194  _In_ struct _IO_CSQ *Csq,
195  _In_ KIRQL Irql);
196 typedef IO_CSQ_RELEASE_LOCK *PIO_CSQ_RELEASE_LOCK;
197 
198 /*
199  * Finally, this is called by the queue library when it wants to complete
200  * a canceled IRP.
201  *
202  * Sample:
203  *
204  VOID NTAPI CsqCompleteCancelledIrp(PIO_CSQ Csq, PIRP Irp)
205  {
206  KdPrint(("cancelling irp 0x%x\n", Irp));
207  Irp->IoStatus.Status = STATUS_CANCELLED;
208  Irp->IoStatus.Information = 0;
209  IoCompleteRequest(Irp, IO_NO_INCREMENT);
210  }
211  *
212  */
213 typedef VOID
214 (NTAPI IO_CSQ_COMPLETE_CANCELED_IRP)(
215  _In_ struct _IO_CSQ *Csq,
216  _In_ PIRP Irp);
217 typedef IO_CSQ_COMPLETE_CANCELED_IRP *PIO_CSQ_COMPLETE_CANCELED_IRP;
218 
219 /*
220  * IO_CSQ - Queue control structure
221  */
222 typedef struct _IO_CSQ {
230  PVOID ReservePointer; /* must be NULL */
231 } IO_CSQ, *PIO_CSQ;
232 
233 #endif /* IO_TYPE_CSQ_IRP_CONTEXT */
234 
235 #ifndef IO_TYPE_CSQ_EX
236 
237 /* See IO_TYPE_CSQ_* above */
238 #define IO_TYPE_CSQ_EX 3
239 
240 /*
241  * Function to insert an IRP into the queue with extended context information.
242  * This is useful if you need to be able to de-queue particular IRPs more
243  * easily in some cases.
244  *
245  * Same deal as above; sample implementation:
246  *
247  NTSTATUS NTAPI CsqInsertIrpEx(PIO_CSQ Csq, PIRP Irp, PVOID InsertContext)
248  {
249  CsqInsertIrp(Csq, Irp);
250  return STATUS_PENDING;
251  }
252  *
253  */
254 typedef NTSTATUS
255 (NTAPI IO_CSQ_INSERT_IRP_EX)(
256  _In_ struct _IO_CSQ *Csq,
259 typedef IO_CSQ_INSERT_IRP_EX *PIO_CSQ_INSERT_IRP_EX;
260 
261 #endif /* IO_TYPE_CSQ_EX */
262 
263 /*
264  * CANCEL-SAFE QUEUE DDIs
265  *
266  * These device driver interfaces are called to make use of the queue. Again,
267  * authoritative documentation for these functions is in the DDK. The csqtest
268  * driver also makes use of some of them.
269  */
270 
271 
272 /*
273  * Call this in DriverEntry or similar in order to set up the Csq structure.
274  * As long as the Csq struct and the functions you pass in are resident,
275  * there are no IRQL restrictions.
276  */
285 
286 /*
287  * Same as above, except you provide a CsqInsertIrpEx routine instead of
288  * CsqInsertIrp. This eventually allows you to supply extra tracking
289  * information for use with the queue.
290  */
299 
300 /*
301  * Insert an IRP into the queue
302  */
305  _Inout_ PIRP Irp,
307 
308 /*
309  * Insert an IRP into the queue, with special context maintained that
310  * makes it easy to find IRPs in the queue
311  */
314  _Inout_ PIRP Irp,
317 
318 /*
319  * Remove a particular IRP from the queue
320  */
324 
325 /*
326  * Remove the next IRP from the queue
327  */
331 
332 #ifdef __cplusplus
333 }
334 #endif
_In_ PIO_CSQ_INSERT_IRP CsqInsertIrp
Definition: iofuncs.h:1884
PIO_CSQ Csq
Definition: csq.h:87
PIO_CSQ_ACQUIRE_LOCK CsqAcquireLock
Definition: csq.h:227
NTKERNELAPI PIRP NTAPI IoCsqRemoveNextIrp(_Inout_ PIO_CSQ Csq, _In_opt_ PVOID PeekContext)
IoCsqRemoveNextIrp - Removes the next IRP from the queue.
Definition: csq.c:398
_In_ PIRP Irp
Definition: csq.h:116
IO_CSQ_REMOVE_IRP * PIO_CSQ_REMOVE_IRP
Definition: csq.h:135
NTKERNELAPI VOID NTAPI IoCsqInsertIrp(_Inout_ PIO_CSQ Csq, _Inout_ PIRP Irp, _Out_opt_ PIO_CSQ_IRP_CONTEXT Context)
Insert an IRP into the CSQ.
Definition: csq.c:177
typedef NTSTATUS(NTAPI IO_CSQ_INSERT_IRP_EX)(_In_ struct _IO_CSQ *Csq
LONG NTSTATUS
Definition: precomp.h:26
IO_CSQ_ACQUIRE_LOCK * PIO_CSQ_ACQUIRE_LOCK
Definition: csq.h:180
_In_ PIO_CSQ_INSERT_IRP _In_ PIO_CSQ_REMOVE_IRP _In_ PIO_CSQ_PEEK_NEXT_IRP _In_ PIO_CSQ_ACQUIRE_LOCK _In_ PIO_CSQ_RELEASE_LOCK CsqReleaseLock
Definition: iofuncs.h:1884
_Out_ PKIRQL Irql
Definition: csq.h:179
#define _In_opt_
Definition: no_sal2.h:213
UCHAR KIRQL
Definition: env_spec_w32.h:591
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
struct _IO_CSQ * PIO_CSQ
Definition: csq.h:69
PIO_CSQ_PEEK_NEXT_IRP CsqPeekNextIrp
Definition: csq.h:226
struct _IO_CSQ IO_CSQ
Definition: csq.h:69
struct _IO_CSQ_IRP_CONTEXT IO_CSQ_IRP_CONTEXT
ULONG Type
Definition: csq.h:223
#define _Out_
Definition: no_sal2.h:323
#define NTKERNELAPI
IO_CSQ_PEEK_NEXT_IRP * PIO_CSQ_PEEK_NEXT_IRP
Definition: csq.h:161
NTSTATUS NTAPI CsqInsertIrpEx(PIO_CSQ Csq, PIRP Irp, PVOID InsertContext)
Definition: csqtest.c:82
_In_ PIO_CSQ_INSERT_IRP _In_ PIO_CSQ_REMOVE_IRP _In_ PIO_CSQ_PEEK_NEXT_IRP CsqPeekNextIrp
Definition: iofuncs.h:1884
_In_ PIO_CSQ_INSERT_IRP _In_ PIO_CSQ_REMOVE_IRP CsqRemoveIrp
Definition: iofuncs.h:1884
_In_ PIRP _In_ PVOID InsertContext
Definition: csq.h:257
#define _Out_opt_
Definition: no_sal2.h:339
NTKERNELAPI NTSTATUS NTAPI IoCsqInitializeEx(_Out_ PIO_CSQ Csq, _In_ PIO_CSQ_INSERT_IRP_EX CsqInsertIrpEx, _In_ PIO_CSQ_REMOVE_IRP CsqRemoveIrp, _In_ PIO_CSQ_PEEK_NEXT_IRP CsqPeekNextIrp, _In_ PIO_CSQ_ACQUIRE_LOCK CsqAcquireLock, _In_ PIO_CSQ_RELEASE_LOCK CsqReleaseLock, _In_ PIO_CSQ_COMPLETE_CANCELED_IRP CsqCompleteCanceledIrp)
Set up a CSQ struct to initialize the queue (extended version)
Definition: csq.c:143
PIO_CSQ_REMOVE_IRP CsqRemoveIrp
Definition: csq.h:225
_In_ PIO_CSQ_INSERT_IRP _In_ PIO_CSQ_REMOVE_IRP _In_ PIO_CSQ_PEEK_NEXT_IRP _In_ PIO_CSQ_ACQUIRE_LOCK _In_ PIO_CSQ_RELEASE_LOCK _In_ PIO_CSQ_COMPLETE_CANCELED_IRP CsqCompleteCanceledIrp
Definition: iofuncs.h:1884
#define _Inout_
Definition: no_sal2.h:244
PVOID ReservePointer
Definition: csq.h:230
PIO_CSQ_INSERT_IRP CsqInsertIrp
Definition: csq.h:224
PIO_CSQ_RELEASE_LOCK CsqReleaseLock
Definition: csq.h:228
IO_CSQ_INSERT_IRP * PIO_CSQ_INSERT_IRP
Definition: csq.h:117
KIRQL * PKIRQL
Definition: env_spec_w32.h:592
PIO_CSQ_COMPLETE_CANCELED_IRP CsqCompleteCanceledIrp
Definition: csq.h:229
struct _IO_CSQ_IRP_CONTEXT * PIO_CSQ_IRP_CONTEXT
#define _In_
Definition: no_sal2.h:204
Definition: csq.h:222
NTKERNELAPI NTSTATUS NTAPI IoCsqInsertIrpEx(_Inout_ PIO_CSQ Csq, _Inout_ PIRP Irp, _Out_opt_ PIO_CSQ_IRP_CONTEXT Context, _In_opt_ PVOID InsertContext)
Insert an IRP into the CSQ, with additional tracking context.
Definition: csq.c:205
typedef VOID(NTAPI IO_CSQ_INSERT_IRP)(_In_ struct _IO_CSQ *Csq
IO_CSQ_RELEASE_LOCK * PIO_CSQ_RELEASE_LOCK
Definition: csq.h:196
_In_opt_ PIRP _In_opt_ PVOID PeekContext
Definition: csq.h:159
IO_CSQ Csq
Definition: csqrtns.c:46
IO_CSQ_INSERT_IRP_EX * PIO_CSQ_INSERT_IRP_EX
Definition: csq.h:259
unsigned int ULONG
Definition: retypes.h:1
NTKERNELAPI NTSTATUS NTAPI IoCsqInitialize(_Out_ PIO_CSQ Csq, _In_ PIO_CSQ_INSERT_IRP CsqInsertIrp, _In_ PIO_CSQ_REMOVE_IRP CsqRemoveIrp, _In_ PIO_CSQ_PEEK_NEXT_IRP CsqPeekNextIrp, _In_ PIO_CSQ_ACQUIRE_LOCK CsqAcquireLock, _In_ PIO_CSQ_RELEASE_LOCK CsqReleaseLock, _In_ PIO_CSQ_COMPLETE_CANCELED_IRP CsqCompleteCanceledIrp)
Set up a CSQ struct to initialize the queue.
Definition: csq.c:103
IO_CSQ_COMPLETE_CANCELED_IRP * PIO_CSQ_COMPLETE_CANCELED_IRP
Definition: csq.h:217
ULONG Type
Definition: csq.h:85
_In_ PIO_CSQ_INSERT_IRP _In_ PIO_CSQ_REMOVE_IRP _In_ PIO_CSQ_PEEK_NEXT_IRP _In_ PIO_CSQ_ACQUIRE_LOCK CsqAcquireLock
Definition: iofuncs.h:1884
typedef PIRP(NTAPI IO_CSQ_PEEK_NEXT_IRP)(_In_ struct _IO_CSQ *Csq
NTKERNELAPI PIRP NTAPI IoCsqRemoveIrp(_Inout_ PIO_CSQ Csq, _Inout_ PIO_CSQ_IRP_CONTEXT Context)
Remove anb IRP from the queue.
Definition: csq.c:326