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