Commit in reactos/subsys/win32k/objects on MAIN
gdiobj.c+133-291.78 -> 1.79
dump some statistics on the gdi handle table when it runs out of handles

reactos/subsys/win32k/objects
gdiobj.c 1.78 -> 1.79
diff -u -r1.78 -r1.79
--- gdiobj.c	17 Dec 2004 15:12:37 -0000	1.78
+++ gdiobj.c	18 Dec 2004 21:41:17 -0000	1.79
@@ -19,7 +19,7 @@
 /*
  * GDIOBJ.C - GDI object manipulation routines
  *
- * $Id: gdiobj.c,v 1.78 2004/12/17 15:12:37 navaraf Exp $
+ * $Id: gdiobj.c,v 1.79 2004/12/18 21:41:17 royce Exp $
  */
 #include <w32k.h>
 
@@ -53,7 +53,7 @@
 typedef struct _GDI_HANDLE_TABLE
 {
   PPAGED_LOOKASIDE_LIST LookasideLists;
-  
+
   SLIST_HEADER FreeEntriesHead;
   SLIST_ENTRY FreeEntries[((GDI_HANDLE_COUNT * sizeof(GDI_TABLE_ENTRY)) << 3) /
                           (sizeof(SLIST_ENTRY) << 3)];
@@ -126,7 +126,7 @@
   handleTable = ExAllocatePoolWithTag(NonPagedPool, sizeof(GDI_HANDLE_TABLE), TAG_GDIHNDTBLE);
   ASSERT( handleTable );
   RtlZeroMemory(handleTable, sizeof(GDI_HANDLE_TABLE));
-  
+
   /*
    * initialize the free entry cache
    */
@@ -209,6 +209,71 @@
   return 0;
 }
 
+#ifdef DBG
+
+static int leak_reported = 0;
+#define GDI_STACK_LEVELS 4
+static ULONG GDIHandleAllocator[GDI_STACK_LEVELS][GDI_HANDLE_COUNT];
+struct DbgOpenGDIHandle
+{
+	ULONG loc;
+	int count;
+};
+#define H 1024
+static struct DbgOpenGDIHandle h[H];
+
+void IntDumpHandleTable ( int which )
+{
+	int i, n = 0, j;
+
+	// step through GDI handle table and find out who our culprit is...
+	for ( i = RESERVE_ENTRIES_COUNT; i < GDI_HANDLE_COUNT; i++ )
+	{
+		for ( j = 0; j < n; j++ )
+		{
+			if ( GDIHandleAllocator[which][i] == h[j].loc )
+				break;
+		}
+		if ( j < H )
+		{
+			if ( j == n )
+			{
+				h[j].loc = GDIHandleAllocator[which][i];
+				h[j].count = 1;
+				n = n + 1;
+			}
+			else
+				h[j].count++;
+		}
+	}
+	// bubble sort time! weeeeee!!
+	for ( i = 0; i < n-1; i++ )
+	{
+		if ( h[i].count < h[i+1].count )
+		{
+			struct DbgOpenGDIHandle t;
+			t.loc = h[i+1].loc;
+			t.count = h[i+1].count;
+			h[i+1].loc = h[i].loc;
+			h[i+1].count = h[i].count;
+			j = i;
+			while ( j > 0 && h[j-1].count < t.count )
+				j--;
+			h[j] = t;
+		}
+	}
+	// print the first 30 offenders...
+	DbgPrint ( "Worst GDI Handle leak offenders - stack trace level %i (out of %i unique locations):\n", which, n );
+	for ( i = 0; i < 30 && i < n; i++ )
+	{
+		DbgPrint ( "\t" );
+		if ( !KeRosPrintAddress ( (PVOID)h[i].loc ) )
+			DbgPrint ( "<%X>", h[i].loc );
+		DbgPrint ( " (%i allocations)\n", h[i].count );
+	}
+}
+#endif//DBG
+
 /*!
  * Allocate memory for GDI object and return handle to it.
  *
@@ -269,14 +334,14 @@
       RtlZeroMemory(ObjectBody, GetObjectSize(ObjectType));
 
       TypeInfo = (ObjectType & 0xFFFF0000) | (ObjectType >> 16);
-      
+
       FreeEntry = InterlockedPopEntrySList(&HandleTable->FreeEntriesHead);
       if(FreeEntry != NULL)
       {
         LONG PrevProcId;
         UINT Index;
         HGDIOBJ Handle;
-        
+
         /* calculate the entry from the address of the entry in the free slot array */
         Index = ((ULONG_PTR)FreeEntry - (ULONG_PTR)&HandleTable->FreeEntries[0]) /
                 sizeof(HandleTable->FreeEntries[0]);
