merge ROS Shell without integrated explorer part into trunk
[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
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 struct _IO_CSQ;
49
50
51 /*
52 * CSQ Callbacks
53 *
54 * The cancel-safe queue is implemented as a set of IoCsqXxx() OS routines
55 * copuled with a set of driver callbacks to handle the basic operations of
56 * the queue. You need to supply one of each of these functions in your own
57 * driver. These routines are also documented in the DDK under CsqXxx().
58 * That is the authoritative documentation.
59 */
60
61 /*
62 * Function to insert an IRP in the queue. No need to worry about locking;
63 * just tack it onto your list or something.
64 *
65 * Sample implementation:
66 *
67 VOID NTAPI CsqInsertIrp(PIO_CSQ Csq, PIRP Irp)
68 {
69 KdPrint(("Inserting IRP 0x%x into CSQ\n", Irp));
70 InsertTailList(&IrpQueue, &Irp->Tail.Overlay.ListEntry);
71 }
72 *
73 */
74 typedef VOID (NTAPI *PIO_CSQ_INSERT_IRP) (struct _IO_CSQ *Csq,
75 PIRP Irp);
76
77
78 /*
79 * Function to insert an IRP into the queue with extended context information.
80 * This is useful if you need to be able to de-queue particular IRPs more
81 * easily in some cases.
82 *
83 * Same deal as above; sample implementation:
84 *
85 NTSTATUS NTAPI CsqInsertIrpEx(PIO_CSQ Csq, PIRP Irp, PVOID InsertContext)
86 {
87 CsqInsertIrp(Csq, Irp);
88 return STATUS_PENDING;
89 }
90 *
91 */
92 typedef NTSTATUS (NTAPI *PIO_CSQ_INSERT_IRP_EX) (struct _IO_CSQ *Csq,
93 PIRP Irp,
94 PVOID InsertContext);
95
96 /*
97 * Function to remove an IRP from the queue.
98 *
99 * Sample:
100 *
101 VOID NTAPI CsqRemoveIrp(PIO_CSQ Csq, PIRP Irp)
102 {
103 KdPrint(("Removing IRP 0x%x from CSQ\n", Irp));
104 RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
105 }
106 *
107 */
108 typedef VOID (NTAPI *PIO_CSQ_REMOVE_IRP) (struct _IO_CSQ *Csq,
109 PIRP Irp);
110
111 /*
112 * Function to look for an IRP in the queue
113 *
114 * Sample:
115 *
116 PIRP NTAPI CsqPeekNextIrp(PIO_CSQ Csq, PIRP Irp, PVOID PeekContext)
117 {
118 KdPrint(("Peeking for next IRP\n"));
119
120 if(Irp)
121 return CONTAINING_RECORD(&Irp->Tail.Overlay.ListEntry.Flink, IRP, Tail.Overlay.ListEntry);
122
123 if(IsListEmpty(&IrpQueue))
124 return NULL;
125
126 return CONTAINING_RECORD(IrpQueue.Flink, IRP, Tail.Overlay.ListEntry);
127 }
128 *
129 */
130 typedef PIRP (NTAPI *PIO_CSQ_PEEK_NEXT_IRP) (struct _IO_CSQ *Csq,
131 PIRP Irp,
132 PVOID PeekContext);
133
134 /*
135 * Lock the queue. This can be a spinlock, a mutex, or whatever
136 * else floats your boat.
137 *
138 * Sample:
139 *
140 VOID NTAPI CsqAcquireLock(PIO_CSQ Csq, PKIRQL Irql)
141 {
142 KdPrint(("Acquiring spin lock\n"));
143 KeAcquireSpinLock(&IrpQueueLock, Irql);
144 }
145 *
146 */
147 typedef VOID (NTAPI *PIO_CSQ_ACQUIRE_LOCK) (struct _IO_CSQ *Csq,
148 PKIRQL Irql);
149
150 /*
151 * Unlock the queue:
152 *
153 VOID NTAPI CsqReleaseLock(PIO_CSQ Csq, KIRQL Irql)
154 {
155 KdPrint(("Releasing spin lock\n"));
156 KeReleaseSpinLock(&IrpQueueLock, Irql);
157 }
158 *
159 */
160 typedef VOID (NTAPI *PIO_CSQ_RELEASE_LOCK) (struct _IO_CSQ *Csq,
161 KIRQL Irql);
162
163 /*
164 * Finally, this is called by the queue library when it wants to complete
165 * a canceled IRP.
166 *
167 * Sample:
168 *
169 VOID NTAPI CsqCompleteCancelledIrp(PIO_CSQ Csq, PIRP Irp)
170 {
171 KdPrint(("cancelling irp 0x%x\n", Irp));
172 Irp->IoStatus.Status = STATUS_CANCELLED;
173 Irp->IoStatus.Information = 0;
174 IoCompleteRequest(Irp, IO_NO_INCREMENT);
175 }
176 *
177 */
178 typedef VOID (NTAPI *PIO_CSQ_COMPLETE_CANCELED_IRP) (struct _IO_CSQ *Csq,
179 PIRP Irp);
180
181
182 /*
183 * STRUCTURES
184 *
185 * NOTE: Please do not use these directly. You will make incompatible code
186 * if you do. Always only use the documented IoCsqXxx() interfaces and you
187 * will amass much Good Karma.
188 */
189 #define IO_TYPE_CSQ_IRP_CONTEXT 1
190 #define IO_TYPE_CSQ 2
191 #define IO_TYPE_CSQ_EX 3
192
193 /*
194 * IO_CSQ - Queue control structure
195 */
196 typedef struct _IO_CSQ {
197 ULONG Type;
198 PIO_CSQ_INSERT_IRP CsqInsertIrp;
199 PIO_CSQ_REMOVE_IRP CsqRemoveIrp;
200 PIO_CSQ_PEEK_NEXT_IRP CsqPeekNextIrp;
201 PIO_CSQ_ACQUIRE_LOCK CsqAcquireLock;
202 PIO_CSQ_RELEASE_LOCK CsqReleaseLock;
203 PIO_CSQ_COMPLETE_CANCELED_IRP CsqCompleteCanceledIrp;
204 PVOID ReservePointer; /* must be NULL */
205 } IO_CSQ, *PIO_CSQ;
206
207 /*
208 * IO_CSQ_IRP_CONTEXT - Context used to track an IRP in the CSQ
209 */
210 typedef struct _IO_CSQ_IRP_CONTEXT {
211 ULONG Type;
212 PIRP Irp;
213 PIO_CSQ Csq;
214 } IO_CSQ_IRP_CONTEXT, *PIO_CSQ_IRP_CONTEXT;
215
216
217 /*
218 * CANCEL-SAFE QUEUE DDIs
219 *
220 * These device driver interfaces are called to make use of the queue. Again,
221 * authoritative documentation for these functions is in the DDK. The csqtest
222 * driver also makes use of some of them.
223 */
224
225
226 /*
227 * Call this in DriverEntry or similar in order to set up the Csq structure.
228 * As long as the Csq struct and the functions you pass in are resident,
229 * there are no IRQL restrictions.
230 */
231 NTSTATUS NTAPI IoCsqInitialize(PIO_CSQ Csq,
232 PIO_CSQ_INSERT_IRP CsqInsertIrp,
233 PIO_CSQ_REMOVE_IRP CsqRemoveIrp,
234 PIO_CSQ_PEEK_NEXT_IRP CsqPeekNextIrp,
235 PIO_CSQ_ACQUIRE_LOCK CsqAcquireLock,
236 PIO_CSQ_RELEASE_LOCK CsqReleaseLock,
237 PIO_CSQ_COMPLETE_CANCELED_IRP CsqCompleteCanceledIrp);
238
239 /*
240 * Same as above, except you provide a CsqInsertIrpEx routine instead of
241 * CsqInsertIrp. This eventually allows you to supply extra tracking
242 * information for use with the queue.
243 */
244 NTSTATUS NTAPI IoCsqInitializeEx(PIO_CSQ Csq,
245 PIO_CSQ_INSERT_IRP_EX CsqInsertIrpEx,
246 PIO_CSQ_REMOVE_IRP CsqRemoveIrp,
247 PIO_CSQ_PEEK_NEXT_IRP CsqPeekNextIrp,
248 PIO_CSQ_ACQUIRE_LOCK CsqAcquireLock,
249 PIO_CSQ_RELEASE_LOCK CsqReleaseLock,
250 PIO_CSQ_COMPLETE_CANCELED_IRP CsqCompleteCanceledIrp);
251
252 /*
253 * Insert an IRP into the queue
254 */
255 VOID NTAPI IoCsqInsertIrp(PIO_CSQ Csq,
256 PIRP Irp,
257 PIO_CSQ_IRP_CONTEXT Context);
258
259 /*
260 * Insert an IRP into the queue, with special context maintained that
261 * makes it easy to find IRPs in the queue
262 */
263 NTSTATUS NTAPI IoCsqInsertIrpEx(PIO_CSQ Csq,
264 PIRP Irp,
265 PIO_CSQ_IRP_CONTEXT Context,
266 PVOID InsertContext);
267
268 /*
269 * Remove a particular IRP from the queue
270 */
271 PIRP NTAPI IoCsqRemoveIrp(PIO_CSQ Csq,
272 PIO_CSQ_IRP_CONTEXT Context);
273
274 /*
275 * Remove the next IRP from the queue
276 */
277 PIRP NTAPI IoCsqRemoveNextIrp(PIO_CSQ Csq,
278 PVOID PeekContext);
279
280 #endif /* _REACTOS_CSQ_H */