1 /* 2 * ReactOS Floppy Driver 3 * Copyright (C) 2004, Vizzini (vizzini@plasmic.com) 4 * 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. 9 * 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. 14 * 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. 18 * 19 * PROJECT: ReactOS Floppy Driver 20 * FILE: csqrtns.c 21 * PURPOSE: Cancel-safe queue routines 22 * PROGRAMMER: Vizzini (vizzini@plasmic.com) 23 * REVISIONS: 24 * 15-Feb-2004 vizzini - Created 25 * NOTES: 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. 39 */ 40 41 #include "precomp.h" 42 43 #include <debug.h> 44 45 /* Global CSQ struct that the CSQ functions initialize and use */ 46 IO_CSQ Csq; 47 48 /* List and lock for the actual IRP queue */ 49 LIST_ENTRY IrpQueue; 50 KSPIN_LOCK IrpQueueLock; 51 KSEMAPHORE QueueSemaphore; 52 53 /* 54 * CSQ Callbacks 55 */ 56 57 58 VOID NTAPI 59 CsqRemoveIrp(PIO_CSQ UnusedCsq, PIRP Irp) 60 /* 61 * FUNCTION: Remove an IRP from the queue 62 * ARGUMENTS: 63 * UnusedCsq: Pointer to CSQ context structure 64 * Irp: Pointer to the IRP to remove from the queue 65 * NOTES: 66 * - Called under the protection of the queue lock 67 */ 68 { 69 UNREFERENCED_PARAMETER(UnusedCsq); 70 TRACE_(FLOPPY, "CSQ: Removing IRP 0x%p\n", Irp); 71 RemoveEntryList(&Irp->Tail.Overlay.ListEntry); 72 } 73 74 75 PIRP NTAPI 76 CsqPeekNextIrp(PIO_CSQ UnusedCsq, PIRP Irp, PVOID PeekContext) 77 /* 78 * FUNCTION: Find the next matching IRP in the queue 79 * ARGUMENTS: 80 * UnusedCsq: Pointer to CSQ context structure 81 * Irp: Pointer to a starting IRP in the queue (i.e. start search here) 82 * PeekContext: Unused 83 * RETURNS: 84 * Pointer to an IRP that is next in line to be removed, if one can be found 85 * NOTES: 86 * - This does *not* remove the IRP from the queue; it merely returns a pointer. 87 * - Called under the protection of the queue lock 88 */ 89 { 90 UNREFERENCED_PARAMETER(UnusedCsq); 91 UNREFERENCED_PARAMETER(PeekContext); 92 TRACE_(FLOPPY, "CSQ: Peeking for next IRP\n"); 93 94 if(Irp) 95 return CONTAINING_RECORD(&Irp->Tail.Overlay.ListEntry.Flink, IRP, Tail.Overlay.ListEntry); 96 97 if(IsListEmpty(&IrpQueue)) 98 return NULL; 99 100 return CONTAINING_RECORD(IrpQueue.Flink, IRP, Tail.Overlay.ListEntry); 101 } 102 103 104 VOID NTAPI 105 CsqAcquireLock(PIO_CSQ UnusedCsq, PKIRQL Irql) 106 /* 107 * FUNCTION: Acquire the queue lock 108 * ARGUMENTS: 109 * UnusedCsq: Pointer to CSQ context structure 110 * Irql: Pointer to a variable to store the old irql into 111 */ 112 { 113 UNREFERENCED_PARAMETER(UnusedCsq); 114 INFO_(FLOPPY, "CSQ: Acquiring spin lock\n"); 115 KeAcquireSpinLock(&IrpQueueLock, Irql); 116 } 117 118 119 VOID NTAPI 120 CsqReleaseLock(PIO_CSQ UnusedCsq, KIRQL Irql) 121 /* 122 * FUNCTION: Release the queue lock 123 * ARGUMENTS: 124 * UnusedCsq: Pointer to CSQ context structure 125 * Irql: IRQL to lower to on release 126 */ 127 { 128 UNREFERENCED_PARAMETER(UnusedCsq); 129 INFO_(FLOPPY, "CSQ: Releasing spin lock\n"); 130 KeReleaseSpinLock(&IrpQueueLock, Irql); 131 } 132 133 134 VOID NTAPI 135 CsqCompleteCanceledIrp(PIO_CSQ UnusedCsq, PIRP Irp) 136 /* 137 * FUNCTION: Complete a canceled IRP 138 * ARGUMENTS: 139 * UnusedCsq: Pointer to CSQ context structure 140 * Irp: IRP to complete 141 * NOTES: 142 * - Perhaps we should complete with something besides NO_INCREMENT 143 * - MS misspelled CANCELLED... sigh... 144 */ 145 { 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); 151 } 152 153 154 VOID NTAPI 155 CsqInsertIrp(PIO_CSQ UnusedCsq, PIRP Irp) 156 /* 157 * FUNCTION: Queue an IRP 158 * ARGUMENTS: 159 * UnusedCsq: Unused 160 * Irp: IRP to add to the queue 161 * NOTES: 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 169 */ 170 { 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); 175 } 176