@@ -288,7 +353,7 @@
         if(PrevProcId == 0)
         {
           ASSERT(Entry->KernelData == NULL);
-          
+
           Entry->KernelData = ObjectBody;
 
           /* we found a free entry, no need to exchange this field atomically
@@ -298,6 +363,27 @@
           /* unlock the entry */
           InterlockedExchange(&Entry->ProcessId, CurrentProcessId);
 
+#ifdef DBG
+          {
+            PULONG Frame;
+			int which;
+#if defined __GNUC__
+            __asm__("mov %%ebp, %%ebx" : "=b" (Frame) : );
+#elif defined(_MSC_VER)
+            __asm mov [Frame], ebp
+#endif
+			Frame = (PULONG)Frame[0]; // step out of AllocObj()
+			for ( which = 0; which < GDI_STACK_LEVELS && Frame[1] != 0 && Frame[1] != 0xDEADBEEF; which++ )
+			{
+	            GDIHandleAllocator[which][Index] = Frame[1]; // step out of AllocObj()
+				Frame = ((PULONG)Frame[0]);
+			}
+			for ( ; which < GDI_STACK_LEVELS; which++ )
+				GDIHandleAllocator[which][Index] = 0xDEADBEEF;
+          }
+#endif//DBG
+          //ExAllocatePool ( PagedPool, (ULONG)newObject ); // initiate red-zone verification of object we allocated
+
           if(W32Process != NULL)
           {
             InterlockedIncrement(&W32Process->GDIObjects);
@@ -325,6 +411,20 @@
 
       ExFreeToPagedLookasideList(LookasideList, newObject);
       DPRINT1("Failed to insert gdi object into the handle table, no handles left!\n");
+#ifdef DBG
+	  if ( !leak_reported )
+	  {
+		  DPRINT1("reporting gdi handle abusers:\n");
+		  int which;
+		  for ( which = 0; which < GDI_STACK_LEVELS; which++ )
+		      IntDumpHandleTable(which);
+		  leak_reported = 1;
+	  }
+	  else
+	  {
+		  DPRINT1("gdi handle abusers already reported!\n");
+	  }
+#endif//DBG
     }
     else
     {
@@ -363,7 +463,7 @@
 #endif
 
   DPRINT("GDIOBJ_FreeObj: hObj: 0x%08x\n", hObj);
-  
+
   if(GDI_HANDLE_IS_STOCKOBJ(hObj))
   {
     DPRINT1("GDIOBJ_FreeObj() failed, can't delete stock object handle: 0x%x !!!\n", hObj);
@@ -403,14 +503,14 @@
         /* Clear the type field so when unlocking the handle it gets finally deleted */
         Entry->Type = 0;
         Entry->KernelData = NULL;
-        
+
         /* unlock the handle slot */
         InterlockedExchange(&Entry->ProcessId, 0);
-        
+
         /* push this entry to the free list */
         InterlockedPushEntrySList(&HandleTable->FreeEntriesHead,
                                   &HandleTable->FreeEntries[GDI_ENTRY_TO_INDEX(HandleTable, Entry)]);
-        
+
         if(W32Process != NULL)
         {
           InterlockedDecrement(&W32Process->GDIObjects);
@@ -433,7 +533,7 @@
         /* the object is currently locked. just clear the type field so when the
            object gets unlocked it will be finally deleted from the table. */
         Entry->Type = 0;
-        
+
         /* unlock the handle slot */
         InterlockedExchange(&Entry->ProcessId, 0);
 
@@ -680,7 +780,7 @@
 #endif
 
   DPRINT("GDIOBJ_LockObj: hObj: 0x%08x\n", hObj);
-  
+
   Thread = PsGetCurrentThread();
 
   /* shift the process id to the left so we can use the first bit to lock the object.
@@ -713,7 +813,7 @@
          that locked the object. There's no need to do this atomically as we're
          holding the lock of the handle slot, but this way it's easier ;) */
       PrevThread = InterlockedCompareExchangePointer(&GdiHdr->LockingThread, Thread, NULL);
-      
+
       if(PrevThread == NULL || PrevThread == Thread)
       {
         if(++GdiHdr->Locks == 1)
@@ -725,14 +825,14 @@
         }
 
         InterlockedExchange(&Entry->ProcessId, PrevProcId);
-        
+
         /* we're done, return the object body */
         return GDIHdrToBdy(GdiHdr);
       }
       else
       {
         InterlockedExchange(&Entry->ProcessId, PrevProcId);
-        
+
 #ifdef GDI_DEBUG
         if(++Attempts > 20)
         {
@@ -747,14 +847,16 @@
     else
     {
       InterlockedExchange(&Entry->ProcessId, PrevProcId);
-      
+
       if(EntryType == 0)
       {
         DPRINT1("Attempted to lock object 0x%x that is deleted!\n", hObj);
+        KeRosDumpStackFrames ( NULL, 20 );
       }
       else
       {
         DPRINT1("Attempted to lock object 0x%x, type mismatch (0x%x : 0x%x)\n", hObj, EntryType, ExpectedType);
+        KeRosDumpStackFrames ( NULL, 20 );
       }
 #ifdef GDI_DEBUG
       DPRINT1("-> called from %s:%i\n", file, line);
@@ -786,6 +888,7 @@
   else
   {
     DPRINT1("Attempted to lock foreign handle: 0x%x, Owner: 0x%x locked: 0x%x Caller: 0x%x, stockobj: 0x%x\n", hObj, PrevProcId >> 1, PrevProcId & 0x1, PsGetCurrentProcessId(), GDI_HANDLE_IS_STOCKOBJ(hObj));
+    KeRosDumpStackFrames ( NULL, 20 );
 #ifdef GDI_DEBUG
     DPRINT1("-> called from %s:%i\n", file, line);
 #endif
@@ -842,7 +945,8 @@
       PGDIOBJHDR GdiHdr;
 
       GdiHdr = GDIBdyToHdr(Entry->KernelData);
-      
+	  //ExAllocatePool ( PagedPool, (ULONG)GdiHdr ); // initiate red-zone validation on this block
+
       PrevThread = GdiHdr->LockingThread;
       if(PrevThread == Thread)
       {
@@ -851,33 +955,33 @@
         if(--GdiHdr->Locks == 0)
         {
           GdiHdr->LockingThread = NULL;
-          
+
 #ifdef GDI_DEBUG
           GdiHdr->lockfile = NULL;
           GdiHdr->lockline = 0;
 #endif
         }
-        
+
         if(Entry->Type == 0 && GdiHdr->Locks == 0)
         {
           PPAGED_LOOKASIDE_LIST LookasideList;
           PW32PROCESS W32Process = PsGetWin32Process();
           DWORD Type = GDI_HANDLE_GET_TYPE(hObj);
-          
+
           ASSERT(ProcessId != 0); /* must not delete a global handle!!!! */
-          
+
           /* we should delete the handle */
           Entry->KernelData = NULL;
           InterlockedExchange(&Entry->ProcessId, 0);
-          
+
           InterlockedPushEntrySList(&HandleTable->FreeEntriesHead,
                                     &HandleTable->FreeEntries[GDI_ENTRY_TO_INDEX(HandleTable, Entry)]);
-          
+
           if(W32Process != NULL)
           {
             InterlockedDecrement(&W32Process->GDIObjects);
           }
-          
+
           /* call the cleanup routine. */
           Ret = RunCleanupCallback(GDIHdrToBdy(GdiHdr), Type);
 
@@ -994,11 +1098,11 @@
 #ifdef GDI_DEBUG
   ULONG Attempts = 0;
 #endif
-  
+
   ASSERT(hObj);
 
   DPRINT("GDIOBJ_ConvertToStockObj: hObj: 0x%08x\n", *hObj);
-  
+
   Thread = PsGetCurrentThread();
 
   if(!GDI_HANDLE_IS_STOCKOBJ(*hObj))
@@ -1130,7 +1234,7 @@
 #endif
 
   DPRINT("GDIOBJ_SetOwnership: hObj: 0x%x, NewProcess: 0x%x\n", ObjectHandle, (NewOwner ? PsGetProcessId(NewOwner) : 0));
-  
+
   Thread = PsGetCurrentThread();
 
   if(!GDI_HANDLE_IS_STOCKOBJ(ObjectHandle))
@@ -1152,7 +1256,7 @@
       if(Entry->Type != 0 && Entry->KernelData != NULL)
       {
         PGDIOBJHDR GdiHdr = GDIBdyToHdr(Entry->KernelData);
-        
+
         PrevThread = GdiHdr->LockingThread;
         if(PrevThread == NULL || PrevThread == Thread)
         {
@@ -1265,7 +1369,7 @@
 #endif
 
   DPRINT("GDIOBJ_CopyOwnership: from: 0x%x, to: 0x%x\n", CopyFrom, CopyTo);
-  
+
   Thread = PsGetCurrentThread();
 
   if(!GDI_HANDLE_IS_STOCKOBJ(CopyFrom) && !GDI_HANDLE_IS_STOCKOBJ(CopyTo))
CVSspam 0.2.8