2 * ReactOS Floppy Driver
3 * Copyright (C) 2004, Vizzini (vizzini@plasmic.com)
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 * PROJECT: ReactOS Floppy Driver
21 * PURPOSE: Cancel-safe queue routines
22 * PROGRAMMER: Vizzini (vizzini@plasmic.com)
24 * 15-Feb-2004 vizzini - Created
26 * - These functions provide the callbacks for the CSQ routines.
27 * They will be called automatically by the IoCsqXxx() routines.
28 * This driver uses the CSQ in the standard way. In addition to
29 * queuing and de-queuing IRPs, the InsertIrp routine releases
30 * a semaphore every time an IRP is queued, allowing a queue management
31 * thread to properly drain the queue.
32 * - Note that the semaphore can get ahead of the number of IRPs in the
33 * queue if any are canceled; the queue management thread that de-queues
34 * IRPs is coded with that in mind.
35 * - For more information, see the csqtest driver in the ReactOS tree,
36 * or the cancel sample in recent (3790+) Microsoft DDKs.
37 * - Many of these routines are called at DISPATCH_LEVEL, due to the fact
38 * that my lock choice is a spin lock.
45 /* Global CSQ struct that the CSQ functions initialize and use */
48 /* List and lock for the actual IRP queue */
50 KSPIN_LOCK IrpQueueLock
;
51 KSEMAPHORE QueueSemaphore
;
59 CsqRemoveIrp(PIO_CSQ UnusedCsq
, PIRP Irp
)
61 * FUNCTION: Remove an IRP from the queue
63 * UnusedCsq: Pointer to CSQ context structure
64 * Irp: Pointer to the IRP to remove from the queue
66 * - Called under the protection of the queue lock
69 UNREFERENCED_PARAMETER(UnusedCsq
);
70 TRACE_(FLOPPY
, "CSQ: Removing IRP 0x%p\n", Irp
);
71 RemoveEntryList(&Irp
->Tail
.Overlay
.ListEntry
);
76 CsqPeekNextIrp(PIO_CSQ UnusedCsq
, PIRP Irp
, PVOID PeekContext
)
78 * FUNCTION: Find the next matching IRP in the queue
80 * UnusedCsq: Pointer to CSQ context structure
81 * Irp: Pointer to a starting IRP in the queue (i.e. start search here)
84 * Pointer to an IRP that is next in line to be removed, if one can be found
86 * - This does *not* remove the IRP from the queue; it merely returns a pointer.
87 * - Called under the protection of the queue lock
90 UNREFERENCED_PARAMETER(UnusedCsq
);
91 UNREFERENCED_PARAMETER(PeekContext
);
92 TRACE_(FLOPPY
, "CSQ: Peeking for next IRP\n");
95 return CONTAINING_RECORD(&Irp
->Tail
.Overlay
.ListEntry
.Flink
, IRP
, Tail
.Overlay
.ListEntry
);
97 if(IsListEmpty(&IrpQueue
))
100 return CONTAINING_RECORD(IrpQueue
.Flink
, IRP
, Tail
.Overlay
.ListEntry
);
105 CsqAcquireLock(PIO_CSQ UnusedCsq
, PKIRQL Irql
)
107 * FUNCTION: Acquire the queue lock
109 * UnusedCsq: Pointer to CSQ context structure
110 * Irql: Pointer to a variable to store the old irql into
113 UNREFERENCED_PARAMETER(UnusedCsq
);
114 INFO_(FLOPPY
, "CSQ: Acquiring spin lock\n");
115 KeAcquireSpinLock(&IrpQueueLock
, Irql
);
120 CsqReleaseLock(PIO_CSQ UnusedCsq
, KIRQL Irql
)
122 * FUNCTION: Release the queue lock
124 * UnusedCsq: Pointer to CSQ context structure
125 * Irql: IRQL to lower to on release
128 UNREFERENCED_PARAMETER(UnusedCsq
);
129 INFO_(FLOPPY
, "CSQ: Releasing spin lock\n");
130 KeReleaseSpinLock(&IrpQueueLock
, Irql
);
135 CsqCompleteCanceledIrp(PIO_CSQ UnusedCsq
, PIRP Irp
)
137 * FUNCTION: Complete a canceled IRP
139 * UnusedCsq: Pointer to CSQ context structure
140 * Irp: IRP to complete
142 * - Perhaps we should complete with something besides NO_INCREMENT
143 * - MS misspelled CANCELLED... sigh...
146 UNREFERENCED_PARAMETER(UnusedCsq
);
147 TRACE_(FLOPPY
, "CSQ: Canceling irp 0x%p\n", Irp
);
148 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
149 Irp
->IoStatus
.Information
= 0;
150 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
155 CsqInsertIrp(PIO_CSQ UnusedCsq
, PIRP Irp
)
157 * FUNCTION: Queue an IRP
160 * Irp: IRP to add to the queue
162 * - Called under the protection of the queue lock
163 * - Releases the semaphore for each queued packet, which is how
164 * the queue management thread knows that there might be
165 * an IRP in the queue
166 * - Note that the semaphore will get released more times than
167 * the queue management thread will have IRPs to process, given
168 * that at least one IRP is canceled at some point
171 UNREFERENCED_PARAMETER(UnusedCsq
);
172 TRACE_(FLOPPY
, "CSQ: Inserting IRP 0x%p\n", Irp
);
173 InsertTailList(&IrpQueue
, &Irp
->Tail
.Overlay
.ListEntry
);
174 KeReleaseSemaphore(&QueueSemaphore
, 0, 1, FALSE
);