Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335/* * Cancel-Safe Queue Library * Created in 2004 by Vizzini (vizzini@plasmic.com) * * THIS SOFTWARE IS NOT COPYRIGHTED * * This source code is offered for use in the public domain. You may * use, modify or distribute it freely. * * This code is distributed in the hope that it will be useful but * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY * DISCLAIMED. This includes but is not limited to warranties of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * * This header defines the interface to the ReactOS Cancel-Safe Queue library. * This interface is based on and is similar to the Microsoft Cancel-Safe * Queue interface. * * BACKGROUND * * IRP queuing is a royal pain in the butt, due to the fact that there are * tons of built-in race conditions. IRP handling is difficult in general, * but the cancel logic has been particularly complicated due to some subtle * races, coupled with the fact that the system interfaces have changed over * time. * * Walter Oney (2nd. Ed. of Programming the Windows Driver Model) states a * common opinion among driver developers when he says that it is foolish * to try to roll your own cancel logic. There are only a very few people * who have gotten it right in the past. He suggests, instead, that you * either use his own well-tested code, or use the code in the Microsoft * Cancel-Safe Queue Library. * * We cannot do either, of course, due to copyright issues. I have therefore * created this clone of the Microsoft library in order to concentrate all * of the IRP-queuing bugs in one place. I'm quite sure there are problems * here, so if you are a driver writer, I'd be glad to hear your feedback. * * Apart from that, please try to use these routines, rather than building * your own. If you think you have found a bug, please bring it up with me * or on-list, as this is complicated and non-obvious stuff. Don't just * change this and hope for the best! * * USAGE * * This library follows exactly the same interface as the Microsoft Cancel-Safe * Queue routines (IoCsqXxx()). As such, the authoritative reference is the * current DDK. There is also a DDK sample called "cancel" that has an * example of how to use this code. I have also provided a sample driver * that makes use of this queue. Finally, please do read the header and the * source if you're curious about the inner workings of these routines. */
#pragma once
#define _CSQ_H_
#ifdef __cplusplusextern "C" {#endif
/* * Prevent including the CSQ definitions twice. They're present in NTDDK * now too, except the *_EX versions. */#ifndef IO_TYPE_CSQ_IRP_CONTEXT
typedef struct _IO_CSQ IO_CSQ, *PIO_CSQ;
/* * STRUCTURES * * NOTE: Please do not use these directly. You will make incompatible code * if you do. Always only use the documented IoCsqXxx() interfaces and you * will amass much Good Karma. */#define IO_TYPE_CSQ_IRP_CONTEXT 1#define IO_TYPE_CSQ 2
/* * IO_CSQ_IRP_CONTEXT - Context used to track an IRP in the CSQ */typedef struct _IO_CSQ_IRP_CONTEXT { ULONG Type; PIRP Irp; PIO_CSQ Csq;} IO_CSQ_IRP_CONTEXT, *PIO_CSQ_IRP_CONTEXT;
/* * CSQ Callbacks * * The cancel-safe queue is implemented as a set of IoCsqXxx() OS routines * copuled with a set of driver callbacks to handle the basic operations of * the queue. You need to supply one of each of these functions in your own * driver. These routines are also documented in the DDK under CsqXxx(). * That is the authoritative documentation. */
/* * Function to insert an IRP in the queue. No need to worry about locking; * just tack it onto your list or something. * * Sample implementation: * VOID NTAPI CsqInsertIrp(PIO_CSQ Csq, PIRP Irp) { KdPrint(("Inserting IRP 0x%x into CSQ\n", Irp)); InsertTailList(&IrpQueue, &Irp->Tail.Overlay.ListEntry); } * */typedef VOID(NTAPI IO_CSQ_INSERT_IRP)( _In_ struct _IO_CSQ *Csq, _In_ PIRP Irp);typedef IO_CSQ_INSERT_IRP *PIO_CSQ_INSERT_IRP;
/* * Function to remove an IRP from the queue. * * Sample: * VOID NTAPI CsqRemoveIrp(PIO_CSQ Csq, PIRP Irp) { KdPrint(("Removing IRP 0x%x from CSQ\n", Irp)); RemoveEntryList(&Irp->Tail.Overlay.ListEntry); } * */typedef VOID(NTAPI IO_CSQ_REMOVE_IRP)( _In_ struct _IO_CSQ *Csq, _In_ PIRP Irp);typedef IO_CSQ_REMOVE_IRP *PIO_CSQ_REMOVE_IRP;
/* * Function to look for an IRP in the queue * * Sample: * PIRP NTAPI CsqPeekNextIrp(PIO_CSQ Csq, PIRP Irp, PVOID PeekContext) { KdPrint(("Peeking for next IRP\n"));
if(Irp) return CONTAINING_RECORD(&Irp->Tail.Overlay.ListEntry.Flink, IRP, Tail.Overlay.ListEntry);
if(IsListEmpty(&IrpQueue)) return NULL;
return CONTAINING_RECORD(IrpQueue.Flink, IRP, Tail.Overlay.ListEntry); } * */typedef PIRP(NTAPI IO_CSQ_PEEK_NEXT_IRP)( _In_ struct _IO_CSQ *Csq, _In_opt_ PIRP Irp, _In_opt_ PVOID PeekContext);typedef IO_CSQ_PEEK_NEXT_IRP *PIO_CSQ_PEEK_NEXT_IRP;
/* * Lock the queue. This can be a spinlock, a mutex, or whatever * else floats your boat. * * Sample: * VOID NTAPI CsqAcquireLock(PIO_CSQ Csq, PKIRQL Irql) { KdPrint(("Acquiring spin lock\n")); KeAcquireSpinLock(&IrpQueueLock, Irql); } * */typedef VOID(NTAPI IO_CSQ_ACQUIRE_LOCK)( _In_ struct _IO_CSQ *Csq, _Out_ PKIRQL Irql);typedef IO_CSQ_ACQUIRE_LOCK *PIO_CSQ_ACQUIRE_LOCK;
/* * Unlock the queue: * VOID NTAPI CsqReleaseLock(PIO_CSQ Csq, KIRQL Irql) { KdPrint(("Releasing spin lock\n")); KeReleaseSpinLock(&IrpQueueLock, Irql); } * */typedef VOID(NTAPI IO_CSQ_RELEASE_LOCK)( _In_ struct _IO_CSQ *Csq, _In_ KIRQL Irql);typedef IO_CSQ_RELEASE_LOCK *PIO_CSQ_RELEASE_LOCK;
/* * Finally, this is called by the queue library when it wants to complete * a canceled IRP. * * Sample: * VOID NTAPI CsqCompleteCancelledIrp(PIO_CSQ Csq, PIRP Irp) { KdPrint(("cancelling irp 0x%x\n", Irp)); Irp->IoStatus.Status = STATUS_CANCELLED; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); } * */typedef VOID(NTAPI IO_CSQ_COMPLETE_CANCELED_IRP)( _In_ struct _IO_CSQ *Csq, _In_ PIRP Irp);typedef IO_CSQ_COMPLETE_CANCELED_IRP *PIO_CSQ_COMPLETE_CANCELED_IRP;
/* * IO_CSQ - Queue control structure */typedef struct _IO_CSQ { ULONG Type; PIO_CSQ_INSERT_IRP CsqInsertIrp; PIO_CSQ_REMOVE_IRP CsqRemoveIrp; PIO_CSQ_PEEK_NEXT_IRP CsqPeekNextIrp; PIO_CSQ_ACQUIRE_LOCK CsqAcquireLock; PIO_CSQ_RELEASE_LOCK CsqReleaseLock; PIO_CSQ_COMPLETE_CANCELED_IRP CsqCompleteCanceledIrp; PVOID ReservePointer; /* must be NULL */} IO_CSQ, *PIO_CSQ;
#endif /* IO_TYPE_CSQ_IRP_CONTEXT */
#ifndef IO_TYPE_CSQ_EX
/* See IO_TYPE_CSQ_* above */#define IO_TYPE_CSQ_EX 3
/* * Function to insert an IRP into the queue with extended context information. * This is useful if you need to be able to de-queue particular IRPs more * easily in some cases. * * Same deal as above; sample implementation: * NTSTATUS NTAPI CsqInsertIrpEx(PIO_CSQ Csq, PIRP Irp, PVOID InsertContext) { CsqInsertIrp(Csq, Irp); return STATUS_PENDING; } * */typedef NTSTATUS(NTAPI IO_CSQ_INSERT_IRP_EX)( _In_ struct _IO_CSQ *Csq, _In_ PIRP Irp, _In_ PVOID InsertContext);typedef IO_CSQ_INSERT_IRP_EX *PIO_CSQ_INSERT_IRP_EX;
#endif /* IO_TYPE_CSQ_EX */
/* * CANCEL-SAFE QUEUE DDIs * * These device driver interfaces are called to make use of the queue. Again, * authoritative documentation for these functions is in the DDK. The csqtest * driver also makes use of some of them. */
/* * Call this in DriverEntry or similar in order to set up the Csq structure. * As long as the Csq struct and the functions you pass in are resident, * there are no IRQL restrictions. */NTKERNELAPINTSTATUS 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);
/* * Same as above, except you provide a CsqInsertIrpEx routine instead of * CsqInsertIrp. This eventually allows you to supply extra tracking * information for use with the queue. */NTKERNELAPINTSTATUS 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);
/* * Insert an IRP into the queue */NTKERNELAPIVOID NTAPI IoCsqInsertIrp(_Inout_ PIO_CSQ Csq, _Inout_ PIRP Irp, _Out_opt_ PIO_CSQ_IRP_CONTEXT Context);
/* * Insert an IRP into the queue, with special context maintained that * makes it easy to find IRPs in the queue */NTKERNELAPINTSTATUS NTAPI IoCsqInsertIrpEx(_Inout_ PIO_CSQ Csq, _Inout_ PIRP Irp, _Out_opt_ PIO_CSQ_IRP_CONTEXT Context, _In_opt_ PVOID InsertContext);
/* * Remove a particular IRP from the queue */NTKERNELAPIPIRP NTAPI IoCsqRemoveIrp(_Inout_ PIO_CSQ Csq, _Inout_ PIO_CSQ_IRP_CONTEXT Context);
/* * Remove the next IRP from the queue */NTKERNELAPIPIRP NTAPI IoCsqRemoveNextIrp(_Inout_ PIO_CSQ Csq, _In_opt_ PVOID PeekContext);
#ifdef __cplusplus}#endif