Allocate memory for the handle table from paged pool!
[reactos.git] / reactos / subsys / win32k / objects / gdiobj.c
index e058cac..149680d 100644 (file)
 /*
  * GDIOBJ.C - GDI object manipulation routines
  *
- * $Id: gdiobj.c,v 1.54 2003/12/14 19:39:50 gvg Exp $
+ * $Id: gdiobj.c,v 1.73 2004/10/02 16:48:12 navaraf Exp $
  *
  */
+#include <w32k.h>
 
-#undef WIN32_LEAN_AND_MEAN
-#define WIN32_NO_STATUS
-#include <windows.h>
-#include <ddk/ntddk.h>
-#include <include/dce.h>
-#include <include/object.h>
-#include <win32k/gdiobj.h>
-#include <win32k/brush.h>
-#include <win32k/pen.h>
-#include <win32k/text.h>
-#include <win32k/dc.h>
-#include <win32k/bitmaps.h>
-#include <win32k/region.h>
-#include <win32k/cursoricon.h>
-#include <include/palette.h>
-#include <include/intgdi.h>
-#define NDEBUG
-#include <win32k/debug1.h>
+/* count all gdi objects */
+#define GDI_COUNT_OBJECTS 1
 
 /*! Size of the GDI handle table
  * http://www.windevnet.com/documents/s=7290/wdj9902b/9902b.htm
 
 typedef struct _GDI_HANDLE_TABLE
 {
-  WORD  wTableSize;
+  WORD wTableSize;
+  WORD AllocationHint;
+  #if GDI_COUNT_OBJECTS
+  ULONG HandlesCount;
+  #endif
+  PPAGED_LOOKASIDE_LIST LookasideLists;
   PGDIOBJHDR Handles[1];
 } GDI_HANDLE_TABLE, *PGDI_HANDLE_TABLE;
 
+typedef struct
+{
+  ULONG Type;
+  ULONG Size;
+} GDI_OBJ_SIZE;
+
+const
+GDI_OBJ_SIZE ObjSizes[] =
+{
+  /* Testing shows that regions are the most used GDIObj type,
+     so put that one first for performance */
+  {GDI_OBJECT_TYPE_REGION,      sizeof(ROSRGNDATA)},
+  {GDI_OBJECT_TYPE_BITMAP,      sizeof(BITMAPOBJ)},
+  {GDI_OBJECT_TYPE_DC,          sizeof(DC)},
+  {GDI_OBJECT_TYPE_PALETTE,     sizeof(PALGDI)},
+  {GDI_OBJECT_TYPE_BRUSH,       sizeof(GDIBRUSHOBJ)},
+  {GDI_OBJECT_TYPE_PEN,         sizeof(GDIBRUSHOBJ)},
+  {GDI_OBJECT_TYPE_FONT,        sizeof(TEXTOBJ)},
+  {GDI_OBJECT_TYPE_DCE,         sizeof(DCE)},
+/*
+  {GDI_OBJECT_TYPE_DIRECTDRAW,  sizeof(DD_DIRECTDRAW)},
+  {GDI_OBJECT_TYPE_DD_SURFACE,  sizeof(DD_SURFACE)},
+*/
+  {GDI_OBJECT_TYPE_EXTPEN,      0},
+  {GDI_OBJECT_TYPE_METADC,      0},
+  {GDI_OBJECT_TYPE_METAFILE,    0},
+  {GDI_OBJECT_TYPE_ENHMETAFILE, 0},
+  {GDI_OBJECT_TYPE_ENHMETADC,   0},
+  {GDI_OBJECT_TYPE_MEMDC,       0},
+  {GDI_OBJECT_TYPE_EMF,         0}
+};
+
+#define OBJTYPE_COUNT (sizeof(ObjSizes) / sizeof(ObjSizes[0]))
+
 /*  GDI stock objects */
 
 static LOGBRUSH WhiteBrush =
@@ -120,40 +144,41 @@ static LOGPEN NullPen =
 { PS_NULL, { 0, 0 }, 0 };
 
 static LOGFONTW OEMFixedFont =
-{ 14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, OEM_CHARSET,
-  0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, L"" };
+{ 11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, OEM_CHARSET,
+  0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, L"Bitstream Vera Sans Mono" };
 
 static LOGFONTW AnsiFixedFont =
