Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenremlock.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: ntoskrnl/io/remlock.c 00005 * PURPOSE: Remove Lock Support 00006 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 00007 * Filip Navara (navaraf@reactos.org) 00008 * Pierre Schweitzer (pierre.schweitzer@reactos.org) 00009 */ 00010 00011 /* INCLUDES ******************************************************************/ 00012 00013 #include <ntoskrnl.h> 00014 #define NDEBUG 00015 #include <debug.h> 00016 00017 typedef struct _IO_REMOVE_LOCK_TRACKING_BLOCK 00018 { 00019 PIO_REMOVE_LOCK_TRACKING_BLOCK Next; 00020 PVOID Tag; 00021 LARGE_INTEGER LockMoment; 00022 LPCSTR File; 00023 ULONG Line; 00024 } IO_REMOVE_LOCK_TRACKING_BLOCK; 00025 00026 /* FUNCTIONS *****************************************************************/ 00027 00028 /* 00029 * @implemented 00030 */ 00031 VOID 00032 NTAPI 00033 IoInitializeRemoveLockEx(IN PIO_REMOVE_LOCK RemoveLock, 00034 IN ULONG AllocateTag, 00035 IN ULONG MaxLockedMinutes, 00036 IN ULONG HighWatermark, 00037 IN ULONG RemlockSize) 00038 { 00039 PEXTENDED_IO_REMOVE_LOCK Lock = (PEXTENDED_IO_REMOVE_LOCK)RemoveLock; 00040 PAGED_CODE(); 00041 00042 ASSERT(HighWatermark < MAXLONG); 00043 00044 /* If no lock given, nothing to do */ 00045 if (!Lock) 00046 { 00047 return; 00048 } 00049 00050 switch (RemlockSize) 00051 { 00052 /* Check if this is a debug lock */ 00053 case (sizeof(IO_REMOVE_LOCK_DBG_BLOCK) + sizeof(IO_REMOVE_LOCK_COMMON_BLOCK)): 00054 /* Setup debug parameters */ 00055 Lock->Dbg.Signature = 'COLR'; 00056 Lock->Dbg.HighWatermark = HighWatermark; 00057 Lock->Dbg.MaxLockedTicks = KeQueryTimeIncrement() * MaxLockedMinutes * 600000000; 00058 Lock->Dbg.AllocateTag = AllocateTag; 00059 KeInitializeSpinLock(&(Lock->Dbg.Spin)); 00060 Lock->Dbg.LowMemoryCount = 0; 00061 Lock->Dbg.Blocks = NULL; 00062 00063 case sizeof(IO_REMOVE_LOCK_COMMON_BLOCK): 00064 /* Setup a free block */ 00065 Lock->Common.Removed = FALSE; 00066 Lock->Common.IoCount = 1; 00067 KeInitializeEvent(&Lock->Common.RemoveEvent, 00068 SynchronizationEvent, 00069 FALSE); 00070 } 00071 } 00072 00073 /* 00074 * @implemented 00075 */ 00076 NTSTATUS 00077 NTAPI 00078 IoAcquireRemoveLockEx(IN PIO_REMOVE_LOCK RemoveLock, 00079 IN OPTIONAL PVOID Tag, 00080 IN LPCSTR File, 00081 IN ULONG Line, 00082 IN ULONG RemlockSize) 00083 { 00084 KIRQL OldIrql; 00085 LONG LockValue; 00086 PIO_REMOVE_LOCK_TRACKING_BLOCK TrackingBlock; 00087 PEXTENDED_IO_REMOVE_LOCK Lock = (PEXTENDED_IO_REMOVE_LOCK)RemoveLock; 00088 00089 /* Increase the lock count */ 00090 LockValue = InterlockedIncrement(&(Lock->Common.IoCount)); 00091 ASSERT(LockValue > 0); 00092 if (!Lock->Common.Removed) 00093 { 00094 /* Check what kind of lock this is */ 00095 if (RemlockSize == (sizeof(IO_REMOVE_LOCK_DBG_BLOCK) + sizeof(IO_REMOVE_LOCK_COMMON_BLOCK))) 00096 { 00097 ASSERT(Lock->Dbg.HighWatermark == 0 || LockValue <= Lock->Dbg.HighWatermark); 00098 00099 /* Allocate a tracking block */ 00100 TrackingBlock = ExAllocatePoolWithTag(NonPagedPool, sizeof(IO_REMOVE_LOCK_TRACKING_BLOCK), Lock->Dbg.AllocateTag); 00101 if (!TrackingBlock) 00102 { 00103 /* Keep count of failures for lock release and missing tags */ 00104 InterlockedIncrement(&(Lock->Dbg.LowMemoryCount)); 00105 } 00106 else 00107 { 00108 /* Initialize block */ 00109 RtlZeroMemory(TrackingBlock, sizeof(IO_REMOVE_LOCK_TRACKING_BLOCK)); 00110 TrackingBlock->Tag = Tag; 00111 TrackingBlock->File = File; 00112 TrackingBlock->Line = Line; 00113 KeQueryTickCount(&(TrackingBlock->LockMoment)); 00114 00115 /* Queue the block */ 00116 KeAcquireSpinLock(&(Lock->Dbg.Spin), &OldIrql); 00117 TrackingBlock->Next = Lock->Dbg.Blocks; 00118 Lock->Dbg.Blocks = TrackingBlock; 00119 KeReleaseSpinLock(&(Lock->Dbg.Spin), OldIrql); 00120 } 00121 } 00122 } 00123 else 00124 { 00125 /* Otherwise, decrement the count and check if it's gone */ 00126 if (!InterlockedDecrement(&(Lock->Common.IoCount))) 00127 { 00128 /* Signal the event */ 00129 KeSetEvent(&(Lock->Common.RemoveEvent), IO_NO_INCREMENT, FALSE); 00130 } 00131 00132 /* Return pending delete */ 00133 return STATUS_DELETE_PENDING; 00134 } 00135 00136 /* Otherwise, return success */ 00137 return STATUS_SUCCESS; 00138 } 00139 00140 /* 00141 * @implemented 00142 */ 00143 VOID 00144 NTAPI 00145 IoReleaseRemoveLockEx(IN PIO_REMOVE_LOCK RemoveLock, 00146 IN PVOID Tag, 00147 IN ULONG RemlockSize) 00148 { 00149 KIRQL OldIrql; 00150 LONG LockValue; 00151 BOOLEAN TagFound; 00152 LARGE_INTEGER CurrentMoment; 00153 PIO_REMOVE_LOCK_TRACKING_BLOCK TrackingBlock; 00154 PIO_REMOVE_LOCK_TRACKING_BLOCK *TrackingBlockLink; 00155 PEXTENDED_IO_REMOVE_LOCK Lock = (PEXTENDED_IO_REMOVE_LOCK)RemoveLock; 00156 00157 /* Check what kind of lock this is */ 00158 if (RemlockSize == (sizeof(IO_REMOVE_LOCK_DBG_BLOCK) + sizeof(IO_REMOVE_LOCK_COMMON_BLOCK))) 00159 { 00160 /* Acquire blocks queue */ 00161 KeAcquireSpinLock(&(Lock->Dbg.Spin), &OldIrql); 00162 00163 /* Get the release moment */ 00164 KeQueryTickCount(&CurrentMoment); 00165 00166 /* Start browsing tracking blocks to find a block that would match given tag */ 00167 TagFound = FALSE; 00168 TrackingBlock = Lock->Dbg.Blocks; 00169 TrackingBlockLink = &(Lock->Dbg.Blocks); 00170 while (TrackingBlock != NULL) 00171 { 00172 /* First of all, check if the lock was locked for too long */ 00173 if (Lock->Dbg.MaxLockedTicks && 00174 CurrentMoment.QuadPart - TrackingBlock->LockMoment.QuadPart > Lock->Dbg.MaxLockedTicks) 00175 { 00176 DPRINT("Lock %#08lx (with tag %#08lx) was supposed to be held at max %I64d ticks but lasted longer\n", 00177 Lock, TrackingBlock->Tag, Lock->Dbg.MaxLockedTicks); 00178 DPRINT("Lock was acquired in file %s at line %d\n", TrackingBlock->File, TrackingBlock->Line); 00179 ASSERT(FALSE); 00180 } 00181 00182 /* Check if this is the first matching tracking block */ 00183 if ((TagFound == FALSE) && (TrackingBlock->Tag == Tag)) 00184 { 00185 /* Unlink this tracking block, and free it */ 00186 TagFound = TRUE; 00187 *TrackingBlockLink = TrackingBlock->Next; 00188 ExFreePoolWithTag(TrackingBlock, Lock->Dbg.AllocateTag); 00189 TrackingBlock = *TrackingBlockLink; 00190 } 00191 else 00192 { 00193 /* Go to the next tracking block */ 00194 TrackingBlockLink = &(TrackingBlock->Next); 00195 TrackingBlock = TrackingBlock->Next; 00196 } 00197 } 00198 00199 /* We're done, release queue lock */ 00200 KeReleaseSpinLock(&(Lock->Dbg.Spin), OldIrql); 00201 00202 /* If we didn't find any matching block */ 00203 if (TagFound == FALSE) 00204 { 00205 /* Check if it was because we were low in memory 00206 * If yes, then ignore, that's normal 00207 */ 00208 if (InterlockedDecrement(&(Lock->Dbg.LowMemoryCount)) < 0) 00209 { 00210 /* Otherwise signal the issue, it shouldn't happen */ 00211 InterlockedIncrement(&(Lock->Dbg.LowMemoryCount)); 00212 DPRINT("Failed finding block for tag: %#08lx\n", Tag); 00213 ASSERT(FALSE); 00214 } 00215 } 00216 } 00217 00218 /* Decrement the lock count */ 00219 LockValue = InterlockedDecrement(&(Lock->Common.IoCount)); 00220 ASSERT(LockValue >= 0); 00221 00222 if (!LockValue) 00223 { 00224 /* Someone should be waiting... */ 00225 ASSERT(Lock->Common.Removed); 00226 00227 /* Signal the event */ 00228 KeSetEvent(&(Lock->Common.RemoveEvent), IO_NO_INCREMENT, FALSE); 00229 } 00230 } 00231 00232 /* 00233 * @implemented 00234 */ 00235 VOID 00236 NTAPI 00237 IoReleaseRemoveLockAndWaitEx(IN PIO_REMOVE_LOCK RemoveLock, 00238 IN PVOID Tag, 00239 IN ULONG RemlockSize) 00240 { 00241 LONG LockValue; 00242 PIO_REMOVE_LOCK_TRACKING_BLOCK TrackingBlock; 00243 PEXTENDED_IO_REMOVE_LOCK Lock = (PEXTENDED_IO_REMOVE_LOCK)RemoveLock; 00244 PAGED_CODE(); 00245 00246 /* Remove the lock and decrement the count */ 00247 Lock->Common.Removed = TRUE; 00248 LockValue = InterlockedDecrement(&Lock->Common.IoCount); 00249 ASSERT(LockValue > 0); 00250 00251 /* If we are still > 0, then wait for the others to remove lock */ 00252 if (InterlockedDecrement(&Lock->Common.IoCount) > 0) 00253 { 00254 /* Wait for it */ 00255 KeWaitForSingleObject(&(Lock->Common.RemoveEvent), 00256 Executive, 00257 KernelMode, 00258 FALSE, 00259 NULL); 00260 } 00261 00262 /* Check what kind of lock this is */ 00263 if (RemlockSize == (sizeof(IO_REMOVE_LOCK_DBG_BLOCK) + sizeof(IO_REMOVE_LOCK_COMMON_BLOCK))) 00264 { 00265 /* A block must be remaining */ 00266 ASSERT(Lock->Dbg.Blocks); 00267 00268 /* Get it */ 00269 TrackingBlock = Lock->Dbg.Blocks; 00270 /* Tag should match */ 00271 if (TrackingBlock->Tag != Tag) 00272 { 00273 DPRINT("Last tracking block tag invalid! Expected: %x, having: %x\n", Tag, TrackingBlock->Tag); 00274 ASSERT(TrackingBlock->Tag != Tag); 00275 } 00276 00277 /* Release block */ 00278 ExFreePoolWithTag(Lock->Dbg.Blocks, Lock->Dbg.AllocateTag); 00279 } 00280 } 00281 00282 /* EOF */ Generated on Sat May 26 2012 04:36:10 for ReactOS by
1.7.6.1
|