Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

remlock.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1990 Microsoft Corporation 00004 00005 Module Name: 00006 00007 remlock.c 00008 00009 Abstract: 00010 00011 This is the NT SCSI port driver. 00012 00013 Authors: 00014 00015 Peter Wieland 00016 Kenneth Ray 00017 00018 Environment: 00019 00020 kernel mode only 00021 00022 Notes: 00023 00024 00025 00026 Revision History: 00027 00028 --*/ 00029 00030 #include "iop.h" 00031 00032 #include <remlock.h> 00033 00034 #pragma alloc_text(PAGE, IoInitializeRemoveLockEx) 00035 #pragma alloc_text(PAGE, IoReleaseRemoveLockAndWaitEx) 00036 00037 #define MinutesToTicks(x) \ 00038 (ULONGLONG) KeQueryTimeIncrement() * \ 00039 10 * \ 00040 1000 * \ 00041 1000 * \ 00042 60 * \ 00043 x 00044 00045 // 10 -> microseconds, 1000 -> miliseconds, 1000 -> seconds, 60 -> minutes 00046 00047 00048 typedef struct _IO_PRIVATE_REMOVE_LOCK { 00049 IO_REMOVE_LOCK_COMMON_BLOCK Common; 00050 IO_REMOVE_LOCK_DBG_BLOCK Dbg; 00051 } IO_PRIVATE_REMOVE_LOCK, *PIO_PRIVATE_REMOVE_LOCK; 00052 00053 00054 #define FREESIZE sizeof (IO_REMOVE_LOCK_COMMON_BLOCK) 00055 #define CHECKEDSIZE sizeof (IO_PRIVATE_REMOVE_LOCK) 00056 00057 00058 NTSYSAPI 00059 VOID 00060 NTAPI 00061 IoInitializeRemoveLockEx( 00062 IN PIO_REMOVE_LOCK PublicLock, 00063 IN ULONG AllocateTag, // Used only on checked kernels 00064 IN ULONG MaxLockedMinutes, // Used only on checked kernels 00065 IN ULONG HighWatermark, // Used only on checked kernels 00066 IN ULONG RemlockSize // are we checked or free 00067 ) 00068 /*++ 00069 00070 Routine Description: 00071 00072 This routine is called to initialize the remove lock for a device object. 00073 00074 --*/ 00075 { 00076 PIO_PRIVATE_REMOVE_LOCK Lock = (PIO_PRIVATE_REMOVE_LOCK) PublicLock; 00077 00078 PAGED_CODE (); 00079 00080 if (Lock) { 00081 00082 switch (RemlockSize) { 00083 00084 case CHECKEDSIZE: 00085 Lock->Dbg.Signature = IO_REMOVE_LOCK_SIG; 00086 Lock->Dbg.HighWatermark = HighWatermark; 00087 Lock->Dbg.MaxLockedTicks = MinutesToTicks (MaxLockedMinutes); 00088 Lock->Dbg.AllocateTag = AllocateTag; 00089 KeInitializeSpinLock (&Lock->Dbg.Spin); 00090 Lock->Dbg.LowMemoryCount = 0; 00091 Lock->Dbg.Blocks = NULL; 00092 00093 // 00094 // fall through 00095 // 00096 case FREESIZE: 00097 Lock->Common.Removed = FALSE; 00098 Lock->Common.IoCount = 1; 00099 KeInitializeEvent(&Lock->Common.RemoveEvent, 00100 SynchronizationEvent, 00101 FALSE); 00102 break; 00103 00104 default: 00105 break; 00106 } 00107 } 00108 } 00109 00110 00111 NTSYSAPI 00112 NTSTATUS 00113 NTAPI 00114 IoAcquireRemoveLockEx( 00115 IN PIO_REMOVE_LOCK PublicLock, 00116 IN OPTIONAL PVOID Tag, 00117 IN PCSTR File, 00118 IN ULONG Line, 00119 IN ULONG RemlockSize // are we checked or free 00120 ) 00121 00122 /*++ 00123 00124 Routine Description: 00125 00126 This routine is called to acquire the remove lock for a device object. 00127 While the lock is held, the caller can assume that no pending pnp REMOVE 00128 requests will be completed. 00129 00130 The lock should be acquired immediately upon entering a dispatch routine. 00131 It should also be acquired before creating any new reference to the 00132 device object if there's a chance of releasing the reference before the 00133 new one is done. 00134 00135 Arguments: 00136 00137 RemoveLock - A pointer to an initialized REMOVE_LOCK structure. 00138 00139 Tag - Used for tracking lock allocation and release. If an irp is 00140 specified when acquiring the lock then the same Tag must be 00141 used to release the lock before the Tag is completed. 00142 00143 File - set to __FILE__ as the location in the code where the lock was taken. 00144 00145 Line - set to __LINE__. 00146 00147 Return Value: 00148 00149 Returns whether or not the remove lock was obtained. 00150 If successful the caller should continue with work calling 00151 IoReleaseRemoveLock when finished. 00152 00153 If not successful the lock was not obtained. The caller should abort the 00154 work but not call IoReleaseRemoveLock. 00155 00156 --*/ 00157 00158 { 00159 PIO_PRIVATE_REMOVE_LOCK Lock = (PIO_PRIVATE_REMOVE_LOCK) PublicLock; 00160 LONG lockValue; 00161 NTSTATUS status; 00162 00163 PIO_REMOVE_LOCK_TRACKING_BLOCK trackingBlock; 00164 00165 // 00166 // Grab the remove lock 00167 // 00168 00169 lockValue = InterlockedIncrement(&Lock->Common.IoCount); 00170 00171 ASSERTMSG("IoAcquireRemoveLock - lock value was negative : ", 00172 (lockValue > 0)); 00173 00174 if (! Lock->Common.Removed) { 00175 00176 switch (RemlockSize) { 00177 case CHECKEDSIZE: 00178 00179 ASSERTMSG("RemoveLock increased to meet LockHighWatermark", 00180 ((0 == Lock->Dbg.HighWatermark) || 00181 (lockValue <= Lock->Dbg.HighWatermark))); 00182 00183 trackingBlock = ExAllocatePoolWithTag( 00184 NonPagedPool, 00185 sizeof(IO_REMOVE_LOCK_TRACKING_BLOCK), 00186 Lock->Dbg.AllocateTag); 00187 00188 if (NULL == trackingBlock) { 00189 00190 // ASSERTMSG ("insufficient resources", FALSE); 00191 InterlockedIncrement (& Lock->Dbg.LowMemoryCount); 00192 // 00193 // Let the acquire go through but without adding the 00194 // tracking block. 00195 // When we are later releasing the lock, but the tracking 00196 // block does not exist, deduct from this value to see if the 00197 // release was still valuable. 00198 // 00199 00200 } else { 00201 00202 KIRQL oldIrql; 00203 00204 RtlZeroMemory (trackingBlock, 00205 sizeof (IO_REMOVE_LOCK_TRACKING_BLOCK)); 00206 00207 trackingBlock->Tag = Tag; 00208 trackingBlock->File = File; 00209 trackingBlock->Line = Line; 00210 00211 KeQueryTickCount(&trackingBlock->TimeLocked); 00212 00213 ExAcquireSpinLock (&Lock->Dbg.Spin, &oldIrql); 00214 trackingBlock->Link = Lock->Dbg.Blocks; 00215 Lock->Dbg.Blocks = trackingBlock; 00216 ExReleaseSpinLock(&Lock->Dbg.Spin, oldIrql); 00217 } 00218 break; 00219 00220 case FREESIZE: 00221 break; 00222 00223 default: 00224 break; 00225 } 00226 00227 status = STATUS_SUCCESS; 00228 00229 } else { 00230 00231 if (0 == InterlockedDecrement (&Lock->Common.IoCount)) { 00232 KeSetEvent (&Lock->Common.RemoveEvent, 0, FALSE); 00233 } 00234 status = STATUS_DELETE_PENDING; 00235 } 00236 00237 return status; 00238 } 00239 00240 00241 NTSYSAPI 00242 VOID 00243 NTAPI 00244 IoReleaseRemoveLockEx( 00245 IN PIO_REMOVE_LOCK PublicLock, 00246 IN PVOID Tag, 00247 IN ULONG RemlockSize // are we checked or free 00248 ) 00249 00250 /*++ 00251 00252 Routine Description: 00253 00254 This routine is called to release the remove lock on the device object. It 00255 must be called when finished using a previously locked reference to the 00256 device object. If an Tag was specified when acquiring the lock then the 00257 same Tag must be specified when releasing the lock. 00258 00259 When the lock count reduces to zero, this routine will signal the waiting 00260 event to release the waiting thread deleting the device object protected 00261 by this lock. 00262 00263 Arguments: 00264 00265 DeviceObject - the device object to lock 00266 00267 Tag - The tag (if any) specified when acquiring the lock. This is used 00268 for lock tracking purposes 00269 00270 Return Value: 00271 00272 none 00273 00274 --*/ 00275 00276 { 00277 PIO_PRIVATE_REMOVE_LOCK Lock = (PIO_PRIVATE_REMOVE_LOCK) PublicLock; 00278 LONG lockValue; 00279 KIRQL oldIrql; 00280 LARGE_INTEGER ticks; 00281 LONGLONG difference; 00282 BOOLEAN found; 00283 00284 PIO_REMOVE_LOCK_TRACKING_BLOCK last; 00285 PIO_REMOVE_LOCK_TRACKING_BLOCK current; 00286 00287 switch (RemlockSize) { 00288 case CHECKEDSIZE: 00289 00290 // 00291 // Check the tick count and make sure this thing hasn't been locked 00292 // for more than MaxLockedMinutes. 00293 // 00294 00295 found = FALSE; 00296 ExAcquireSpinLock(&Lock->Dbg.Spin, &oldIrql); 00297 last = (Lock->Dbg.Blocks); 00298 current = last; 00299 00300 KeQueryTickCount((&ticks)); 00301 00302 while (NULL != current) { 00303 00304 if (Lock->Dbg.MaxLockedTicks) { 00305 difference = ticks.QuadPart - current->TimeLocked.QuadPart; 00306 00307 if (Lock->Dbg.MaxLockedTicks < difference) { 00308 00309 KdPrint(("IoReleaseRemoveLock: Lock %#08lx (tag %#08lx) " 00310 "locked for %I64d ticks - TOO LONG\n", 00311 Lock, 00312 current->Tag, 00313 difference)); 00314 00315 KdPrint(("IoReleaseRemoveLock: Lock acquired in file " 00316 "%s on line %d\n", 00317 current->File, 00318 current->Line)); 00319 ASSERT(FALSE); 00320 } 00321 } 00322 00323 if ((!found) && (current->Tag == Tag)) { 00324 found = TRUE; 00325 if (current == Lock->Dbg.Blocks) { 00326 Lock->Dbg.Blocks = current->Link; 00327 ExFreePool (current); 00328 current = Lock->Dbg.Blocks; 00329 } else { 00330 last->Link = current->Link; 00331 ExFreePool (current); 00332 current = last->Link; 00333 } 00334 continue; 00335 } 00336 00337 last = current; 00338 current = current->Link; 00339 } 00340 00341 ExReleaseSpinLock(&Lock->Dbg.Spin, oldIrql); 00342 00343 if (!found) { 00344 // 00345 // Check to see if we have any credits in our Low Memory Count. 00346 // In this fassion we can tell if we have acquired any locks without 00347 // the memory for adding tracking blocks. 00348 // 00349 if (InterlockedDecrement (& Lock->Dbg.LowMemoryCount) < 0) { 00350 // 00351 // We have just released a lock that neither had a corresponding 00352 // tracking block, nor a credit in LowMemoryCount. 00353 // 00354 InterlockedIncrement (& Lock->Dbg.LowMemoryCount); 00355 KdPrint (("IoReleaseRemoveLock: Couldn't find Tag %#08lx " 00356 "in the lock tracking list\n", 00357 Tag)); 00358 ASSERT(FALSE); 00359 } 00360 } 00361 break; 00362 00363 case FREESIZE: 00364 break; 00365 00366 default: 00367 break; 00368 } 00369 00370 lockValue = InterlockedDecrement(&Lock->Common.IoCount); 00371 00372 ASSERT(0 <= lockValue); 00373 00374 if (0 == lockValue) { 00375 00376 ASSERT (Lock->Common.Removed); 00377 00378 // 00379 // The device needs to be removed. Signal the remove event 00380 // that it's safe to go ahead. 00381 // 00382 00383 KeSetEvent(&Lock->Common.RemoveEvent, 00384 IO_NO_INCREMENT, 00385 FALSE); 00386 } 00387 return; 00388 } 00389 00390 00391 NTSYSAPI 00392 VOID 00393 NTAPI 00394 IoReleaseRemoveLockAndWaitEx ( 00395 IN PIO_REMOVE_LOCK PublicLock, 00396 IN PVOID Tag, 00397 IN ULONG RemlockSize // are we checked or free 00398 ) 00399 00400 /*++ 00401 00402 Routine Description: 00403 00404 This routine is called when the client would like to delete the remove- 00405 locked resource. 00406 This routine will block until all the remove locks have completed. 00407 00408 This routine MUST be called after acquiring once more the lock. 00409 00410 Arguments: 00411 00412 RemoveLock - 00413 00414 Return Value: 00415 00416 none 00417 00418 --*/ 00419 { 00420 PIO_PRIVATE_REMOVE_LOCK Lock = (PIO_PRIVATE_REMOVE_LOCK) PublicLock; 00421 LONG ioCount; 00422 00423 PAGED_CODE (); 00424 00425 Lock->Common.Removed = TRUE; 00426 00427 ioCount = InterlockedDecrement (&Lock->Common.IoCount); 00428 ASSERT (0 < ioCount); 00429 00430 if (0 < InterlockedDecrement (&Lock->Common.IoCount)) { 00431 KeWaitForSingleObject (&Lock->Common.RemoveEvent, 00432 Executive, 00433 KernelMode, 00434 FALSE, 00435 NULL); 00436 } 00437 00438 switch (RemlockSize) { 00439 case CHECKEDSIZE: 00440 00441 ASSERT (Lock->Dbg.Blocks); 00442 if (Tag != Lock->Dbg.Blocks->Tag) { 00443 KdPrint (("IoRelaseRemoveLockAndWait last tag invalid %x %x\n", 00444 Tag, 00445 Lock->Dbg.Blocks->Tag)); 00446 00447 ASSERT (Tag != Lock->Dbg.Blocks->Tag); 00448 } 00449 00450 ExFreePool (Lock->Dbg.Blocks); 00451 break; 00452 00453 case FREESIZE: 00454 break; 00455 00456 default: 00457 break; 00458 00459 } 00460 } 00461 00462

Generated on Sat May 15 19:41:38 2004 for test by doxygen 1.3.7