-{ 14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
-  0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, L"" };
+{ 11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
+  0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, L"Bitstream Vera Sans Mono" };
 
 /*static LOGFONTW AnsiVarFont =
- *{ 14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
+ *{ 10, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
  *  0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, L"MS Sans Serif" }; */
 
 static LOGFONTW SystemFont =
-{ 14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
-  0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, L"System" };
+{ 11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
+  0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, L"Bitstream Vera Sans" };
 
 static LOGFONTW DeviceDefaultFont =
-{ 14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
-  0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, L"" };
+{ 11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
+  0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, L"Bitstream Vera Sans" };
 
 static LOGFONTW SystemFixedFont =
-{ 14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
-  0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, L"" };
+{ 11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
+  0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, L"Bitstream Vera Sans Mono" };
 
 /* FIXME: Is this correct? */
 static LOGFONTW DefaultGuiFont =
-{ 14, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
-  0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, L"MS Sans Serif" };
+{ 11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
+  0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, L"Bitstream Vera Sans" };
 
 #define NB_STOCK_OBJECTS (DEFAULT_GUI_FONT + 1)
 
-static HGDIOBJ *StockObjects[NB_STOCK_OBJECTS];
+static HGDIOBJ StockObjects[NB_STOCK_OBJECTS];
 static PGDI_HANDLE_TABLE  HandleTable = 0;
 static FAST_MUTEX  HandleTableMutex;
 static FAST_MUTEX  RefCountHandling;
+static LARGE_INTEGER  ShortDelay;
 
 /*!
  * Allocate GDI object table.
@@ -164,20 +189,35 @@ static PGDI_HANDLE_TABLE FASTCALL
 GDIOBJ_iAllocHandleTable (WORD Size)
 {
   PGDI_HANDLE_TABLE  handleTable;
+  ULONG MemSize;
+  UINT ObjType;
+  
+  MemSize = sizeof(GDI_HANDLE_TABLE) + sizeof(PGDIOBJ) * Size;
 
-  /* prevent APC delivery for the *FastMutexUnsafe calls */
-  const KIRQL PrevIrql = KfRaiseIrql(APC_LEVEL);
-  ExAcquireFastMutexUnsafe (&HandleTableMutex);
-  handleTable = ExAllocatePool(PagedPool,
-                               sizeof(GDI_HANDLE_TABLE) +
-                               sizeof(PGDIOBJ) * Size);
+  ExAcquireFastMutex(&HandleTableMutex);
+  handleTable = ExAllocatePoolWithTag(PagedPool, MemSize, TAG_GDIHNDTBLE);
   ASSERT( handleTable );
-  memset (handleTable,
-          0,
-          sizeof(GDI_HANDLE_TABLE) + sizeof(PGDIOBJ) * Size);
+  memset (handleTable, 0, MemSize);
+#if GDI_COUNT_OBJECTS
+  handleTable->HandlesCount = 0;
+#endif
   handleTable->wTableSize = Size;
-  ExReleaseFastMutexUnsafe (&HandleTableMutex);
-  KfLowerIrql(PrevIrql);
+  handleTable->AllocationHint = 1;
+  handleTable->LookasideLists = ExAllocatePoolWithTag(PagedPool,
+                                                      OBJTYPE_COUNT * sizeof(PAGED_LOOKASIDE_LIST),
+                                                      TAG_GDIHNDTBLE);
+  if (NULL == handleTable->LookasideLists)
+    {
+      ExFreePool(handleTable);
+      ExReleaseFastMutex(&HandleTableMutex);
+      return NULL;
+    }
+  for (ObjType = 0; ObjType < OBJTYPE_COUNT; ObjType++)
+    {
+      ExInitializePagedLookasideList(handleTable->LookasideLists + ObjType, NULL, NULL, 0,
+                                     ObjSizes[ObjType].Size + sizeof(GDIOBJHDR), TAG_GDIOBJ, 0);
+    }
+  ExReleaseFastMutex(&HandleTableMutex);
 
   return handleTable;
 }
