NTSYSAPI VOID NTAPI IoInitializeRemoveLockEx( IN PIO_REMOVE_LOCK PublicLock, IN ULONG AllocateTag, // Used only on checked kernels IN ULONG MaxLockedMinutes, // Used only on checked kernels IN ULONG HighWatermark, // Used only on checked kernels IN ULONG RemlockSize // are we checked or free ) /*++ Routine Description: This routine is called to initialize the remove lock for a device object. --*/ { PIO_PRIVATE_REMOVE_LOCK Lock = (PIO_PRIVATE_REMOVE_LOCK) PublicLock; PAGED_CODE (); if (Lock) { switch (RemlockSize) { case CHECKEDSIZE: Lock->Dbg.Signature = IO_REMOVE_LOCK_SIG; Lock->Dbg.HighWatermark = HighWatermark; Lock->Dbg.MaxLockedTicks = MinutesToTicks (MaxLockedMinutes); Lock->Dbg.AllocateTag = AllocateTag; KeInitializeSpinLock (&Lock->Dbg.Spin); Lock->Dbg.LowMemoryCount = 0; Lock->Dbg.Blocks = NULL; // // fall through // case FREESIZE: Lock->Common.Removed = FALSE; Lock->Common.IoCount = 1; KeInitializeEvent(&Lock->Common.RemoveEvent, SynchronizationEvent, FALSE); break; default: break; } } }
NTSYSAPI VOID NTAPI RtlReleaseRemoveLock( IN PRTL_REMOVE_LOCK RemoveLock, IN PVOID Tag ) /*++ Routine Description: This routine is called to release the remove lock on the device object. It must be called when finished using a previously locked reference to the device object. If an Tag was specified when acquiring the lock then the same Tag must be specified when releasing the lock. When the lock count reduces to zero, this routine will signal the waiting event to release the waiting thread deleting the device object protected by this lock. Arguments: DeviceObject - the device object to lock Tag - The tag (if any) specified when acquiring the lock. This is used for lock tracking purposes Return Value: none --*/ { LONG lockValue; #if DBG KIRQL oldIrql; LARGE_INTEGER difference; BOOLEAN found; LONGLONG maxTime; PRTL_REMOVE_LOCK_TRACKING_BLOCK last; PRTL_REMOVE_LOCK_TRACKING_BLOCK current; // // Check the tick count and make sure this thing hasn't been locked // for more than MaxLockedMinutes. // found = FALSE; KeAcquireSpinLock(&RemoveLock->Spin, &oldIrql); last = (&RemoveLock->Blocks); current = last->Link; // // Note the first one is the sentinal // while (NULL != current) { KeQueryTickCount((&difference)); difference.QuadPart -= current->TimeLocked.QuadPart; maxTime = MinutesToTicks (RemoveLock->MaxLockedMinutes); if (maxTime && (maxTime < difference.QuadPart)) { KdPrint(("RtlReleaseRemoveLock: Lock %#08lx (tag %#08lx) locked " "for %I64d ticks - TOO LONG\n", RemoveLock, current->Tag, difference.QuadPart)); KdPrint(("RtlReleaseRemoveLock: Lock acquired in file " "%s on line %d\n", current->File, current->Line)); ASSERT(FALSE); } if ((!found) && (current->Tag == Tag)) { found = TRUE; last->Link = current->Link; ExFreePool (current); current = last->Link; continue; } last = current; current = current->Link; } KeReleaseSpinLock(&RemoveLock->Spin, oldIrql); if (!found) { KdPrint (("RtlReleaseRemoveLock: Couldn't find Tag %#08lx " "in the lock tracking list\n", Tag)); ASSERT(FALSE); } #endif lockValue = InterlockedDecrement(&RemoveLock->IoCount); ASSERT(0 <= lockValue); if (0 == lockValue) { ASSERT (RemoveLock->Removed); // // The device needs to be removed. Signal the remove event // that it's safe to go ahead. // KeSetEvent(&RemoveLock->RemoveEvent, IO_NO_INCREMENT, FALSE); } return; }