From 9c7afd4d329f0d506e18653328e3b841dfab76dc Mon Sep 17 00:00:00 2001 From: "dp%netscape.com" Date: Tue, 9 Feb 1999 20:31:24 +0000 Subject: [PATCH] Major repository upgrade to use a presistent regitry. We use libreg/ directly (NR_*() functions) for now. --- xpcom/components/nsRepository.cpp | 626 +++++++++++++++++++++++------- xpcom/src/nsRepository.cpp | 626 +++++++++++++++++++++++------- 2 files changed, 972 insertions(+), 280 deletions(-) diff --git a/xpcom/components/nsRepository.cpp b/xpcom/components/nsRepository.cpp index e07c7303519d..c060232f82f7 100644 --- a/xpcom/components/nsRepository.cpp +++ b/xpcom/components/nsRepository.cpp @@ -28,6 +28,7 @@ #include "plstr.h" #include "prlink.h" #include "prsystem.h" +#include "prprf.h" #include "nsRepository.h" #ifdef USE_NSREG @@ -50,65 +51,131 @@ nsHashtable *nsRepository::factories = NULL; PRMonitor *nsRepository::monitor = NULL; + +/** + * dllStore + * + * The dllStore maintains a collection of dlls that are hashed by the dll + * name. The repository uses the DllStore only to store these dlls: + * + * 1. dlls that store components in them. + * The inmemory nsDll that is stored here always reflects the values of + * {lastModTime, fileSize} that are stored in the registry. + * It is the job of the autoregistration mechanism to do the right + * thing if the dll on disk is newer. + * 2. dlls that dont store components in them. + * This is for the purpose of the autoregistration mechanism only. + * These are marked in the registry too so that unless they change + * they wont have to loaded every session. + * + */ nsDllStore *nsRepository::dllStore = NULL; static PRLogModuleInfo *logmodule = NULL; static NS_DEFINE_IID(kFactory2IID, NS_IFACTORY2_IID); +/***************************************************************************/ + +/** + * Class: FactoryEntry() + * + * There are two types of FactoryEntries. + * + * 1. {CID, dll} mapping. + * Factory is a consequence of the dll. These can be either session + * specific or persistent based on whether we write this + * to the registry or not. + * + * 2. {CID, factory} mapping + * These are strictly session specific and in memory only. + */ + class FactoryEntry { public: nsCID cid; nsIFactory *factory; - + + FactoryEntry(const nsCID &aClass, const char *aLibrary, + PRTime lastModTime, PRUint64 fileSize); + FactoryEntry(const nsCID &aClass, nsIFactory *aFactory); + ~FactoryEntry(); // DO NOT DELETE THIS. Many FactoryEntry(s) could be sharing the same Dll. // This gets deleted from the dllStore going away. nsDll *dll; - FactoryEntry(const nsCID &aClass, nsIFactory *aFactory, - const char *aLibrary) - : cid(aClass), factory(aFactory), dll(NULL) +}; + +FactoryEntry::FactoryEntry(const nsCID &aClass, const char *aLibrary, + PRTime lastModTime, PRUint64 fileSize) + : cid(aClass), factory(NULL), dll(NULL) +{ + nsDllStore *dllCollection = nsRepository::dllStore; + + if (aLibrary == NULL) { - nsDllStore *dllCollection = nsRepository::dllStore; - - if (aLibrary == NULL) - { - return; - } - - // If dll not already in dllCollection, add it. - // PR_EnterMonitor(nsRepository::monitor); - dll = dllCollection->Get(aLibrary); - // PR_ExitMonitor(nsRepository::monitor); - - if (dll == NULL) - { - // Add a new Dll into the nsDllStore - dll = new nsDll(aLibrary); - if (dll->GetStatus() != DLL_OK) - { - // Cant create a nsDll. Backoff. - delete dll; - dll = NULL; - } - else - { - // PR_EnterMonitor(nsRepository::monitor); - dllCollection->Put(aLibrary, dll); - // PR_ExitMonitor(nsRepository::monitor); - } - } + return; } - ~FactoryEntry(void) + // If dll not already in dllCollection, add it. + // PR_EnterMonitor(nsRepository::monitor); + dll = dllCollection->Get(aLibrary); + // PR_ExitMonitor(nsRepository::monitor); + + if (dll == NULL) { - if (factory != NULL) + PR_LOG(logmodule, PR_LOG_ALWAYS, + ("nsRepository: New dll \"%s\".", aLibrary)); + + // Add a new Dll into the nsDllStore + dll = new nsDll(aLibrary, lastModTime, fileSize); + if (dll->GetStatus() != DLL_OK) { - factory->Release(); + // Cant create a nsDll. Backoff. + PR_LOG(logmodule, PR_LOG_ALWAYS, + ("nsRepository: New dll status error. \"%s\".", aLibrary)); + delete dll; + dll = NULL; + } + else + { + PR_LOG(logmodule, PR_LOG_ALWAYS, + ("nsRepository: Adding New dll \"%s\" to dllStore.", + aLibrary)); + + // PR_EnterMonitor(nsRepository::monitor); + dllCollection->Put(aLibrary, dll); + // PR_ExitMonitor(nsRepository::monitor); } - // DO NOT DELETE nsDll *dll; } -}; + else + { + PR_LOG(logmodule, PR_LOG_ALWAYS, + ("nsRepository: Found in dllStore \"%s\".", aLibrary)); + // XXX We found the dll in the dllCollection. + // XXX Consistency check: dll needs to have the same + // XXX lastModTime and fileSize. If not that would mean + // XXX that the dll wasn't registered properly. + } +} + + +FactoryEntry::FactoryEntry(const nsCID &aClass, nsIFactory *aFactory) + : cid(aClass), factory(aFactory), dll(NULL) +{ +} + + +FactoryEntry::~FactoryEntry(void) +{ + if (factory != NULL) + { + factory->Release(); + } + // DO NOT DELETE nsDll *dll; +} + +/***************************************************************************/ class IDKey: public nsHashKey { private: @@ -127,75 +194,315 @@ public: nsHashKey *Clone(void) const { return new IDKey(id); } }; +/***************************************************************************/ + #ifdef USE_NSREG #define USE_REGISTRY -static nsresult platformRegister(const nsCID &aCID, const char *aLibrary) +static nsDll *platformCreateDll(const char *fullname) { HREG hreg; REGERR err = NR_RegOpen(NULL, &hreg); - if (err == REGERR_OK) + + if (err != REGERR_OK) { - RKEY key; - err = NR_RegAddKey(hreg, ROOTKEY_COMMON, - "Classes", &key); - if (err == REGERR_OK) - { - char *cidString = aCID.ToString(); - err = NR_RegSetEntryString(hreg, key, cidString, (char *) aLibrary); - delete [] cidString; - } - NR_RegClose(hreg); + return (NULL); } + RKEY xpcomKey; + if (NR_RegAddKey(hreg, ROOTKEY_COMMON, "Software/Netscape/XPCOM", &xpcomKey) != REGERR_OK) + { + NR_RegClose(hreg); + return (NULL); + } + + RKEY key; + err = NR_RegGetKey(hreg, xpcomKey, (char *)fullname, &key); + if (err != REGERR_OK) + { + return (NULL); + } + + PRTime lastModTime = LL_ZERO; + PRUint64 fileSize = LL_ZERO; + uint32 n = sizeof(lastModTime); + NR_RegGetEntry(hreg, key, "LastModTimeStamp", &lastModTime, &n); + n = sizeof(fileSize); + NR_RegGetEntry(hreg, key, "FileSize", &fileSize, &n); + + nsDll *dll = new nsDll(fullname, lastModTime, fileSize); + + return (dll); +} + +/** + * platformMarkNoComponents(nsDll) + * + * Stores the dll name, last modified time, size and 0 for number of + * components in dll in the registry at location + * ROOTKEY_COMMON/Software/Netscape/XPCOM/dllname + */ +static nsresult platformMarkNoComponents(nsDll *dll) +{ + HREG hreg; + REGERR err = NR_RegOpen(NULL, &hreg); + + if (err != REGERR_OK) + { + return (NS_ERROR_FAILURE); + } + + // XXX Gross. LongLongs dont have a serialization format. This makes + // XXX the registry non-xp. Someone beat on the nspr people to get + // XXX a longlong serialization function please! + RKEY xpcomKey; + if (NR_RegAddKey(hreg, ROOTKEY_COMMON, "Software/Netscape/XPCOM", &xpcomKey) != REGERR_OK) + { + NR_RegClose(hreg); + return (NS_ERROR_FAILURE); + } + + RKEY key; + err = NR_RegAddKey(hreg, xpcomKey, (char *)dll->GetFullPath(), &key); + + if (err != REGERR_OK) + { + NR_RegClose(hreg); + return (NS_ERROR_FAILURE); + } + + PRTime lastModTime = dll->GetLastModifiedTime(); + PRUint64 fileSize = dll->GetSize(); + NR_RegSetEntry(hreg, key, "LastModTimeStamp", REGTYPE_ENTRY_BYTES, + &lastModTime, sizeof(lastModTime)); + NR_RegSetEntry(hreg, key, "FileSize", REGTYPE_ENTRY_BYTES, + &fileSize, sizeof(fileSize)); + + char *ncomponentsString = "0"; + + NR_RegSetEntryString(hreg, key, "ComponentsCount", + ncomponentsString); + + NR_RegClose(hreg); + return (NS_OK); +} + +static nsresult platformRegister(NSQuickRegisterData regd, nsDll *dll) +{ + HREG hreg; + // Preconditions + PR_ASSERT(regd != NULL); + PR_ASSERT(regd->CIDString != NULL); + PR_ASSERT(dll != NULL); + + REGERR err = NR_RegOpen(NULL, &hreg); + + if (err != REGERR_OK) + { + return (NS_ERROR_FAILURE); + } + + RKEY classesKey; + if (NR_RegAddKey(hreg, ROOTKEY_COMMON, "Classes", &classesKey) != REGERR_OK) + { + NR_RegClose(hreg); + return (NS_ERROR_FAILURE); + } + + RKEY key; + NR_RegAddKey(hreg, classesKey, "CLSID", &key); + NR_RegAddKey(hreg, key, (char *)regd->CIDString, &key); + + NR_RegSetEntryString(hreg, key, "ClassName", (char *)regd->className); + if (regd->progID) + NR_RegSetEntryString(hreg, key, "ProgID", (char *)(regd->progID)); + char *libName = (char *)dll->GetFullPath(); + NR_RegSetEntry(hreg, key, "InprocServer", REGTYPE_ENTRY_FILE, libName, + strlen(libName) + 1); + + if (regd->progID) + { + NR_RegAddKey(hreg, classesKey, (char *)regd->progID, &key); + NR_RegSetEntryString(hreg, key, "CLSID", (char *)regd->CIDString); + } + + // XXX Gross. LongLongs dont have a serialization format. This makes + // XXX the registry non-xp. Someone beat on the nspr people to get + // XXX a longlong serialization function please! + RKEY xpcomKey; + if (NR_RegAddKey(hreg, ROOTKEY_COMMON, "Software/Netscape/XPCOM", &xpcomKey) != REGERR_OK) + { + NR_RegClose(hreg); + // This aint a fatal error. It causes autoregistration to fail + // and hence the dll would be registered again the next time + // we startup. Let us run with it. + return (NS_OK); + } + + NR_RegAddKey(hreg, xpcomKey, (char *)dll->GetFullPath(), &key); + + PRTime lastModTime = dll->GetLastModifiedTime(); + PRUint64 fileSize = dll->GetSize(); + + NR_RegSetEntry(hreg, key, "LastModTimeStamp", REGTYPE_ENTRY_BYTES, + &lastModTime, sizeof(lastModTime)); + NR_RegSetEntry(hreg, key, "FileSize", REGTYPE_ENTRY_BYTES, + &fileSize, sizeof(fileSize)); + + unsigned int nComponents = 0; + char buf[MAXREGNAMELEN]; + uint32 len = sizeof(buf); + + if (NR_RegGetEntryString(hreg, key, "ComponentsCount", buf, len) == REGERR_OK) + { + nComponents = atoi(buf); + } + nComponents++; + PR_snprintf(buf, sizeof(buf), "%d", nComponents); + NR_RegSetEntryString(hreg, key, "ComponentsCount", buf); + + NR_RegClose(hreg); return err; } -static nsresult platformUnregister(const nsCID &aCID, const char *aLibrary) +static nsresult platformUnregister(NSQuickRegisterData regd, const char *aLibrary) { HREG hreg; REGERR err = NR_RegOpen(NULL, &hreg); - if (err == REGERR_OK) + + if (err != REGERR_OK) { - RKEY key; - err = NR_RegAddKey(hreg, ROOTKEY_COMMON, "Classes", &key); - if (err == REGERR_OK) - { - char *cidString = aCID.ToString(); - err = NR_RegDeleteEntry(hreg, key, cidString); - delete [] cidString; - } - NR_RegClose(hreg); + return (NS_ERROR_FAILURE); } - return err; + + RKEY classesKey; + if (NR_RegAddKey(hreg, ROOTKEY_COMMON, "Classes", &classesKey) != REGERR_OK) + { + NR_RegClose(hreg); + return (NS_ERROR_FAILURE); + } + + RKEY key; + NR_RegAddKey(hreg, classesKey, "CLSID", &key); + NR_RegDeleteKey(hreg, key, (char *)regd->CIDString); + + if (regd->progID) + NR_RegDeleteKey(hreg, classesKey, (char *)regd->progID); + + RKEY xpcomKey; + if (NR_RegAddKey(hreg, ROOTKEY_COMMON, "Software/Netscape/XPCOM", &xpcomKey) != REGERR_OK) + { + NR_RegClose(hreg); + // This aint a fatal error. It causes autoregistration to fail + // and hence the dll would be registered again the next time + // we startup. Let us run with it. + return (NS_OK); + } + + NR_RegGetKey(hreg, xpcomKey, (char *)aLibrary, &key); + + // We need to reduce the ComponentCount by 1. + // If the ComponentCount hits 0, delete the entire key. + int nComponents = 0; + char buf[MAXREGNAMELEN]; + uint32 len = sizeof(buf); + + if (NR_RegGetEntryString(hreg, key, "ComponentsCount", buf, len) == REGERR_OK) + { + nComponents = atoi(buf); + nComponents--; + } + if (nComponents <= 0) + { + NR_RegDeleteKey(hreg, key, (char *)aLibrary); + } + else + { + PR_snprintf(buf, sizeof(buf), "%d", nComponents); + NR_RegSetEntryString(hreg, key, "ComponentsCount", buf); + } + + NR_RegClose(hreg); + return (NS_OK); } static FactoryEntry *platformFind(const nsCID &aCID) { - FactoryEntry *res = NULL; HREG hreg; REGERR err = NR_RegOpen(NULL, &hreg); - if (err == REGERR_OK) + + if (err != REGERR_OK) { - RKEY key; - err = NR_RegGetKey(hreg, ROOTKEY_COMMON, "Classes", &key); - if (err == REGERR_OK) { - char *cidString = aCID.ToString(); - char library[256]; - uint32 len = 256; - err = NR_RegGetEntryString(hreg, key, cidString, library, len); - - delete [] cidString; - if (err == REGERR_OK) { - res = new FactoryEntry(aCID, NULL, library); - } - } - NR_RegClose(hreg); + return (NULL); } - return res; + + RKEY classesKey; + if (NR_RegAddKey(hreg, ROOTKEY_COMMON, "Classes", &classesKey) != REGERR_OK) + { + NR_RegClose(hreg); + return (NULL); + } + + RKEY key; + NR_RegAddKey(hreg, classesKey, "CLSID", &key); + + FactoryEntry *res = NULL; + + RKEY cidKey; + char *cidString = aCID.ToString(); + err = NR_RegGetKey(hreg, key, cidString, &cidKey); + delete [] cidString; + + if (err != REGERR_OK) + { + NR_RegClose(hreg); + return (NULL); + } + + // Get the library name, modifiedtime and size + PRTime lastModTime = LL_ZERO; + PRUint64 fileSize = LL_ZERO; + + char buf[MAXREGNAMELEN]; + uint32 len = sizeof(buf); + err = NR_RegGetEntry(hreg, cidKey, "InprocServer", buf, &len); + if (err != REGERR_OK) + { + // Registry inconsistent. No File name for CLSID. + NR_RegClose(hreg); + return (NULL); + } + + char *library = buf; + + // XXX Gross. LongLongs dont have a serialization format. This makes + // XXX the registry non-xp. Someone beat on the nspr people to get + // XXX a longlong serialization function please! + RKEY xpcomKey; + if (NR_RegAddKey(hreg, ROOTKEY_COMMON, "Software/Netscape/XPCOM", &xpcomKey) == REGERR_OK) + { + if (NR_RegGetKey(hreg, xpcomKey, library, &key) == REGERR_OK) + { + uint32 n = sizeof(lastModTime); + NR_RegGetEntry(hreg, key, "LastModTimeStamp", &lastModTime, &n); + PR_ASSERT(n == sizeof(lastModTime)); + n = sizeof(fileSize); + NR_RegGetEntry(hreg, key, "FileSize", &fileSize, &n); + PR_ASSERT(n == sizeof(fileSize)); + } + } + + res = new FactoryEntry(aCID, library, lastModTime, fileSize); + + NR_RegClose(hreg); + + return (res); } + #endif // USE_NSREG +/***************************************************************************/ + nsresult nsRepository::loadFactory(FactoryEntry *aEntry, nsIFactory **aFactory) { @@ -204,6 +511,10 @@ nsresult nsRepository::loadFactory(FactoryEntry *aEntry, return NS_ERROR_NULL_POINTER; } *aFactory = NULL; + + // loadFactory() cannot be called for entries that are CID<->factory + // mapping entries for the session. + PR_ASSERT(aEntry->dll != NULL); if (aEntry->dll->IsLoaded() == PR_FALSE) { @@ -246,17 +557,11 @@ nsresult nsRepository::FindFactory(const nsCID &aClass, if (PR_LOG_TEST(logmodule, PR_LOG_ALWAYS)) { char *buf = aClass.ToString(); - PR_LogPrint("nsRepository: Finding Factory."); - PR_LogPrint("nsRepository: + %s", - buf); + PR_LogPrint("nsRepository: FindFactory(%s)", buf); delete [] buf; } - if (aFactory == NULL) - { - PR_LOG(logmodule, PR_LOG_ERROR, ("nsRepository: !! NULL pointer.")); - return NS_ERROR_NULL_POINTER; - } + PR_ASSERT(aFactory != NULL); PR_EnterMonitor(monitor); @@ -268,13 +573,19 @@ nsresult nsRepository::FindFactory(const nsCID &aClass, #ifdef USE_REGISTRY if (entry == NULL) { + PR_LOG(logmodule, PR_LOG_ALWAYS, ("\t\tnot found in factory cache. Looking in registry")); entry = platformFind(aClass); // If we got one, cache it in our hashtable if (entry != NULL) { + PR_LOG(logmodule, PR_LOG_ALWAYS, ("\t\tfound in registry.")); factories->Put(&key, entry); } } + else + { + PR_LOG(logmodule, PR_LOG_ALWAYS, ("\t\tfound in factory cache.")); + } #endif PR_ExitMonitor(monitor); @@ -284,7 +595,8 @@ nsresult nsRepository::FindFactory(const nsCID &aClass, if ((entry)->factory == NULL) { res = loadFactory(entry, aFactory); - } else + } + else { *aFactory = entry->factory; (*aFactory)->AddRef(); @@ -292,8 +604,8 @@ nsresult nsRepository::FindFactory(const nsCID &aClass, } } - PR_LOG(logmodule, PR_LOG_WARNING, ("nsRepository: ! Find Factory %s", - res == NS_OK ? "succeeded" : "failed")); + PR_LOG(logmodule, PR_LOG_WARNING, ("nsRepository: FindFactory() %s", + res == NS_OK ? "succeeded" : "FAILED")); return res; } @@ -347,8 +659,7 @@ nsresult nsRepository::CreateInstance(const nsCID &aClass, if (PR_LOG_TEST(logmodule, PR_LOG_ALWAYS)) { char *buf = aClass.ToString(); - PR_LogPrint("nsRepository: Creating Instance."); - PR_LogPrint("nsRepository: + %s", buf); + PR_LogPrint("nsRepository: CreateInstance(%s)", buf); delete [] buf; } if (aResult == NULL) @@ -363,13 +674,16 @@ nsresult nsRepository::CreateInstance(const nsCID &aClass, { res = factory->CreateInstance(aDelegate, aIID, aResult); factory->Release(); - + PR_LOG(logmodule, PR_LOG_ALWAYS, ("\t\tCreateInstance() succeeded.")); return res; } - + + PR_LOG(logmodule, PR_LOG_ALWAYS, ("\t\tCreateInstance() FAILED.")); return NS_ERROR_FACTORY_NOT_REGISTERED; } +#if 0 +/* nsresult nsRepository::CreateInstance2(const nsCID &aClass, nsISupports *aDelegate, const nsIID &aIID, @@ -415,6 +729,8 @@ nsresult nsRepository::CreateInstance2(const nsCID &aClass, return NS_ERROR_FACTORY_NOT_REGISTERED; } +*/ +#endif /* 0 */ nsresult nsRepository::RegisterFactory(const nsCID &aClass, nsIFactory *aFactory, @@ -424,35 +740,37 @@ nsresult nsRepository::RegisterFactory(const nsCID &aClass, if (PR_LOG_TEST(logmodule, PR_LOG_ALWAYS)) { char *buf = aClass.ToString(); - PR_LogPrint("nsRepository: Registering Factory."); - PR_LogPrint("nsRepository: + %s", buf); - PR_LogPrint("nsRepository: + Replace = %d.", (int) aReplace); + PR_LogPrint("nsRepository: RegisterFactory(%s, factory), replace = %d.", buf, (int)aReplace); delete [] buf; } - + nsIFactory *old = NULL; FindFactory(aClass, &old); - + if (old != NULL) { old->Release(); if (!aReplace) { - PR_LOG(logmodule, PR_LOG_WARNING, - ("nsRepository: ! Factory already registered.")); + PR_LOG(logmodule, PR_LOG_WARNING, ("\t\tFactory already registered.")); return NS_ERROR_FACTORY_EXISTS; } + else + { + PR_LOG(logmodule, PR_LOG_WARNING, ("\t\tdeleting old Factory Entry.")); + delete old; + } } PR_EnterMonitor(monitor); - + nsIDKey key(aClass); - factories->Put(&key, new FactoryEntry(aClass, aFactory, NULL)); + factories->Put(&key, new FactoryEntry(aClass, aFactory)); PR_ExitMonitor(monitor); PR_LOG(logmodule, PR_LOG_WARNING, - ("nsRepository: ! Factory register succeeded.")); + ("\t\tFactory register succeeded.")); return NS_OK; } @@ -466,23 +784,26 @@ nsresult nsRepository::RegisterFactory(const nsCID &aClass, if (PR_LOG_TEST(logmodule, PR_LOG_ALWAYS)) { char *buf = aClass.ToString(); - PR_LogPrint("nsRepository: Registering Factory."); - PR_LogPrint("nsRepository: + %s in \"%s\".", buf, aLibrary); - PR_LogPrint("nsRepository: + Replace = %d, Persist = %d.", - (int) aReplace, (int) aPersist); + PR_LogPrint("nsRepository: RegisterFactory(%s, %s), replace = %d, persist = %d.", buf, aLibrary, (int)aReplace, (int)aPersist); delete [] buf; } + nsIFactory *old = NULL; FindFactory(aClass, &old); if (old != NULL) { old->Release(); - if (!aReplace) { - PR_LOG(logmodule, PR_LOG_WARNING, - ("nsRepository: ! Factory already registered.")); + if (!aReplace) + { + PR_LOG(logmodule, PR_LOG_WARNING,("\t\tFactory already registered.")); return NS_ERROR_FACTORY_EXISTS; } + else + { + PR_LOG(logmodule, PR_LOG_WARNING,("\t\tdeleting registered Factory.")); + delete old; + } } PR_EnterMonitor(monitor); @@ -490,19 +811,30 @@ nsresult nsRepository::RegisterFactory(const nsCID &aClass, #ifdef USE_REGISTRY if (aPersist == PR_TRUE) { - platformRegister(aClass, aLibrary); + // Add it to the registry + nsDll *dll = new nsDll(aLibrary); + // XXX temp hack until we get the dll to give us the entire + // XXX NSQuickRegisterClassData + NSQuickRegisterClassData cregd = {0}; + cregd.CIDString = aClass.ToString(); + platformRegister(&cregd, dll); + delete [] (char *)cregd.CIDString; + delete dll; } else #endif { + nsDll *dll = new nsDll(aLibrary); nsIDKey key(aClass); - factories->Put(&key, new FactoryEntry(aClass, NULL, aLibrary)); + factories->Put(&key, new FactoryEntry(aClass, aLibrary, + dll->GetLastModifiedTime(), dll->GetSize())); + delete dll; } PR_ExitMonitor(monitor); PR_LOG(logmodule, PR_LOG_WARNING, - ("nsRepository: ! Factory register succeeded.")); + ("\t\tFactory register succeeded.")); return NS_OK; } @@ -518,26 +850,22 @@ nsresult nsRepository::UnregisterFactory(const nsCID &aClass, PR_LogPrint("nsRepository: + %s.", buf); delete [] buf; } + - nsIFactory *old = NULL; - FindFactory(aClass, &old); - + nsIDKey key(aClass); nsresult res = NS_ERROR_FACTORY_NOT_REGISTERED; + FactoryEntry *old = (FactoryEntry *) factories->Get(&key); if (old != NULL) { - if (old == aFactory) + if (old->factory == aFactory) { PR_EnterMonitor(monitor); - - nsIDKey key(aClass); - FactoryEntry *entry = (FactoryEntry *) factories->Remove(&key); - delete entry; - + old = (FactoryEntry *) factories->Remove(&key); PR_ExitMonitor(monitor); - + delete old; res = NS_OK; } - old->Release(); + } PR_LOG(logmodule, PR_LOG_WARNING, @@ -566,7 +894,7 @@ nsresult nsRepository::UnregisterFactory(const nsCID &aClass, PR_EnterMonitor(monitor); - if (old != NULL) + if (old != NULL && old->dll != NULL) { if (old->dll->GetFullPath() != NULL && #ifdef XP_UNIX @@ -580,10 +908,15 @@ nsresult nsRepository::UnregisterFactory(const nsCID &aClass, delete entry; res = NS_OK; } - } #ifdef USE_REGISTRY - res = platformUnregister(aClass, aLibrary); + // XXX temp hack until we get the dll to give us the entire + // XXX NSQuickRegisterClassData + NSQuickRegisterClassData cregd = {0}; + cregd.CIDString = aClass.ToString(); + res = platformUnregister(&cregd, aLibrary); + delete [] (char *)cregd.CIDString; #endif + } PR_ExitMonitor(monitor); @@ -667,7 +1000,6 @@ nsresult nsRepository::AddToDefaultPathList(const char *pathlist) nsresult nsRepository::SyncComponentsInPathList(const char *pathlist) { -#ifndef XP_UNIX char *paths = PL_strdup(pathlist); if (paths == NULL || *paths == '\0') @@ -682,7 +1014,6 @@ nsresult nsRepository::SyncComponentsInPathList(const char *pathlist) paths = nextpath; } PL_strfree(pathsMem); -#endif return (NS_OK); } @@ -779,6 +1110,9 @@ nsresult nsRepository::SyncComponentsInFile(const char *fullname) { // XXX Create nsDll for this from registry and // XXX add it to our dll cache dllStore. +#ifdef USE_REGISTRY + dll = platformCreateDll(fullname); +#endif /* USE_REGISTRY */ } if (dll != NULL) @@ -798,8 +1132,7 @@ nsresult nsRepository::SyncComponentsInFile(const char *fullname) { // Dll hasn't changed. Skip. PR_LOG(logmodule, PR_LOG_ALWAYS, - ("nsRepository: + nsDll not changed and already " - "registered \"%s\". Skipping...", + ("nsRepository: + nsDll not changed \"%s\". Skipping...", dll->GetFullPath())); return (NS_OK); } @@ -837,6 +1170,16 @@ nsresult nsRepository::SyncComponentsInFile(const char *fullname) return (NS_ERROR_FAILURE); } } + else + { + // dll doesn't have a CanUnload proc. Guess it is + // ok to unload it. + dll->Unload(); + PR_LOG(logmodule, PR_LOG_ALWAYS, + ("nsRepository: + Unloading \"%s\". (no CanUnloadProc).", + dll->GetFullPath())); + + } } // dll isloaded @@ -873,10 +1216,12 @@ nsresult nsRepository::SyncComponentsInFile(const char *fullname) PR_LOG(logmodule, PR_LOG_ALWAYS, ("nsRepository: Autoregistration FAILED for " "\"%s\". Skipping...", dll->GetFullPath())); - // XXX Mark dll as not xpcom dll along with modified time - // XXX and size in the registry so that in the next - // XXX session, we wont do all this again until - // XXX the dll changes. + // Mark dll as not xpcom dll along with modified time and size in + // the registry so that we wont need to load the dll again every + // session until the dll changes. +#ifdef USE_REGISTRY + platformMarkNoComponents(dll); +#endif /* USE_REGISTRY */ ret = NS_ERROR_FAILURE; } else @@ -884,8 +1229,9 @@ nsresult nsRepository::SyncComponentsInFile(const char *fullname) PR_LOG(logmodule, PR_LOG_ALWAYS, ("nsRepository: Autoregistration Passed for " "\"%s\". Skipping...", dll->GetFullPath())); - // XXX Mark dll along with modified time and size in the - // XXX registry. + // Marking dll along with modified time and size in the + // registry happens at platformregister(). No need to do it + // here again. } return (ret); } @@ -932,8 +1278,8 @@ nsresult nsRepository::SelfRegisterDll(nsDll *dll) { res = regproc(/* serviceMgr, */ dll->GetFullPath()); } - dll->Unload(); } + dll->Unload(); return (res); } @@ -973,7 +1319,7 @@ nsresult nsRepository::SelfUnregisterDll(nsDll *dll) { res = unregproc(/* serviceMgr, */dll->GetFullPath()); } - dll->Unload(); } + dll->Unload(); return (res); } diff --git a/xpcom/src/nsRepository.cpp b/xpcom/src/nsRepository.cpp index e07c7303519d..c060232f82f7 100644 --- a/xpcom/src/nsRepository.cpp +++ b/xpcom/src/nsRepository.cpp @@ -28,6 +28,7 @@ #include "plstr.h" #include "prlink.h" #include "prsystem.h" +#include "prprf.h" #include "nsRepository.h" #ifdef USE_NSREG @@ -50,65 +51,131 @@ nsHashtable *nsRepository::factories = NULL; PRMonitor *nsRepository::monitor = NULL; + +/** + * dllStore + * + * The dllStore maintains a collection of dlls that are hashed by the dll + * name. The repository uses the DllStore only to store these dlls: + * + * 1. dlls that store components in them. + * The inmemory nsDll that is stored here always reflects the values of + * {lastModTime, fileSize} that are stored in the registry. + * It is the job of the autoregistration mechanism to do the right + * thing if the dll on disk is newer. + * 2. dlls that dont store components in them. + * This is for the purpose of the autoregistration mechanism only. + * These are marked in the registry too so that unless they change + * they wont have to loaded every session. + * + */ nsDllStore *nsRepository::dllStore = NULL; static PRLogModuleInfo *logmodule = NULL; static NS_DEFINE_IID(kFactory2IID, NS_IFACTORY2_IID); +/***************************************************************************/ + +/** + * Class: FactoryEntry() + * + * There are two types of FactoryEntries. + * + * 1. {CID, dll} mapping. + * Factory is a consequence of the dll. These can be either session + * specific or persistent based on whether we write this + * to the registry or not. + * + * 2. {CID, factory} mapping + * These are strictly session specific and in memory only. + */ + class FactoryEntry { public: nsCID cid; nsIFactory *factory; - + + FactoryEntry(const nsCID &aClass, const char *aLibrary, + PRTime lastModTime, PRUint64 fileSize); + FactoryEntry(const nsCID &aClass, nsIFactory *aFactory); + ~FactoryEntry(); // DO NOT DELETE THIS. Many FactoryEntry(s) could be sharing the same Dll. // This gets deleted from the dllStore going away. nsDll *dll; - FactoryEntry(const nsCID &aClass, nsIFactory *aFactory, - const char *aLibrary) - : cid(aClass), factory(aFactory), dll(NULL) +}; + +FactoryEntry::FactoryEntry(const nsCID &aClass, const char *aLibrary, + PRTime lastModTime, PRUint64 fileSize) + : cid(aClass), factory(NULL), dll(NULL) +{ + nsDllStore *dllCollection = nsRepository::dllStore; + + if (aLibrary == NULL) { - nsDllStore *dllCollection = nsRepository::dllStore; - - if (aLibrary == NULL) - { - return; - } - - // If dll not already in dllCollection, add it. - // PR_EnterMonitor(nsRepository::monitor); - dll = dllCollection->Get(aLibrary); - // PR_ExitMonitor(nsRepository::monitor); - - if (dll == NULL) - { - // Add a new Dll into the nsDllStore - dll = new nsDll(aLibrary); - if (dll->GetStatus() != DLL_OK) - { - // Cant create a nsDll. Backoff. - delete dll; - dll = NULL; - } - else - { - // PR_EnterMonitor(nsRepository::monitor); - dllCollection->Put(aLibrary, dll); - // PR_ExitMonitor(nsRepository::monitor); - } - } + return; } - ~FactoryEntry(void) + // If dll not already in dllCollection, add it. + // PR_EnterMonitor(nsRepository::monitor); + dll = dllCollection->Get(aLibrary); + // PR_ExitMonitor(nsRepository::monitor); + + if (dll == NULL) { - if (factory != NULL) + PR_LOG(logmodule, PR_LOG_ALWAYS, + ("nsRepository: New dll \"%s\".", aLibrary)); + + // Add a new Dll into the nsDllStore + dll = new nsDll(aLibrary, lastModTime, fileSize); + if (dll->GetStatus() != DLL_OK) { - factory->Release(); + // Cant create a nsDll. Backoff. + PR_LOG(logmodule, PR_LOG_ALWAYS, + ("nsRepository: New dll status error. \"%s\".", aLibrary)); + delete dll; + dll = NULL; + } + else + { + PR_LOG(logmodule, PR_LOG_ALWAYS, + ("nsRepository: Adding New dll \"%s\" to dllStore.", + aLibrary)); + + // PR_EnterMonitor(nsRepository::monitor); + dllCollection->Put(aLibrary, dll); + // PR_ExitMonitor(nsRepository::monitor); } - // DO NOT DELETE nsDll *dll; } -}; + else + { + PR_LOG(logmodule, PR_LOG_ALWAYS, + ("nsRepository: Found in dllStore \"%s\".", aLibrary)); + // XXX We found the dll in the dllCollection. + // XXX Consistency check: dll needs to have the same + // XXX lastModTime and fileSize. If not that would mean + // XXX that the dll wasn't registered properly. + } +} + + +FactoryEntry::FactoryEntry(const nsCID &aClass, nsIFactory *aFactory) + : cid(aClass), factory(aFactory), dll(NULL) +{ +} + + +FactoryEntry::~FactoryEntry(void) +{ + if (factory != NULL) + { + factory->Release(); + } + // DO NOT DELETE nsDll *dll; +} + +/***************************************************************************/ class IDKey: public nsHashKey { private: @@ -127,75 +194,315 @@ public: nsHashKey *Clone(void) const { return new IDKey(id); } }; +/***************************************************************************/ + #ifdef USE_NSREG #define USE_REGISTRY -static nsresult platformRegister(const nsCID &aCID, const char *aLibrary) +static nsDll *platformCreateDll(const char *fullname) { HREG hreg; REGERR err = NR_RegOpen(NULL, &hreg); - if (err == REGERR_OK) + + if (err != REGERR_OK) { - RKEY key; - err = NR_RegAddKey(hreg, ROOTKEY_COMMON, - "Classes", &key); - if (err == REGERR_OK) - { - char *cidString = aCID.ToString(); - err = NR_RegSetEntryString(hreg, key, cidString, (char *) aLibrary); - delete [] cidString; - } - NR_RegClose(hreg); + return (NULL); } + RKEY xpcomKey; + if (NR_RegAddKey(hreg, ROOTKEY_COMMON, "Software/Netscape/XPCOM", &xpcomKey) != REGERR_OK) + { + NR_RegClose(hreg); + return (NULL); + } + + RKEY key; + err = NR_RegGetKey(hreg, xpcomKey, (char *)fullname, &key); + if (err != REGERR_OK) + { + return (NULL); + } + + PRTime lastModTime = LL_ZERO; + PRUint64 fileSize = LL_ZERO; + uint32 n = sizeof(lastModTime); + NR_RegGetEntry(hreg, key, "LastModTimeStamp", &lastModTime, &n); + n = sizeof(fileSize); + NR_RegGetEntry(hreg, key, "FileSize", &fileSize, &n); + + nsDll *dll = new nsDll(fullname, lastModTime, fileSize); + + return (dll); +} + +/** + * platformMarkNoComponents(nsDll) + * + * Stores the dll name, last modified time, size and 0 for number of + * components in dll in the registry at location + * ROOTKEY_COMMON/Software/Netscape/XPCOM/dllname + */ +static nsresult platformMarkNoComponents(nsDll *dll) +{ + HREG hreg; + REGERR err = NR_RegOpen(NULL, &hreg); + + if (err != REGERR_OK) + { + return (NS_ERROR_FAILURE); + } + + // XXX Gross. LongLongs dont have a serialization format. This makes + // XXX the registry non-xp. Someone beat on the nspr people to get + // XXX a longlong serialization function please! + RKEY xpcomKey; + if (NR_RegAddKey(hreg, ROOTKEY_COMMON, "Software/Netscape/XPCOM", &xpcomKey) != REGERR_OK) + { + NR_RegClose(hreg); + return (NS_ERROR_FAILURE); + } + + RKEY key; + err = NR_RegAddKey(hreg, xpcomKey, (char *)dll->GetFullPath(), &key); + + if (err != REGERR_OK) + { + NR_RegClose(hreg); + return (NS_ERROR_FAILURE); + } + + PRTime lastModTime = dll->GetLastModifiedTime(); + PRUint64 fileSize = dll->GetSize(); + NR_RegSetEntry(hreg, key, "LastModTimeStamp", REGTYPE_ENTRY_BYTES, + &lastModTime, sizeof(lastModTime)); + NR_RegSetEntry(hreg, key, "FileSize", REGTYPE_ENTRY_BYTES, + &fileSize, sizeof(fileSize)); + + char *ncomponentsString = "0"; + + NR_RegSetEntryString(hreg, key, "ComponentsCount", + ncomponentsString); + + NR_RegClose(hreg); + return (NS_OK); +} + +static nsresult platformRegister(NSQuickRegisterData regd, nsDll *dll) +{ + HREG hreg; + // Preconditions + PR_ASSERT(regd != NULL); + PR_ASSERT(regd->CIDString != NULL); + PR_ASSERT(dll != NULL); + + REGERR err = NR_RegOpen(NULL, &hreg); + + if (err != REGERR_OK) + { + return (NS_ERROR_FAILURE); + } + + RKEY classesKey; + if (NR_RegAddKey(hreg, ROOTKEY_COMMON, "Classes", &classesKey) != REGERR_OK) + { + NR_RegClose(hreg); + return (NS_ERROR_FAILURE); + } + + RKEY key; + NR_RegAddKey(hreg, classesKey, "CLSID", &key); + NR_RegAddKey(hreg, key, (char *)regd->CIDString, &key); + + NR_RegSetEntryString(hreg, key, "ClassName", (char *)regd->className); + if (regd->progID) + NR_RegSetEntryString(hreg, key, "ProgID", (char *)(regd->progID)); + char *libName = (char *)dll->GetFullPath(); + NR_RegSetEntry(hreg, key, "InprocServer", REGTYPE_ENTRY_FILE, libName, + strlen(libName) + 1); + + if (regd->progID) + { + NR_RegAddKey(hreg, classesKey, (char *)regd->progID, &key); + NR_RegSetEntryString(hreg, key, "CLSID", (char *)regd->CIDString); + } + + // XXX Gross. LongLongs dont have a serialization format. This makes + // XXX the registry non-xp. Someone beat on the nspr people to get + // XXX a longlong serialization function please! + RKEY xpcomKey; + if (NR_RegAddKey(hreg, ROOTKEY_COMMON, "Software/Netscape/XPCOM", &xpcomKey) != REGERR_OK) + { + NR_RegClose(hreg); + // This aint a fatal error. It causes autoregistration to fail + // and hence the dll would be registered again the next time + // we startup. Let us run with it. + return (NS_OK); + } + + NR_RegAddKey(hreg, xpcomKey, (char *)dll->GetFullPath(), &key); + + PRTime lastModTime = dll->GetLastModifiedTime(); + PRUint64 fileSize = dll->GetSize(); + + NR_RegSetEntry(hreg, key, "LastModTimeStamp", REGTYPE_ENTRY_BYTES, + &lastModTime, sizeof(lastModTime)); + NR_RegSetEntry(hreg, key, "FileSize", REGTYPE_ENTRY_BYTES, + &fileSize, sizeof(fileSize)); + + unsigned int nComponents = 0; + char buf[MAXREGNAMELEN]; + uint32 len = sizeof(buf); + + if (NR_RegGetEntryString(hreg, key, "ComponentsCount", buf, len) == REGERR_OK) + { + nComponents = atoi(buf); + } + nComponents++; + PR_snprintf(buf, sizeof(buf), "%d", nComponents); + NR_RegSetEntryString(hreg, key, "ComponentsCount", buf); + + NR_RegClose(hreg); return err; } -static nsresult platformUnregister(const nsCID &aCID, const char *aLibrary) +static nsresult platformUnregister(NSQuickRegisterData regd, const char *aLibrary) { HREG hreg; REGERR err = NR_RegOpen(NULL, &hreg); - if (err == REGERR_OK) + + if (err != REGERR_OK) { - RKEY key; - err = NR_RegAddKey(hreg, ROOTKEY_COMMON, "Classes", &key); - if (err == REGERR_OK) - { - char *cidString = aCID.ToString(); - err = NR_RegDeleteEntry(hreg, key, cidString); - delete [] cidString; - } - NR_RegClose(hreg); + return (NS_ERROR_FAILURE); } - return err; + + RKEY classesKey; + if (NR_RegAddKey(hreg, ROOTKEY_COMMON, "Classes", &classesKey) != REGERR_OK) + { + NR_RegClose(hreg); + return (NS_ERROR_FAILURE); + } + + RKEY key; + NR_RegAddKey(hreg, classesKey, "CLSID", &key); + NR_RegDeleteKey(hreg, key, (char *)regd->CIDString); + + if (regd->progID) + NR_RegDeleteKey(hreg, classesKey, (char *)regd->progID); + + RKEY xpcomKey; + if (NR_RegAddKey(hreg, ROOTKEY_COMMON, "Software/Netscape/XPCOM", &xpcomKey) != REGERR_OK) + { + NR_RegClose(hreg); + // This aint a fatal error. It causes autoregistration to fail + // and hence the dll would be registered again the next time + // we startup. Let us run with it. + return (NS_OK); + } + + NR_RegGetKey(hreg, xpcomKey, (char *)aLibrary, &key); + + // We need to reduce the ComponentCount by 1. + // If the ComponentCount hits 0, delete the entire key. + int nComponents = 0; + char buf[MAXREGNAMELEN]; + uint32 len = sizeof(buf); + + if (NR_RegGetEntryString(hreg, key, "ComponentsCount", buf, len) == REGERR_OK) + { + nComponents = atoi(buf); + nComponents--; + } + if (nComponents <= 0) + { + NR_RegDeleteKey(hreg, key, (char *)aLibrary); + } + else + { + PR_snprintf(buf, sizeof(buf), "%d", nComponents); + NR_RegSetEntryString(hreg, key, "ComponentsCount", buf); + } + + NR_RegClose(hreg); + return (NS_OK); } static FactoryEntry *platformFind(const nsCID &aCID) { - FactoryEntry *res = NULL; HREG hreg; REGERR err = NR_RegOpen(NULL, &hreg); - if (err == REGERR_OK) + + if (err != REGERR_OK) { - RKEY key; - err = NR_RegGetKey(hreg, ROOTKEY_COMMON, "Classes", &key); - if (err == REGERR_OK) { - char *cidString = aCID.ToString(); - char library[256]; - uint32 len = 256; - err = NR_RegGetEntryString(hreg, key, cidString, library, len); - - delete [] cidString; - if (err == REGERR_OK) { - res = new FactoryEntry(aCID, NULL, library); - } - } - NR_RegClose(hreg); + return (NULL); } - return res; + + RKEY classesKey; + if (NR_RegAddKey(hreg, ROOTKEY_COMMON, "Classes", &classesKey) != REGERR_OK) + { + NR_RegClose(hreg); + return (NULL); + } + + RKEY key; + NR_RegAddKey(hreg, classesKey, "CLSID", &key); + + FactoryEntry *res = NULL; + + RKEY cidKey; + char *cidString = aCID.ToString(); + err = NR_RegGetKey(hreg, key, cidString, &cidKey); + delete [] cidString; + + if (err != REGERR_OK) + { + NR_RegClose(hreg); + return (NULL); + } + + // Get the library name, modifiedtime and size + PRTime lastModTime = LL_ZERO; + PRUint64 fileSize = LL_ZERO; + + char buf[MAXREGNAMELEN]; + uint32 len = sizeof(buf); + err = NR_RegGetEntry(hreg, cidKey, "InprocServer", buf, &len); + if (err != REGERR_OK) + { + // Registry inconsistent. No File name for CLSID. + NR_RegClose(hreg); + return (NULL); + } + + char *library = buf; + + // XXX Gross. LongLongs dont have a serialization format. This makes + // XXX the registry non-xp. Someone beat on the nspr people to get + // XXX a longlong serialization function please! + RKEY xpcomKey; + if (NR_RegAddKey(hreg, ROOTKEY_COMMON, "Software/Netscape/XPCOM", &xpcomKey) == REGERR_OK) + { + if (NR_RegGetKey(hreg, xpcomKey, library, &key) == REGERR_OK) + { + uint32 n = sizeof(lastModTime); + NR_RegGetEntry(hreg, key, "LastModTimeStamp", &lastModTime, &n); + PR_ASSERT(n == sizeof(lastModTime)); + n = sizeof(fileSize); + NR_RegGetEntry(hreg, key, "FileSize", &fileSize, &n); + PR_ASSERT(n == sizeof(fileSize)); + } + } + + res = new FactoryEntry(aCID, library, lastModTime, fileSize); + + NR_RegClose(hreg); + + return (res); } + #endif // USE_NSREG +/***************************************************************************/ + nsresult nsRepository::loadFactory(FactoryEntry *aEntry, nsIFactory **aFactory) { @@ -204,6 +511,10 @@ nsresult nsRepository::loadFactory(FactoryEntry *aEntry, return NS_ERROR_NULL_POINTER; } *aFactory = NULL; + + // loadFactory() cannot be called for entries that are CID<->factory + // mapping entries for the session. + PR_ASSERT(aEntry->dll != NULL); if (aEntry->dll->IsLoaded() == PR_FALSE) { @@ -246,17 +557,11 @@ nsresult nsRepository::FindFactory(const nsCID &aClass, if (PR_LOG_TEST(logmodule, PR_LOG_ALWAYS)) { char *buf = aClass.ToString(); - PR_LogPrint("nsRepository: Finding Factory."); - PR_LogPrint("nsRepository: + %s", - buf); + PR_LogPrint("nsRepository: FindFactory(%s)", buf); delete [] buf; } - if (aFactory == NULL) - { - PR_LOG(logmodule, PR_LOG_ERROR, ("nsRepository: !! NULL pointer.")); - return NS_ERROR_NULL_POINTER; - } + PR_ASSERT(aFactory != NULL); PR_EnterMonitor(monitor); @@ -268,13 +573,19 @@ nsresult nsRepository::FindFactory(const nsCID &aClass, #ifdef USE_REGISTRY if (entry == NULL) { + PR_LOG(logmodule, PR_LOG_ALWAYS, ("\t\tnot found in factory cache. Looking in registry")); entry = platformFind(aClass); // If we got one, cache it in our hashtable if (entry != NULL) { + PR_LOG(logmodule, PR_LOG_ALWAYS, ("\t\tfound in registry.")); factories->Put(&key, entry); } } + else + { + PR_LOG(logmodule, PR_LOG_ALWAYS, ("\t\tfound in factory cache.")); + } #endif PR_ExitMonitor(monitor); @@ -284,7 +595,8 @@ nsresult nsRepository::FindFactory(const nsCID &aClass, if ((entry)->factory == NULL) { res = loadFactory(entry, aFactory); - } else + } + else { *aFactory = entry->factory; (*aFactory)->AddRef(); @@ -292,8 +604,8 @@ nsresult nsRepository::FindFactory(const nsCID &aClass, } } - PR_LOG(logmodule, PR_LOG_WARNING, ("nsRepository: ! Find Factory %s", - res == NS_OK ? "succeeded" : "failed")); + PR_LOG(logmodule, PR_LOG_WARNING, ("nsRepository: FindFactory() %s", + res == NS_OK ? "succeeded" : "FAILED")); return res; } @@ -347,8 +659,7 @@ nsresult nsRepository::CreateInstance(const nsCID &aClass, if (PR_LOG_TEST(logmodule, PR_LOG_ALWAYS)) { char *buf = aClass.ToString(); - PR_LogPrint("nsRepository: Creating Instance."); - PR_LogPrint("nsRepository: + %s", buf); + PR_LogPrint("nsRepository: CreateInstance(%s)", buf); delete [] buf; } if (aResult == NULL) @@ -363,13 +674,16 @@ nsresult nsRepository::CreateInstance(const nsCID &aClass, { res = factory->CreateInstance(aDelegate, aIID, aResult); factory->Release(); - + PR_LOG(logmodule, PR_LOG_ALWAYS, ("\t\tCreateInstance() succeeded.")); return res; } - + + PR_LOG(logmodule, PR_LOG_ALWAYS, ("\t\tCreateInstance() FAILED.")); return NS_ERROR_FACTORY_NOT_REGISTERED; } +#if 0 +/* nsresult nsRepository::CreateInstance2(const nsCID &aClass, nsISupports *aDelegate, const nsIID &aIID, @@ -415,6 +729,8 @@ nsresult nsRepository::CreateInstance2(const nsCID &aClass, return NS_ERROR_FACTORY_NOT_REGISTERED; } +*/ +#endif /* 0 */ nsresult nsRepository::RegisterFactory(const nsCID &aClass, nsIFactory *aFactory, @@ -424,35 +740,37 @@ nsresult nsRepository::RegisterFactory(const nsCID &aClass, if (PR_LOG_TEST(logmodule, PR_LOG_ALWAYS)) { char *buf = aClass.ToString(); - PR_LogPrint("nsRepository: Registering Factory."); - PR_LogPrint("nsRepository: + %s", buf); - PR_LogPrint("nsRepository: + Replace = %d.", (int) aReplace); + PR_LogPrint("nsRepository: RegisterFactory(%s, factory), replace = %d.", buf, (int)aReplace); delete [] buf; } - + nsIFactory *old = NULL; FindFactory(aClass, &old); - + if (old != NULL) { old->Release(); if (!aReplace) { - PR_LOG(logmodule, PR_LOG_WARNING, - ("nsRepository: ! Factory already registered.")); + PR_LOG(logmodule, PR_LOG_WARNING, ("\t\tFactory already registered.")); return NS_ERROR_FACTORY_EXISTS; } + else + { + PR_LOG(logmodule, PR_LOG_WARNING, ("\t\tdeleting old Factory Entry.")); + delete old; + } } PR_EnterMonitor(monitor); - + nsIDKey key(aClass); - factories->Put(&key, new FactoryEntry(aClass, aFactory, NULL)); + factories->Put(&key, new FactoryEntry(aClass, aFactory)); PR_ExitMonitor(monitor); PR_LOG(logmodule, PR_LOG_WARNING, - ("nsRepository: ! Factory register succeeded.")); + ("\t\tFactory register succeeded.")); return NS_OK; } @@ -466,23 +784,26 @@ nsresult nsRepository::RegisterFactory(const nsCID &aClass, if (PR_LOG_TEST(logmodule, PR_LOG_ALWAYS)) { char *buf = aClass.ToString(); - PR_LogPrint("nsRepository: Registering Factory."); - PR_LogPrint("nsRepository: + %s in \"%s\".", buf, aLibrary); - PR_LogPrint("nsRepository: + Replace = %d, Persist = %d.", - (int) aReplace, (int) aPersist); + PR_LogPrint("nsRepository: RegisterFactory(%s, %s), replace = %d, persist = %d.", buf, aLibrary, (int)aReplace, (int)aPersist); delete [] buf; } + nsIFactory *old = NULL; FindFactory(aClass, &old); if (old != NULL) { old->Release(); - if (!aReplace) { - PR_LOG(logmodule, PR_LOG_WARNING, - ("nsRepository: ! Factory already registered.")); + if (!aReplace) + { + PR_LOG(logmodule, PR_LOG_WARNING,("\t\tFactory already registered.")); return NS_ERROR_FACTORY_EXISTS; } + else + { + PR_LOG(logmodule, PR_LOG_WARNING,("\t\tdeleting registered Factory.")); + delete old; + } } PR_EnterMonitor(monitor); @@ -490,19 +811,30 @@ nsresult nsRepository::RegisterFactory(const nsCID &aClass, #ifdef USE_REGISTRY if (aPersist == PR_TRUE) { - platformRegister(aClass, aLibrary); + // Add it to the registry + nsDll *dll = new nsDll(aLibrary); + // XXX temp hack until we get the dll to give us the entire + // XXX NSQuickRegisterClassData + NSQuickRegisterClassData cregd = {0}; + cregd.CIDString = aClass.ToString(); + platformRegister(&cregd, dll); + delete [] (char *)cregd.CIDString; + delete dll; } else #endif { + nsDll *dll = new nsDll(aLibrary); nsIDKey key(aClass); - factories->Put(&key, new FactoryEntry(aClass, NULL, aLibrary)); + factories->Put(&key, new FactoryEntry(aClass, aLibrary, + dll->GetLastModifiedTime(), dll->GetSize())); + delete dll; } PR_ExitMonitor(monitor); PR_LOG(logmodule, PR_LOG_WARNING, - ("nsRepository: ! Factory register succeeded.")); + ("\t\tFactory register succeeded.")); return NS_OK; } @@ -518,26 +850,22 @@ nsresult nsRepository::UnregisterFactory(const nsCID &aClass, PR_LogPrint("nsRepository: + %s.", buf); delete [] buf; } + - nsIFactory *old = NULL; - FindFactory(aClass, &old); - + nsIDKey key(aClass); nsresult res = NS_ERROR_FACTORY_NOT_REGISTERED; + FactoryEntry *old = (FactoryEntry *) factories->Get(&key); if (old != NULL) { - if (old == aFactory) + if (old->factory == aFactory) { PR_EnterMonitor(monitor); - - nsIDKey key(aClass); - FactoryEntry *entry = (FactoryEntry *) factories->Remove(&key); - delete entry; - + old = (FactoryEntry *) factories->Remove(&key); PR_ExitMonitor(monitor); - + delete old; res = NS_OK; } - old->Release(); + } PR_LOG(logmodule, PR_LOG_WARNING, @@ -566,7 +894,7 @@ nsresult nsRepository::UnregisterFactory(const nsCID &aClass, PR_EnterMonitor(monitor); - if (old != NULL) + if (old != NULL && old->dll != NULL) { if (old->dll->GetFullPath() != NULL && #ifdef XP_UNIX @@ -580,10 +908,15 @@ nsresult nsRepository::UnregisterFactory(const nsCID &aClass, delete entry; res = NS_OK; } - } #ifdef USE_REGISTRY - res = platformUnregister(aClass, aLibrary); + // XXX temp hack until we get the dll to give us the entire + // XXX NSQuickRegisterClassData + NSQuickRegisterClassData cregd = {0}; + cregd.CIDString = aClass.ToString(); + res = platformUnregister(&cregd, aLibrary); + delete [] (char *)cregd.CIDString; #endif + } PR_ExitMonitor(monitor); @@ -667,7 +1000,6 @@ nsresult nsRepository::AddToDefaultPathList(const char *pathlist) nsresult nsRepository::SyncComponentsInPathList(const char *pathlist) { -#ifndef XP_UNIX char *paths = PL_strdup(pathlist); if (paths == NULL || *paths == '\0') @@ -682,7 +1014,6 @@ nsresult nsRepository::SyncComponentsInPathList(const char *pathlist) paths = nextpath; } PL_strfree(pathsMem); -#endif return (NS_OK); } @@ -779,6 +1110,9 @@ nsresult nsRepository::SyncComponentsInFile(const char *fullname) { // XXX Create nsDll for this from registry and // XXX add it to our dll cache dllStore. +#ifdef USE_REGISTRY + dll = platformCreateDll(fullname); +#endif /* USE_REGISTRY */ } if (dll != NULL) @@ -798,8 +1132,7 @@ nsresult nsRepository::SyncComponentsInFile(const char *fullname) { // Dll hasn't changed. Skip. PR_LOG(logmodule, PR_LOG_ALWAYS, - ("nsRepository: + nsDll not changed and already " - "registered \"%s\". Skipping...", + ("nsRepository: + nsDll not changed \"%s\". Skipping...", dll->GetFullPath())); return (NS_OK); } @@ -837,6 +1170,16 @@ nsresult nsRepository::SyncComponentsInFile(const char *fullname) return (NS_ERROR_FAILURE); } } + else + { + // dll doesn't have a CanUnload proc. Guess it is + // ok to unload it. + dll->Unload(); + PR_LOG(logmodule, PR_LOG_ALWAYS, + ("nsRepository: + Unloading \"%s\". (no CanUnloadProc).", + dll->GetFullPath())); + + } } // dll isloaded @@ -873,10 +1216,12 @@ nsresult nsRepository::SyncComponentsInFile(const char *fullname) PR_LOG(logmodule, PR_LOG_ALWAYS, ("nsRepository: Autoregistration FAILED for " "\"%s\". Skipping...", dll->GetFullPath())); - // XXX Mark dll as not xpcom dll along with modified time - // XXX and size in the registry so that in the next - // XXX session, we wont do all this again until - // XXX the dll changes. + // Mark dll as not xpcom dll along with modified time and size in + // the registry so that we wont need to load the dll again every + // session until the dll changes. +#ifdef USE_REGISTRY + platformMarkNoComponents(dll); +#endif /* USE_REGISTRY */ ret = NS_ERROR_FAILURE; } else @@ -884,8 +1229,9 @@ nsresult nsRepository::SyncComponentsInFile(const char *fullname) PR_LOG(logmodule, PR_LOG_ALWAYS, ("nsRepository: Autoregistration Passed for " "\"%s\". Skipping...", dll->GetFullPath())); - // XXX Mark dll along with modified time and size in the - // XXX registry. + // Marking dll along with modified time and size in the + // registry happens at platformregister(). No need to do it + // here again. } return (ret); } @@ -932,8 +1278,8 @@ nsresult nsRepository::SelfRegisterDll(nsDll *dll) { res = regproc(/* serviceMgr, */ dll->GetFullPath()); } - dll->Unload(); } + dll->Unload(); return (res); } @@ -973,7 +1319,7 @@ nsresult nsRepository::SelfUnregisterDll(nsDll *dll) { res = unregproc(/* serviceMgr, */dll->GetFullPath()); } - dll->Unload(); } + dll->Unload(); return (res); }