@@ -204,17 +244,49 @@ GDIOBJ_iGetObjectForIndex(WORD TableIndex)
 static WORD FASTCALL
 GDIOBJ_iGetNextOpenHandleIndex (void)
 {
-  WORD tableIndex;
+   WORD tableIndex;
+
+   for (tableIndex = HandleTable->AllocationHint;
+        tableIndex < HandleTable->wTableSize;
+        tableIndex++)
+   {
+      if (HandleTable->Handles[tableIndex] == NULL)
+      {
+         HandleTable->AllocationHint = tableIndex + 1;
+         return tableIndex;
+      }
+   }
+
+   for (tableIndex = 1;
+        tableIndex < HandleTable->AllocationHint;
+        tableIndex++)
+   {
+      if (HandleTable->Handles[tableIndex] == NULL)
+      {
+         HandleTable->AllocationHint = tableIndex + 1;
+         return tableIndex;
+      }
+   }
+
+   return 0;
+}
 
-  for (tableIndex = 1; tableIndex < HandleTable->wTableSize; tableIndex++)
+static PPAGED_LOOKASIDE_LIST FASTCALL
+FindLookasideList(DWORD ObjectType)
+{
+  int Index;
+
+  for (Index = 0; Index < OBJTYPE_COUNT; Index++)
     {
-      if (NULL == HandleTable->Handles[tableIndex])
-       {
-         break;
-       }
+      if (ObjSizes[Index].Type == ObjectType)
+        {
+          return HandleTable->LookasideLists + Index;
+        }
     }
 
-  return (tableIndex < HandleTable->wTableSize) ? tableIndex : 0;
+  DPRINT1("Can't find lookaside list for object type 0x%08x\n", ObjectType);
+
+  return NULL;
 }
 
 /*!
@@ -235,22 +307,30 @@ GDIOBJ_AllocObj(WORD Size, DWORD ObjectType, GDICLEANUPPROC CleanupProc)
   PW32PROCESS W32Process;
   PGDIOBJHDR  newObject;
   WORD Index;
-  
+  PPAGED_LOOKASIDE_LIST LookasideList;
+
   ExAcquireFastMutex(&HandleTableMutex);
   Index = GDIOBJ_iGetNextOpenHandleIndex ();
   if (0 == Index)
     {
+      ExReleaseFastMutex(&HandleTableMutex);
       DPRINT1("Out of GDI handles\n");
       return NULL;
     }
 
-  DPRINT("GDIOBJ_AllocObj: handle: %d, size: %d, type: 0x%08x\n", Index, Size, ObjectType);
-  newObject = ExAllocatePool(PagedPool, Size + sizeof (GDIOBJHDR));
-  if (newObject == NULL)
-  {
-    DPRINT1("GDIOBJ_AllocObj: failed\n");
-    return NULL;
-  }
+  LookasideList = FindLookasideList(ObjectType);
+  if (NULL == LookasideList)
+    {
+      ExReleaseFastMutex(&HandleTableMutex);
+      return NULL;
+    }
+  newObject = ExAllocateFromPagedLookasideList(LookasideList);
+  if (NULL == newObject)
+    {
+      ExReleaseFastMutex(&HandleTableMutex);
+      DPRINT1("Unable to allocate GDI object from lookaside list\n");
+      return NULL;
+    }
   RtlZeroMemory (newObject, Size + sizeof(GDIOBJHDR));
 
   newObject->wTableIndex = Index;
@@ -261,9 +341,18 @@ GDIOBJ_AllocObj(WORD Size, DWORD ObjectType, GDICLEANUPPROC CleanupProc)
   newObject->Magic = GDI_TYPE_TO_MAGIC(ObjectType);
   newObject->lockfile = NULL;
   newObject->lockline = 0;
+#ifdef GDIOBJ_USE_FASTMUTEX
   ExInitializeFastMutex(&newObject->Lock);
+  newObject->RecursiveLockCount = 0;
+#else
+  newObject->LockTid = 0;
+  newObject->LockCount = 0;
+#endif
   HandleTable->Handles[Index] = newObject;
-  ExReleaseFastMutexUnsafe (&HandleTableMutex);
+#if GDI_COUNT_OBJECTS
+  HandleTable->HandlesCount++;
+#endif
+  ExReleaseFastMutex(&HandleTableMutex);
   
   W32Process = PsGetCurrentProcess()->Win32Process;
   if(W32Process)
@@ -295,6 +384,7 @@ GDIOBJ_FreeObj(HGDIOBJ hObj, DWORD ObjectType, DWORD Flag)
   PW32PROCESS W32Process;
   PGDIOBJHDR objectHeader;
   PGDIOBJ Obj;
+  PPAGED_LOOKASIDE_LIST LookasideList;
   BOOL         bRet = TRUE;
 
   objectHeader = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(hObj));
@@ -330,9 +420,17 @@ GDIOBJ_FreeObj(HGDIOBJ hObj, DWORD ObjectType, DWORD Flag)
       Obj = (PGDIOBJ)((PCHAR)objectHeader + sizeof(GDIOBJHDR));
       bRet = (*(objectHeader->CleanupProc))(Obj);
     }
-
-  ExFreePool(objectHeader);
+  LookasideList = FindLookasideList(GDI_MAGIC_TO_TYPE(objectHeader->Magic));
+  if (NULL != LookasideList)
+    {
+      ExFreeToPagedLookasideList(LookasideList, objectHeader);
+    }
+  ExAcquireFastMutexUnsafe (&HandleTableMutex);
   HandleTable->Handles[GDI_HANDLE_GET_INDEX(hObj)] = NULL;
+#if GDI_COUNT_OBJECTS
+  HandleTable->HandlesCount--;
+#endif
+  ExReleaseFastMutexUnsafe (&HandleTableMutex);
   
   W32Process = PsGetCurrentProcess()->Win32Process;
   if(W32Process)
@@ -455,6 +553,8 @@ InitGdiObjectHandleTable (VOID)
   ExInitializeFastMutex (&HandleTableMutex);
   ExInitializeFastMutex (&RefCountHandling);
 
+  ShortDelay.QuadPart = -100;
+
   HandleTable = GDIOBJ_iAllocHandleTable (GDI_HANDLE_COUNT);
   DPRINT("HandleTable: %x\n", HandleTable );
 
@@ -528,7 +628,8 @@ NtGdiDeleteObject(HGDIOBJ hObject)
 {
   DPRINT("NtGdiDeleteObject handle 0x%08x\n", hObject);
 
-  return GDIOBJ_FreeObj(hObject, GDI_OBJECT_TYPE_DONTCARE, GDIOBJFLAG_DEFAULT);
+  return NULL != hObject
+         ? GDIOBJ_FreeObj(hObject, GDI_OBJECT_TYPE_DONTCARE, GDIOBJFLAG_DEFAULT) : FALSE;
 }
 
 /*!
@@ -580,6 +681,9 @@ PGDIOBJ FASTCALL
 GDIOBJ_LockObjDbg (const char* file, int line, HGDIOBJ hObj, DWORD ObjectType)
 {
   PGDIOBJHDR ObjHdr = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(hObj));
+#ifndef GDIOBJ_USE_FASTMUTEX
+  DWORD CurrentTid = (DWORD)PsGetCurrentThreadId();
+#endif
 
   DPRINT("(%s:%i) GDIOBJ_LockObjDbg(0x%08x,0x%08x)\n", file, line, hObj, ObjectType);
   if (! GDI_VALID_OBJECT(hObj, ObjHdr, ObjectType, GDIOBJFLAG_DEFAULT))
@@ -608,17 +712,48 @@ GDIOBJ_LockObjDbg (const char* file, int line, HGDIOBJ hObj, DWORD ObjectType)
       return NULL;
     }
 
-  if (! ExTryToAcquireFastMutex(&ObjHdr->Lock))
+#ifdef GDIOBJ_USE_FASTMUTEX
+  if (ObjHdr->Lock.Owner == KeGetCurrentThread())
     {
-      DPRINT1("Caution! GDIOBJ_LockObj trying to lock object 0x%x second time\n", hObj);
-      DPRINT1("  called from: %s:%i\n", file, line);
-      if (NULL != ObjHdr->lockfile)
+      ObjHdr->RecursiveLockCount++;
+    }
+  else
+    {
+#ifdef NDEBUG    
+      ExAcquireFastMutex(&ObjHdr->Lock);
+#else /* NDEBUG */
+      if (! ExTryToAcquireFastMutex(&ObjHdr->Lock))
         {
-          DPRINT1("  previously locked from: %s:%i\n", ObjHdr->lockfile, ObjHdr->lockline);
+          DPRINT1("Caution! GDIOBJ_LockObj trying to lock object 0x%x second time\n", hObj);
+          DPRINT1("  called from: %s:%i (thread %x)\n", file, line, KeGetCurrentThread());
+          if (NULL != ObjHdr->lockfile)
+            {
+              DPRINT1("  previously locked from: %s:%i (thread %x)\n", ObjHdr->lockfile, ObjHdr->lockline, ObjHdr->Lock.Owner);
+            }
+          ExAcquireFastMutex(&ObjHdr->Lock);
+          DPRINT1("  Disregard previous message about object 0x%x, it's ok\n", hObj);
         }
