Revert r46466 this time for real
[reactos.git] / reactos / include / ddk / csq.h
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 #ifndef _REACTOS_CSQ_H
56 #define _REACTOS_CSQ_H
57
58 /*
59 * Prevent including the CSQ definitions twice. They're present in NTDDK
60 * now too, except the *_EX versions.
61 */
62 #ifndef IO_TYPE_CSQ_IRP_CONTEXT
63
64 struct _IO_CSQ;
65
66
67 /*
68 * CSQ Callbacks
69 *
70 * The cancel-safe queue is implemented as a set of IoCsqXxx() OS routines
71 * copuled with a set of driver callbacks to handle the basic operations of
72 * the queue. You need to supply one of each of these functions in your own
73 * driver. These routines are also documented in the DDK under CsqXxx().
74 * That is the authoritative documentation.
75 */
76
77 /*
78 * Function to insert an IRP in the queue. No need to worry about locking;
79 * just tack it onto your list or something.
80 *
81 * Sample implementation:
82 *
83 VOID NTAPI CsqInsertIrp(PIO_CSQ Csq, PIRP Irp)
84 {
85 KdPrint(("Inserting IRP 0x%x into CSQ\n", Irp));
86 InsertTailList(&IrpQueue, &Irp->Tail.Overlay.ListEntry);
87 }
88 *
89 */
90 typedef VOID (NTAPI *PIO_CSQ_INSERT_IRP) (struct _IO_CSQ *Csq,
91 PIRP Irp);
92
93
94 /*
95 * Function to remove an IRP from the queue.
96 *
97 * Sample:
98 *
99 VOID NTAPI CsqRemoveIrp(PIO_CSQ Csq, PIRP Irp)
100 {
101 KdPrint(("Removing IRP 0x%x from CSQ\n", Irp));
102 RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
103 }
104 *
105 */
106 typedef VOID (NTAPI *PIO_CSQ_REMOVE_IRP) (struct _IO_CSQ *Csq,
107 PIRP Irp);
108
109 /*
110 * Function to look for an IRP in the queue
111 *
112 * Sample:
113 *
114 PIRP NTAPI CsqPeekNextIrp(PIO_CSQ Csq, PIRP Irp, PVOID PeekContext)
115 {
116 KdPrint(("Peeking for next IRP\n"));
117
118 if(Irp)
119 return CONTAINING_RECORD(&Irp->Tail.Overlay.ListEntry.Flink, IRP, Tail.Overlay.ListEntry);
120
121 if(IsListEmpty(&IrpQueue))
122 return NULL;
123
124 return CONTAINING_RECORD(IrpQueue.Flink, IRP, Tail.Overlay.ListEntry);
125 }
126 *
127 */
128 typedef PIRP (NTAPI *PIO_CSQ_PEEK_NEXT_IRP) (struct _IO_CSQ *Csq,
129 PIRP Irp,
130 PVOID PeekContext);
131
132 /*
133 * Lock the queue. This can be a spinlock, a mutex, or whatever
134 * else floats your boat.
135 *
136 * Sample:
137 *
138 VOID NTAPI CsqAcquireLock(PIO_CSQ Csq, PKIRQL Irql)
139 {
140 KdPrint(("Acquiring spin lock\n"));
141 KeAcquireSpinLock(&IrpQueueLock, Irql);
142 }
143 *
144 */
145 typedef VOID (NTAPI *PIO_CSQ_ACQUIRE_LOCK) (struct _IO_CSQ *Csq,
146 PKIRQL Irql);
147
148 /*
149 * Unlock the queue:
150 *
151 VOID NTAPI CsqReleaseLock(PIO_CSQ Csq, KIRQL Irql)
152 {
153 KdPrint(("Releasing spin lock\n"));
154 KeReleaseSpinLock(&IrpQueueLock, Irql);
155 }
156 *
157 */
158 typedef VOID (NTAPI *PIO_CSQ_RELEASE_LOCK) (struct _IO_CSQ *Csq,
159 KIRQL Irql);
160
161 /*
162 * Finally, this is called by the queue library when it wants to complete
163 * a canceled IRP.
164 *
165 * Sample:
166 *
167 VOID NTAPI CsqCompleteCancelledIrp(PIO_CSQ Csq, PIRP Irp)
168 {
169 KdPrint(("cancelling irp 0x%x\n", Irp));
170 Irp->IoStatus.Status = STATUS_CANCELLED;
171 Irp->IoStatus.Information = 0;
172 IoCompleteRequest(Irp, IO_NO_INCREMENT);
173 }
174 *
175 */
176 typedef VOID (NTAPI *PIO_CSQ_COMPLETE_CANCELED_IRP) (struct _IO_CSQ *Csq,
177 PIRP Irp);
178
179
180 /*
181 * STRUCTURES
182 *
183 * NOTE: Please do not use these directly. You will make incompatible code
184 * if you do. Always only use the documented IoCsqXxx() interfaces and you
185 * will amass much Good Karma.
186 */
187 #define IO_TYPE_CSQ_IRP_CONTEXT 1
188 #define IO_TYPE_CSQ 2
189
190 /*
191 * IO_CSQ - Queue control structure
192 */
193 typedef struct _IO_CSQ {
194 ULONG Type;
195 PIO_CSQ_INSERT_IRP CsqInsertIrp;
196 PIO_CSQ_REMOVE_IRP CsqRemoveIrp;
197 PIO_CSQ_PEEK_NEXT_IRP CsqPeekNextIrp;
198 PIO_CSQ_ACQUIRE_LOCK CsqAcquireLock;
199 PIO_CSQ_RELEASE_LOCK CsqReleaseLock;
200 PIO_CSQ_COMPLETE_CANCELED_IRP CsqCompleteCanceledIrp;
201 PVOID ReservePointer; /* must be NULL */
202 } IO_CSQ, *PIO_CSQ;
203
204 /*
205 * IO_CSQ_IRP_CONTEXT - Context used to track an IRP in the CSQ
206 */
207 typedef struct _IO_CSQ_IRP_CONTEXT {
208 ULONG Type;
209 PIRP Irp;
210 PIO_CSQ Csq;
211 } IO_CSQ_IRP_CONTEXT, *PIO_CSQ_IRP_CONTEXT;
212
213 #endif /* IO_TYPE_CSQ_IRP_CONTEXT */
214
215 /* See IO_TYPE_CSQ_* above */
216 #define IO_TYPE_CSQ_EX 3
217
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 (NTAPI *PIO_CSQ_INSERT_IRP_EX) (struct _IO_CSQ *Csq,
233 PIRP Irp,
234 PVOID InsertContext);
235
236 /*
237 * CANCEL-SAFE QUEUE DDIs
238 *
239 * These device driver interfaces are called to make use of the queue. Again,
240 * authoritative documentation for these functions is in the DDK. The csqtest
241 * driver also makes use of some of them.
242 */
243
244
245 /*
246 * Call this in DriverEntry or similar in order to set up the Csq structure.
247 * As long as the Csq struct and the functions you pass in are resident,
248 * there are no IRQL restrictions.
249 */
250 NTKERNELAPI
251 NTSTATUS NTAPI IoCsqInitialize(PIO_CSQ Csq,
252 PIO_CSQ_INSERT_IRP CsqInsertIrp,
253 PIO_CSQ_REMOVE_IRP CsqRemoveIrp,
254 PIO_CSQ_PEEK_NEXT_IRP CsqPeekNextIrp,
255 PIO_CSQ_ACQUIRE_LOCK CsqAcquireLock,
256 PIO_CSQ_RELEASE_LOCK CsqReleaseLock,
257 PIO_CSQ_COMPLETE_CANCELED_IRP CsqCompleteCanceledIrp);
258
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 /*
274 * Insert an IRP into the queue
275 */
276 NTKERNELAPI
277 VOID NTAPI IoCsqInsertIrp(PIO_CSQ Csq,
278 PIRP Irp,
279 PIO_CSQ_IRP_CONTEXT Context);
280
281 /*
282 * Insert an IRP into the queue, with special context maintained that
283 * makes it easy to find IRPs in the queue
284 */
285 NTKERNELAPI
286 NTSTATUS NTAPI IoCsqInsertIrpEx(PIO_CSQ Csq,
287 PIRP Irp,
288 PIO_CSQ_IRP_CONTEXT Context,
289 PVOID InsertContext);
290
291 /*
292 * Remove a particular IRP from the queue
293 */
294 NTKERNELAPI
295 PIRP NTAPI IoCsqRemoveIrp(PIO_CSQ Csq,
296 PIO_CSQ_IRP_CONTEXT Context);
297
298 /*
299 * Remove the next IRP from the queue
300 */
301 NTKERNELAPI
302 PIRP NTAPI IoCsqRemoveNextIrp(PIO_CSQ Csq,
303 PVOID PeekContext);
304
305 #endif /* _REACTOS_CSQ_H */