123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334 |
- /*
- * 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 __cplusplus
- extern "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 PIRP Irp,
- IN 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.
- */
- NTKERNELAPI
- NTSTATUS NTAPI IoCsqInitialize(PIO_CSQ Csq,
- 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);
- /*
- * 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.
- */
- NTKERNELAPI
- NTSTATUS NTAPI IoCsqInitializeEx(PIO_CSQ Csq,
- PIO_CSQ_INSERT_IRP_EX CsqInsertIrpEx,
- 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);
- /*
- * Insert an IRP into the queue
- */
- NTKERNELAPI
- VOID NTAPI IoCsqInsertIrp(PIO_CSQ Csq,
- PIRP Irp,
- 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
- */
- NTKERNELAPI
- NTSTATUS NTAPI IoCsqInsertIrpEx(PIO_CSQ Csq,
- PIRP Irp,
- PIO_CSQ_IRP_CONTEXT Context,
- PVOID InsertContext);
- /*
- * Remove a particular IRP from the queue
- */
- NTKERNELAPI
- PIRP NTAPI IoCsqRemoveIrp(PIO_CSQ Csq,
- PIO_CSQ_IRP_CONTEXT Context);
- /*
- * Remove the next IRP from the queue
- */
- NTKERNELAPI
- PIRP NTAPI IoCsqRemoveNextIrp(PIO_CSQ Csq,
- PVOID PeekContext);
- #ifdef __cplusplus
- }
- #endif
|