-      ExAcquireFastMutex(&ObjHdr->Lock);
-      DPRINT1("  Disregard previous message about object 0x%x, it's ok\n", hObj);
+#endif /* NDEBUG */
+      ObjHdr->RecursiveLockCount++;
     }
+#else
+  if (ObjHdr->LockTid == CurrentTid)
+    {
+      InterlockedIncrement(&ObjHdr->LockCount);
+    }
+  else
+    {
+      for (;;)
+        {
+          if (InterlockedCompareExchange(&ObjHdr->LockTid, CurrentTid, 0) == CurrentTid)
+            {
+              InterlockedIncrement(&ObjHdr->LockCount);
+              break;
+            }
+          /* FIXME: KeDelayExecutionThread(KernelMode, FALSE, &ShortDelay); */
+        }
+    }
+#endif
 
   ExAcquireFastMutex(&RefCountHandling);
   ObjHdr->dwCount++;
@@ -671,6 +806,9 @@ PGDIOBJ FASTCALL
 GDIOBJ_LockObj(HGDIOBJ hObj, DWORD ObjectType)
 {
   PGDIOBJHDR ObjHdr = GDIOBJ_iGetObjectForIndex(GDI_HANDLE_GET_INDEX(hObj));
+#ifndef GDIOBJ_USE_FASTMUTEX
+  DWORD CurrentTid = (DWORD)PsGetCurrentThreadId();
+#endif
 
   DPRINT("GDIOBJ_LockObj: hObj: 0x%08x, type: 0x%08x, objhdr: %x\n", hObj, ObjectType, ObjHdr);
   if (! GDI_VALID_OBJECT(hObj, ObjHdr, ObjectType, GDIOBJFLAG_DEFAULT))
@@ -680,7 +818,34 @@ GDIOBJ_LockObj(HGDIOBJ hObj, DWORD ObjectType)
       return NULL;
     }
 
