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