Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygencsq.h
Go to the documentation of this file.
00001 /* 00002 * Cancel-Safe Queue Library 00003 * Created in 2004 by Vizzini (vizzini@plasmic.com) 00004 * 00005 * THIS SOFTWARE IS NOT COPYRIGHTED 00006 * 00007 * This source code is offered for use in the public domain. You may 00008 * use, modify or distribute it freely. 00009 * 00010 * This code is distributed in the hope that it will be useful but 00011 * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY 00012 * DISCLAIMED. This includes but is not limited to warranties of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00014 * 00015 * 00016 * This header defines the interface to the ReactOS Cancel-Safe Queue library. 00017 * This interface is based on and is similar to the Microsoft Cancel-Safe 00018 * Queue interface. 00019 * 00020 * BACKGROUND 00021 * 00022 * IRP queuing is a royal pain in the butt, due to the fact that there are 00023 * tons of built-in race conditions. IRP handling is difficult in general, 00024 * but the cancel logic has been particularly complicated due to some subtle 00025 * races, coupled with the fact that the system interfaces have changed over 00026 * time. 00027 * 00028 * Walter Oney (2nd. Ed. of Programming the Windows Driver Model) states a 00029 * common opinion among driver developers when he says that it is foolish 00030 * to try to roll your own cancel logic. There are only a very few people 00031 * who have gotten it right in the past. He suggests, instead, that you 00032 * either use his own well-tested code, or use the code in the Microsoft 00033 * Cancel-Safe Queue Library. 00034 * 00035 * We cannot do either, of course, due to copyright issues. I have therefore 00036 * created this clone of the Microsoft library in order to concentrate all 00037 * of the IRP-queuing bugs in one place. I'm quite sure there are problems 00038 * here, so if you are a driver writer, I'd be glad to hear your feedback. 00039 * 00040 * Apart from that, please try to use these routines, rather than building 00041 * your own. If you think you have found a bug, please bring it up with me 00042 * or on-list, as this is complicated and non-obvious stuff. Don't just 00043 * change this and hope for the best! 00044 * 00045 * USAGE 00046 * 00047 * This library follows exactly the same interface as the Microsoft Cancel-Safe 00048 * Queue routines (IoCsqXxx()). As such, the authoritative reference is the 00049 * current DDK. There is also a DDK sample called "cancel" that has an 00050 * example of how to use this code. I have also provided a sample driver 00051 * that makes use of this queue. Finally, please do read the header and the 00052 * source if you're curious about the inner workings of these routines. 00053 */ 00054 00055 #pragma once 00056 00057 #define _CSQ_H_ 00058 00059 #ifdef __cplusplus 00060 extern "C" { 00061 #endif 00062 00063 /* 00064 * Prevent including the CSQ definitions twice. They're present in NTDDK 00065 * now too, except the *_EX versions. 00066 */ 00067 #ifndef IO_TYPE_CSQ_IRP_CONTEXT 00068 00069 typedef struct _IO_CSQ IO_CSQ, *PIO_CSQ; 00070 00071 /* 00072 * STRUCTURES 00073 * 00074 * NOTE: Please do not use these directly. You will make incompatible code 00075 * if you do. Always only use the documented IoCsqXxx() interfaces and you 00076 * will amass much Good Karma. 00077 */ 00078 #define IO_TYPE_CSQ_IRP_CONTEXT 1 00079 #define IO_TYPE_CSQ 2 00080 00081 /* 00082 * IO_CSQ_IRP_CONTEXT - Context used to track an IRP in the CSQ 00083 */ 00084 typedef struct _IO_CSQ_IRP_CONTEXT { 00085 ULONG Type; 00086 PIRP Irp; 00087 PIO_CSQ Csq; 00088 } IO_CSQ_IRP_CONTEXT, *PIO_CSQ_IRP_CONTEXT; 00089 00090 /* 00091 * CSQ Callbacks 00092 * 00093 * The cancel-safe queue is implemented as a set of IoCsqXxx() OS routines 00094 * copuled with a set of driver callbacks to handle the basic operations of 00095 * the queue. You need to supply one of each of these functions in your own 00096 * driver. These routines are also documented in the DDK under CsqXxx(). 00097 * That is the authoritative documentation. 00098 */ 00099 00100 /* 00101 * Function to insert an IRP in the queue. No need to worry about locking; 00102 * just tack it onto your list or something. 00103 * 00104 * Sample implementation: 00105 * 00106 VOID NTAPI CsqInsertIrp(PIO_CSQ Csq, PIRP Irp) 00107 { 00108 KdPrint(("Inserting IRP 0x%x into CSQ\n", Irp)); 00109 InsertTailList(&IrpQueue, &Irp->Tail.Overlay.ListEntry); 00110 } 00111 * 00112 */ 00113 typedef VOID 00114 (NTAPI IO_CSQ_INSERT_IRP)( 00115 _In_ struct _IO_CSQ *Csq, 00116 _In_ PIRP Irp); 00117 typedef IO_CSQ_INSERT_IRP *PIO_CSQ_INSERT_IRP; 00118 00119 /* 00120 * Function to remove an IRP from the queue. 00121 * 00122 * Sample: 00123 * 00124 VOID NTAPI CsqRemoveIrp(PIO_CSQ Csq, PIRP Irp) 00125 { 00126 KdPrint(("Removing IRP 0x%x from CSQ\n", Irp)); 00127 RemoveEntryList(&Irp->Tail.Overlay.ListEntry); 00128 } 00129 * 00130 */ 00131 typedef VOID 00132 (NTAPI IO_CSQ_REMOVE_IRP)( 00133 _In_ struct _IO_CSQ *Csq, 00134 _In_ PIRP Irp); 00135 typedef IO_CSQ_REMOVE_IRP *PIO_CSQ_REMOVE_IRP; 00136 00137 /* 00138 * Function to look for an IRP in the queue 00139 * 00140 * Sample: 00141 * 00142 PIRP NTAPI CsqPeekNextIrp(PIO_CSQ Csq, PIRP Irp, PVOID PeekContext) 00143 { 00144 KdPrint(("Peeking for next IRP\n")); 00145 00146 if(Irp) 00147 return CONTAINING_RECORD(&Irp->Tail.Overlay.ListEntry.Flink, IRP, Tail.Overlay.ListEntry); 00148 00149 if(IsListEmpty(&IrpQueue)) 00150 return NULL; 00151 00152 return CONTAINING_RECORD(IrpQueue.Flink, IRP, Tail.Overlay.ListEntry); 00153 } 00154 * 00155 */ 00156 typedef PIRP 00157 (NTAPI IO_CSQ_PEEK_NEXT_IRP)( 00158 _In_ struct _IO_CSQ *Csq, 00159 _In_opt_ PIRP Irp, 00160 _In_opt_ PVOID PeekContext); 00161 typedef IO_CSQ_PEEK_NEXT_IRP *PIO_CSQ_PEEK_NEXT_IRP; 00162 00163 /* 00164 * Lock the queue. This can be a spinlock, a mutex, or whatever 00165 * else floats your boat. 00166 * 00167 * Sample: 00168 * 00169 VOID NTAPI CsqAcquireLock(PIO_CSQ Csq, PKIRQL Irql) 00170 { 00171 KdPrint(("Acquiring spin lock\n")); 00172 KeAcquireSpinLock(&IrpQueueLock, Irql); 00173 } 00174 * 00175 */ 00176 typedef VOID 00177 (NTAPI IO_CSQ_ACQUIRE_LOCK)( 00178 _In_ struct _IO_CSQ *Csq, 00179 _Out_ PKIRQL Irql); 00180 typedef IO_CSQ_ACQUIRE_LOCK *PIO_CSQ_ACQUIRE_LOCK; 00181 00182 /* 00183 * Unlock the queue: 00184 * 00185 VOID NTAPI CsqReleaseLock(PIO_CSQ Csq, KIRQL Irql) 00186 { 00187 KdPrint(("Releasing spin lock\n")); 00188 KeReleaseSpinLock(&IrpQueueLock, Irql); 00189 } 00190 * 00191 */ 00192 typedef VOID 00193 (NTAPI IO_CSQ_RELEASE_LOCK)( 00194 _In_ struct _IO_CSQ *Csq, 00195 _In_ KIRQL Irql); 00196 typedef IO_CSQ_RELEASE_LOCK *PIO_CSQ_RELEASE_LOCK; 00197 00198 /* 00199 * Finally, this is called by the queue library when it wants to complete 00200 * a canceled IRP. 00201 * 00202 * Sample: 00203 * 00204 VOID NTAPI CsqCompleteCancelledIrp(PIO_CSQ Csq, PIRP Irp) 00205 { 00206 KdPrint(("cancelling irp 0x%x\n", Irp)); 00207 Irp->IoStatus.Status = STATUS_CANCELLED; 00208 Irp->IoStatus.Information = 0; 00209 IoCompleteRequest(Irp, IO_NO_INCREMENT); 00210 } 00211 * 00212 */ 00213 typedef VOID 00214 (NTAPI IO_CSQ_COMPLETE_CANCELED_IRP)( 00215 _In_ struct _IO_CSQ *Csq, 00216 _In_ PIRP Irp); 00217 typedef IO_CSQ_COMPLETE_CANCELED_IRP *PIO_CSQ_COMPLETE_CANCELED_IRP; 00218 00219 /* 00220 * IO_CSQ - Queue control structure 00221 */ 00222 typedef struct _IO_CSQ { 00223 ULONG Type; 00224 PIO_CSQ_INSERT_IRP CsqInsertIrp; 00225 PIO_CSQ_REMOVE_IRP CsqRemoveIrp; 00226 PIO_CSQ_PEEK_NEXT_IRP CsqPeekNextIrp; 00227 PIO_CSQ_ACQUIRE_LOCK CsqAcquireLock; 00228 PIO_CSQ_RELEASE_LOCK CsqReleaseLock; 00229 PIO_CSQ_COMPLETE_CANCELED_IRP CsqCompleteCanceledIrp; 00230 PVOID ReservePointer; /* must be NULL */ 00231 } IO_CSQ, *PIO_CSQ; 00232 00233 #endif /* IO_TYPE_CSQ_IRP_CONTEXT */ 00234 00235 #ifndef IO_TYPE_CSQ_EX 00236 00237 /* See IO_TYPE_CSQ_* above */ 00238 #define IO_TYPE_CSQ_EX 3 00239 00240 /* 00241 * Function to insert an IRP into the queue with extended context information. 00242 * This is useful if you need to be able to de-queue particular IRPs more 00243 * easily in some cases. 00244 * 00245 * Same deal as above; sample implementation: 00246 * 00247 NTSTATUS NTAPI CsqInsertIrpEx(PIO_CSQ Csq, PIRP Irp, PVOID InsertContext) 00248 { 00249 CsqInsertIrp(Csq, Irp); 00250 return STATUS_PENDING; 00251 } 00252 * 00253 */ 00254 typedef NTSTATUS 00255 (NTAPI IO_CSQ_INSERT_IRP_EX)( 00256 _In_ struct _IO_CSQ *Csq, 00257 _In_ PIRP Irp, 00258 _In_ PVOID InsertContext); 00259 typedef IO_CSQ_INSERT_IRP_EX *PIO_CSQ_INSERT_IRP_EX; 00260 00261 #endif /* IO_TYPE_CSQ_EX */ 00262 00263 /* 00264 * CANCEL-SAFE QUEUE DDIs 00265 * 00266 * These device driver interfaces are called to make use of the queue. Again, 00267 * authoritative documentation for these functions is in the DDK. The csqtest 00268 * driver also makes use of some of them. 00269 */ 00270 00271 00272 /* 00273 * Call this in DriverEntry or similar in order to set up the Csq structure. 00274 * As long as the Csq struct and the functions you pass in are resident, 00275 * there are no IRQL restrictions. 00276 */ 00277 NTKERNELAPI 00278 NTSTATUS NTAPI IoCsqInitialize(_Out_ PIO_CSQ Csq, 00279 _In_ PIO_CSQ_INSERT_IRP CsqInsertIrp, 00280 _In_ PIO_CSQ_REMOVE_IRP CsqRemoveIrp, 00281 _In_ PIO_CSQ_PEEK_NEXT_IRP CsqPeekNextIrp, 00282 _In_ PIO_CSQ_ACQUIRE_LOCK CsqAcquireLock, 00283 _In_ PIO_CSQ_RELEASE_LOCK CsqReleaseLock, 00284 _In_ PIO_CSQ_COMPLETE_CANCELED_IRP CsqCompleteCanceledIrp); 00285 00286 /* 00287 * Same as above, except you provide a CsqInsertIrpEx routine instead of 00288 * CsqInsertIrp. This eventually allows you to supply extra tracking 00289 * information for use with the queue. 00290 */ 00291 NTKERNELAPI 00292 NTSTATUS NTAPI IoCsqInitializeEx(_Out_ PIO_CSQ Csq, 00293 _In_ PIO_CSQ_INSERT_IRP_EX CsqInsertIrpEx, 00294 _In_ PIO_CSQ_REMOVE_IRP CsqRemoveIrp, 00295 _In_ PIO_CSQ_PEEK_NEXT_IRP CsqPeekNextIrp, 00296 _In_ PIO_CSQ_ACQUIRE_LOCK CsqAcquireLock, 00297 _In_ PIO_CSQ_RELEASE_LOCK CsqReleaseLock, 00298 _In_ PIO_CSQ_COMPLETE_CANCELED_IRP CsqCompleteCanceledIrp); 00299 00300 /* 00301 * Insert an IRP into the queue 00302 */ 00303 NTKERNELAPI 00304 VOID NTAPI IoCsqInsertIrp(_Inout_ PIO_CSQ Csq, 00305 _Inout_ PIRP Irp, 00306 _Out_opt_ PIO_CSQ_IRP_CONTEXT Context); 00307 00308 /* 00309 * Insert an IRP into the queue, with special context maintained that 00310 * makes it easy to find IRPs in the queue 00311 */ 00312 NTKERNELAPI 00313 NTSTATUS NTAPI IoCsqInsertIrpEx(_Inout_ PIO_CSQ Csq, 00314 _Inout_ PIRP Irp, 00315 _Out_opt_ PIO_CSQ_IRP_CONTEXT Context, 00316 _In_opt_ PVOID InsertContext); 00317 00318 /* 00319 * Remove a particular IRP from the queue 00320 */ 00321 NTKERNELAPI 00322 PIRP NTAPI IoCsqRemoveIrp(_Inout_ PIO_CSQ Csq, 00323 _Inout_ PIO_CSQ_IRP_CONTEXT Context); 00324 00325 /* 00326 * Remove the next IRP from the queue 00327 */ 00328 NTKERNELAPI 00329 PIRP NTAPI IoCsqRemoveNextIrp(_Inout_ PIO_CSQ Csq, 00330 _In_opt_ PVOID PeekContext); 00331 00332 #ifdef __cplusplus 00333 } 00334 #endif Generated on Fri May 25 2012 04:28:27 for ReactOS by
1.7.6.1
|