[dcom 2.1] Implement a typelib loader cache
Mike Hearn
mike at theoretic.com
Thu Aug 28 08:05:50 CDT 2003
This is a resend. The original seemed to be OK here, so it's enclosed
unmodified.
ChangeLog:
Implement a typelib loader cache
Index: dlls/oleaut32/typelib.c
===================================================================
RCS file: /home/wine/wine/dlls/oleaut32/typelib.c,v
retrieving revision 1.98
diff -u -r1.98 typelib.c
--- dlls/oleaut32/typelib.c 20 Aug 2003 18:22:32 -0000 1.98
+++ dlls/oleaut32/typelib.c 28 Aug 2003 13:00:25 -0000
@@ -287,6 +287,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)) {
@@ -653,6 +655,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;
@@ -1708,6 +1714,7 @@
recoffset += reclength;
}
}
+
static void MSFT_DoVars(TLBContext *pcx, ITypeInfoImpl *pTI, int cFuncs,
int cVars, int offset, TLBVarDesc ** pptvd)
{
@@ -1965,6 +1972,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
*
@@ -1983,6 +2006,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)
@@ -2054,11 +2091,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;
}
@@ -3197,7 +3257,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);
}
@@ -3214,8 +3274,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)
@@ -4448,6 +4515,7 @@
if (pFDesc->funcdesc.invkind & dwFlags)
break;
}
+
if (pFDesc) {
if (TRACE_ON(typelib)) dump_TLBFuncDescOne(pFDesc);
/* dump_FUNCDESC(&pFDesc->funcdesc);*/
@@ -4869,13 +4937,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