ReactOS 0.4.15-dev-5667-ged97270
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
60extern "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
69typedef 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 */
84typedef 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 */
113typedef VOID
114(NTAPI IO_CSQ_INSERT_IRP)(
115 _In_ struct _IO_CSQ *Csq,
117typedef 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 */
131typedef VOID
132(NTAPI IO_CSQ_REMOVE_IRP)(
133 _In_ struct _IO_CSQ *Csq,
134 _In_ PIRP Irp);
135typedef 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 */
156typedef PIRP
157(NTAPI IO_CSQ_PEEK_NEXT_IRP)(
158 _In_ struct _IO_CSQ *Csq,
161typedef 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 */
176typedef VOID
177(NTAPI IO_CSQ_ACQUIRE_LOCK)(
178 _In_ struct _IO_CSQ *Csq,
180typedef 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 */
192typedef VOID
193(NTAPI IO_CSQ_RELEASE_LOCK)(
194 _In_ struct _IO_CSQ *Csq,
195 _In_ KIRQL Irql);
196typedef 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 */
213typedef VOID
214(NTAPI IO_CSQ_COMPLETE_CANCELED_IRP)(
215 _In_ struct _IO_CSQ *Csq,
216 _In_ PIRP Irp);
217typedef IO_CSQ_COMPLETE_CANCELED_IRP *PIO_CSQ_COMPLETE_CANCELED_IRP;
218
219/*
220 * IO_CSQ - Queue control structure
221 */
222typedef 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 */
254typedef NTSTATUS
255(NTAPI IO_CSQ_INSERT_IRP_EX)(
256 _In_ struct _IO_CSQ *Csq,
257 _In_ PIRP Irp,
259typedef 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 */
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 */
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
struct _IRP * PIRP
#define VOID
Definition: acefi.h:82
LONG NTSTATUS
Definition: precomp.h:26
struct _IO_CSQ_IRP_CONTEXT * PIO_CSQ_IRP_CONTEXT
struct _IO_CSQ IO_CSQ
Definition: csq.h:69
IO_CSQ_ACQUIRE_LOCK * PIO_CSQ_ACQUIRE_LOCK
Definition: csq.h:180
IO_CSQ_RELEASE_LOCK * PIO_CSQ_RELEASE_LOCK
Definition: csq.h:196
_In_ PIRP Irp
Definition: csq.h:116
IO_CSQ_INSERT_IRP * PIO_CSQ_INSERT_IRP
Definition: csq.h:117
_In_ PIRP _In_ PVOID InsertContext
Definition: csq.h:258
IO_CSQ_PEEK_NEXT_IRP * PIO_CSQ_PEEK_NEXT_IRP
Definition: csq.h:161
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
_In_opt_ PIRP _In_opt_ PVOID PeekContext
Definition: csq.h:160
struct _IO_CSQ * PIO_CSQ
Definition: csq.h:69
IO_CSQ_COMPLETE_CANCELED_IRP * PIO_CSQ_COMPLETE_CANCELED_IRP
Definition: csq.h:217
_Out_ PKIRQL Irql
Definition: csq.h:179
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
struct _IO_CSQ_IRP_CONTEXT IO_CSQ_IRP_CONTEXT
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
IO_CSQ_INSERT_IRP_EX * PIO_CSQ_INSERT_IRP_EX
Definition: csq.h:259
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
NTKERNELAPI PIRP NTAPI IoCsqRemoveNextIrp(_Inout_ PIO_CSQ Csq, _In_opt_ PVOID PeekContext)
IoCsqRemoveNextIrp - Removes the next IRP from the queue.
Definition: csq.c:398
NTKERNELAPI PIRP NTAPI IoCsqRemoveIrp(_Inout_ PIO_CSQ Csq, _Inout_ PIO_CSQ_IRP_CONTEXT Context)
Remove anb IRP from the queue.
Definition: csq.c:326
IO_CSQ_REMOVE_IRP * PIO_CSQ_REMOVE_IRP
Definition: csq.h:135
IO_CSQ Csq
Definition: csqrtns.c:46
NTSTATUS NTAPI CsqInsertIrpEx(PIO_CSQ Csq, PIRP Irp, PVOID InsertContext)
Definition: csqtest.c:82
#define NTSTATUS
Definition: precomp.h:20
UCHAR KIRQL
Definition: env_spec_w32.h:591
KIRQL * PKIRQL
Definition: env_spec_w32.h:592
#define _Out_opt_
Definition: ms_sal.h:346
#define _Inout_
Definition: ms_sal.h:378
#define _Out_
Definition: ms_sal.h:345
#define _In_
Definition: ms_sal.h:308
#define _In_opt_
Definition: ms_sal.h:309
PIO_CSQ Csq
Definition: csq.h:87
ULONG Type
Definition: csq.h:85
Definition: csq.h:222
PIO_CSQ_RELEASE_LOCK CsqReleaseLock
Definition: csq.h:228
PIO_CSQ_ACQUIRE_LOCK CsqAcquireLock
Definition: csq.h:227
PVOID ReservePointer
Definition: csq.h:230
PIO_CSQ_COMPLETE_CANCELED_IRP CsqCompleteCanceledIrp
Definition: csq.h:229
PIO_CSQ_REMOVE_IRP CsqRemoveIrp
Definition: csq.h:225
ULONG Type
Definition: csq.h:223
PIO_CSQ_PEEK_NEXT_IRP CsqPeekNextIrp
Definition: csq.h:226
PIO_CSQ_INSERT_IRP CsqInsertIrp
Definition: csq.h:224
#define NTAPI
Definition: typedefs.h:36
uint32_t ULONG
Definition: typedefs.h:59
#define NTKERNELAPI
_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:1893
_In_ PIO_CSQ_INSERT_IRP CsqInsertIrp
Definition: iofuncs.h:1888
_In_ PIO_CSQ_INSERT_IRP _In_ PIO_CSQ_REMOVE_IRP _In_ PIO_CSQ_PEEK_NEXT_IRP CsqPeekNextIrp
Definition: iofuncs.h:1890
_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:1891
_In_ PIO_CSQ_INSERT_IRP _In_ PIO_CSQ_REMOVE_IRP CsqRemoveIrp
Definition: iofuncs.h:1889
_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:1892
IO_CSQ_ACQUIRE_LOCK * PIO_CSQ_ACQUIRE_LOCK
Definition: iotypes.h:2910
IO_CSQ_RELEASE_LOCK * PIO_CSQ_RELEASE_LOCK
Definition: iotypes.h:2916
IO_CSQ_INSERT_IRP * PIO_CSQ_INSERT_IRP
Definition: iotypes.h:2884
IO_CSQ_PEEK_NEXT_IRP * PIO_CSQ_PEEK_NEXT_IRP
Definition: iotypes.h:2904
IO_CSQ_COMPLETE_CANCELED_IRP * PIO_CSQ_COMPLETE_CANCELED_IRP
Definition: iotypes.h:2922
IO_CSQ_REMOVE_IRP * PIO_CSQ_REMOVE_IRP
Definition: iotypes.h:2897