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