-  ExAcquireFastMutex(&ObjHdr->Lock);
+#ifdef GDIOBJ_USE_FASTMUTEX
+  if (ObjHdr->Lock.Owner == KeGetCurrentThread())
+    {
+      ObjHdr->RecursiveLockCount++;
+    }
+  else
+    {
+      ExAcquireFastMutex(&ObjHdr->Lock);
+      ObjHdr->RecursiveLockCount++;
+    }
+#else
+  if (ObjHdr->LockTid == CurrentTid)
+    {
+      InterlockedIncrement(&ObjHdr->LockCount);
+    }
+  else
+    {
+      for (;;)
+        {
+          if (InterlockedCompareExchange(&ObjHdr->LockTid, CurrentTid, 0) == CurrentTid)
+            {
+              InterlockedIncrement(&ObjHdr->LockCount);
+              break;
+            }
+          /* FIXME: KeDelayExecutionThread(KernelMode, FALSE, &ShortDelay); */
+        }
+    }
+#endif
 
   ExAcquireFastMutex(&RefCountHandling);
   ObjHdr->dwCount++;
@@ -713,7 +878,15 @@ GDIOBJ_UnlockObj(HGDIOBJ hObj, DWORD ObjectType)
     return FALSE;
   }
 
-  ExReleaseFastMutex(&ObjHdr->Lock);
+#ifdef GDIOBJ_USE_FASTMUTEX
+  if (--ObjHdr->RecursiveLockCount == 0)
+    ExReleaseFastMutex(&ObjHdr->Lock);
+#else
+  if (InterlockedDecrement(&ObjHdr->LockCount) == 0)
+    {
+      InterlockedExchange(&ObjHdr->LockTid, 0);
+    }
+#endif
 
   ExAcquireFastMutex(&RefCountHandling);
   if (0 == (ObjHdr->dwCount & ~0x80000000))