ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

remlock.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.