Implement typelib loader cache (take 2)

Mike Hearn mike at theoretic.com
Thu Aug 21 07:48:02 CDT 2003


This patch drops the separate cache structure, preferring pointers in
the ITypeLibImpl struct instead. It uses a critical section (grrr, i'll
get into the habit of thread safety eventually, bear with me). I tested
it a bit here, but haven't included any test cases.

ChangeLog:
Implement typelib loader cache



-------------- next part --------------
? typelib.patch
? dlls/kernel/system.spec.c
Index: dlls/oleaut32/typelib.c
===================================================================
RCS file: /home/wine/wine/dlls/oleaut32/typelib.c,v
retrieving revision 1.97
diff -u -r1.97 typelib.c
--- dlls/oleaut32/typelib.c	27 Jun 2003 19:40:03 -0000	1.97
+++ dlls/oleaut32/typelib.c	21 Aug 2003 12:42:04 -0000
@@ -286,6 +286,8 @@
     INT index = 1;
 
     TRACE("(%s,%d,%p)\n",debugstr_w(szFile), regkind, pptLib);
+    
+    *pptLib = NULL;
     if(!SearchPathW(NULL,szFile,NULL,sizeof(szPath)/sizeof(WCHAR),szPath,
 		    NULL)) {
 
@@ -652,6 +654,10 @@
     TYPEDESC * pTypeDesc;       /* array of TypeDescriptions found in the
 				   libary. Only used while read MSFT
 				   typelibs */
+
+    /* typelibs are cached, keyed by path, so store the linked list info within them */
+    struct tagITypeLibImpl *next, *prev;
+    WCHAR *path;
 } ITypeLibImpl;
 
 static struct ICOM_VTABLE(ITypeLib2) tlbvt;
@@ -1707,6 +1713,7 @@
         recoffset += reclength;
     }
 }
+
 static void MSFT_DoVars(TLBContext *pcx, ITypeInfoImpl *pTI, int cFuncs,
 		       int cVars, int offset, TLBVarDesc ** pptvd)
 {
@@ -1964,6 +1971,22 @@
     return ptiRet;
 }
 
+/* Because type library parsing has some degree of overhead, and some apps repeatedly load the same
+ * typelibs over and over, we cache them here. According to MSDN Microsoft have a similar scheme in
+ * place. This will cause a deliberate memory leak, but generally losing RAM for cycles is an acceptable
+ * tradeoff here.
+ */
+ITypeLibImpl *tlb_cache_tail = NULL;
+static CRITICAL_SECTION cache_section;
+static CRITICAL_SECTION_DEBUG cache_section_debug =
+{
+    0, 0, &cache_section,
+    { &cache_section_debug.ProcessLocksList, &cache_section_debug.ProcessLocksList },
+      0, 0, { 0, (DWORD)(__FILE__ ": typelib loader cache") }
+};
+static CRITICAL_SECTION cache_section = { &cache_section_debug, -1, 0, 0, 0, 0 };
+
+
 /****************************************************************************
  *	TLB_ReadTypeLib
  *
@@ -1982,6 +2005,20 @@
 
     *ppTypeLib = NULL;
 
+    /* We look the path up in the typelib cache. If found, we just addref it, and return the pointer. */
+    EnterCriticalSection(&cache_section);
+    if (tlb_cache_tail) {
+	ITypeLibImpl *entry;
+	for (entry = tlb_cache_tail; entry != NULL; entry = entry->next)
+	    if (!strcmpiW(entry->path, pszFileName)) {
+		TRACE("cache hit\n");
+		*ppTypeLib = (ITypeLib2*)entry;
+		ITypeLib_AddRef(*ppTypeLib);
+		return S_OK;
+	    }
+    }
+    LeaveCriticalSection(&cache_section);
+    
     /* check the signature of the file */
     hFile = CreateFileW( pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
     if (INVALID_HANDLE_VALUE != hFile)
@@ -2053,11 +2090,34 @@
       }
     }
 
-    if(*ppTypeLib)
+    if(*ppTypeLib) {
+	ITypeLibImpl *impl = (ITypeLibImpl*)*ppTypeLib;
+	
+	TRACE("adding to cache\n");
+	EnterCriticalSection(&cache_section);
+	impl->path = HeapAlloc(GetProcessHeap(), 0, MAX_PATH); /* is MAX_PATH chars unicode safe? */
+	lstrcpyW(impl->path, pszFileName);
+	/* We should really canonicalise the path here. */
+	
+	if (!tlb_cache_tail) {
+	    /* this is the first typelib loaded */
+	    tlb_cache_tail = (ITypeLibImpl*)*ppTypeLib;
+	    tlb_cache_tail->next = NULL;
+	    tlb_cache_tail->prev = NULL;
+	} else {
+	    ITypeLibImpl *tlb_cache_head = tlb_cache_tail;
+	    
+	    /* locate the head of the list */
+	    while (tlb_cache_head->next != NULL)
+		tlb_cache_head = tlb_cache_head->next;
+	    
+	    tlb_cache_head->next = (ITypeLibImpl*)*ppTypeLib;
+	    tlb_cache_head->next->prev = tlb_cache_head;
+	}
+	LeaveCriticalSection(&cache_section);
       ret = S_OK;
-    else
-      ERR("Loading of typelib %s failed with error %ld\n",
-	  debugstr_w(pszFileName), GetLastError());
+    } else
+	ERR("Loading of typelib %s failed with error %ld\n", debugstr_w(pszFileName), GetLastError());
 
     return ret;
 }
@@ -3196,7 +3256,7 @@
 {
     ICOM_THIS( ITypeLibImpl, iface);
 
-    TRACE("(%p)->ref is %u\n",This, This->ref);
+    TRACE("(%p)->ref was %u\n",This, This->ref);
 
     return ++(This->ref);
 }
@@ -3213,8 +3273,15 @@
 
     if (!This->ref)
     {
-      /* FIXME destroy child objects */
+      /* remove cache entry */
+      TRACE("removing from cache list\n");
+      EnterCriticalSection(&cache_section);
+      if (This->next) This->next->prev = This->prev;
+      if (This->prev) This->prev->next = This->next;
+      if (This == tlb_cache_tail) tlb_cache_tail = NULL;
+      LeaveCriticalSection(&cache_section);
 
+      /* FIXME destroy child objects */
       TRACE(" destroying ITypeLib(%p)\n",This);
 
       if (This->Name)
@@ -4447,6 +4514,7 @@
 	    if (pFDesc->funcdesc.invkind & dwFlags)
 		break;
 	}
+    
     if (pFDesc) {
 	if (TRACE_ON(typelib)) dump_TLBFuncDescOne(pFDesc);
 	/* dump_FUNCDESC(&pFDesc->funcdesc);*/
@@ -4868,13 +4936,13 @@
     /* If a pointer is null, we simply ignore it, the ATL in particular passes pIndex as 0 */
     if (pIndex) {
       *pIndex=This->index;
-      TRACE("returning pIndex=%d", *pIndex);
+      TRACE("returning pIndex=%d\n", *pIndex);
     }
     
     if (ppTLib) {
       *ppTLib=(LPTYPELIB )(This->pTypeLib);
       ITypeLib2_AddRef(*ppTLib);
-      TRACE("returning ppTLib=%p", *ppTLib);
+      TRACE("returning ppTLib=%p\n", *ppTLib);
     }
     
     return S_OK;


More information about the wine-patches mailing list