michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef nsComponentManager_h__ michael@0: #define nsComponentManager_h__ michael@0: michael@0: #include "nsXPCOM.h" michael@0: michael@0: #include "xpcom-private.h" michael@0: #include "nsIComponentManager.h" michael@0: #include "nsIComponentRegistrar.h" michael@0: #include "nsIMemoryReporter.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsIFile.h" michael@0: #include "mozilla/MemoryReporting.h" michael@0: #include "mozilla/Module.h" michael@0: #include "mozilla/ModuleLoader.h" michael@0: #include "mozilla/Mutex.h" michael@0: #include "nsXULAppAPI.h" michael@0: #include "nsNativeComponentLoader.h" michael@0: #include "nsIFactory.h" michael@0: #include "nsIInterfaceRequestor.h" michael@0: #include "nsIInterfaceRequestorUtils.h" michael@0: #include "pldhash.h" michael@0: #include "prtime.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "nsWeakReference.h" michael@0: #include "plarena.h" michael@0: #include "nsCOMArray.h" michael@0: #include "nsDataHashtable.h" michael@0: #include "nsInterfaceHashtable.h" michael@0: #include "nsClassHashtable.h" michael@0: #include "nsTArray.h" michael@0: michael@0: #include "mozilla/Omnijar.h" michael@0: #include "mozilla/Attributes.h" michael@0: michael@0: struct nsFactoryEntry; michael@0: class nsIServiceManager; michael@0: struct PRThread; michael@0: michael@0: #define NS_COMPONENTMANAGER_CID \ michael@0: { /* 91775d60-d5dc-11d2-92fb-00e09805570f */ \ michael@0: 0x91775d60, \ michael@0: 0xd5dc, \ michael@0: 0x11d2, \ michael@0: {0x92, 0xfb, 0x00, 0xe0, 0x98, 0x05, 0x57, 0x0f} \ michael@0: } michael@0: michael@0: /* keys for registry use */ michael@0: extern const char xpcomKeyName[]; michael@0: extern const char xpcomComponentsKeyName[]; michael@0: extern const char lastModValueName[]; michael@0: extern const char fileSizeValueName[]; michael@0: extern const char nativeComponentType[]; michael@0: extern const char staticComponentType[]; michael@0: michael@0: #ifdef DEBUG michael@0: #define XPCOM_CHECK_PENDING_CIDS michael@0: #endif michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: extern const mozilla::Module kXPCOMModule; michael@0: michael@0: /** michael@0: * This is a wrapper around mozilla::Mutex which provides runtime michael@0: * checking for a deadlock where the same thread tries to lock a mutex while michael@0: * it is already locked. This checking is present in both debug and release michael@0: * builds. michael@0: */ michael@0: class SafeMutex michael@0: { michael@0: public: michael@0: SafeMutex(const char* name) michael@0: : mMutex(name) michael@0: , mOwnerThread(nullptr) michael@0: { } michael@0: ~SafeMutex() michael@0: { } michael@0: michael@0: void Lock() michael@0: { michael@0: AssertNotCurrentThreadOwns(); michael@0: mMutex.Lock(); michael@0: MOZ_ASSERT(mOwnerThread == nullptr); michael@0: mOwnerThread = PR_GetCurrentThread(); michael@0: } michael@0: michael@0: void Unlock() michael@0: { michael@0: MOZ_ASSERT(mOwnerThread == PR_GetCurrentThread()); michael@0: mOwnerThread = nullptr; michael@0: mMutex.Unlock(); michael@0: } michael@0: michael@0: void AssertCurrentThreadOwns() const michael@0: { michael@0: // This method is a debug-only check michael@0: MOZ_ASSERT(mOwnerThread == PR_GetCurrentThread()); michael@0: } michael@0: michael@0: MOZ_NEVER_INLINE void AssertNotCurrentThreadOwns() const michael@0: { michael@0: // This method is a release-mode check michael@0: if (PR_GetCurrentThread() == mOwnerThread) { michael@0: MOZ_CRASH(); michael@0: } michael@0: } michael@0: michael@0: private: michael@0: mozilla::Mutex mMutex; michael@0: volatile PRThread* mOwnerThread; michael@0: }; michael@0: michael@0: typedef mozilla::BaseAutoLock SafeMutexAutoLock; michael@0: typedef mozilla::BaseAutoUnlock SafeMutexAutoUnlock; michael@0: michael@0: class nsComponentManagerImpl MOZ_FINAL michael@0: : public nsIComponentManager michael@0: , public nsIServiceManager michael@0: , public nsSupportsWeakReference michael@0: , public nsIComponentRegistrar michael@0: , public nsIInterfaceRequestor michael@0: , public nsIMemoryReporter michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSIINTERFACEREQUESTOR michael@0: NS_DECL_NSICOMPONENTMANAGER michael@0: NS_DECL_NSICOMPONENTREGISTRAR michael@0: NS_DECL_NSIMEMORYREPORTER michael@0: michael@0: static nsresult Create(nsISupports* aOuter, REFNSIID aIID, void** aResult); michael@0: michael@0: nsresult RegistryLocationForFile(nsIFile* aFile, michael@0: nsCString& aResult); michael@0: nsresult FileForRegistryLocation(const nsCString &aLocation, michael@0: nsIFile **aSpec); michael@0: michael@0: NS_DECL_NSISERVICEMANAGER michael@0: michael@0: // nsComponentManagerImpl methods: michael@0: nsComponentManagerImpl(); michael@0: michael@0: static nsComponentManagerImpl* gComponentManager; michael@0: nsresult Init(); michael@0: michael@0: nsresult Shutdown(void); michael@0: michael@0: nsresult FreeServices(); michael@0: michael@0: already_AddRefed LoaderForExtension(const nsACString& aExt); michael@0: nsInterfaceHashtable mLoaderMap; michael@0: michael@0: already_AddRefed FindFactory(const nsCID& aClass); michael@0: already_AddRefed FindFactory(const char *contractID, michael@0: uint32_t aContractIDLen); michael@0: michael@0: already_AddRefed LoadFactory(nsFactoryEntry *aEntry); michael@0: michael@0: nsFactoryEntry *GetFactoryEntry(const char *aContractID, michael@0: uint32_t aContractIDLen); michael@0: nsFactoryEntry *GetFactoryEntry(const nsCID &aClass); michael@0: michael@0: nsDataHashtable mFactories; michael@0: nsDataHashtable mContractIDs; michael@0: michael@0: SafeMutex mLock; michael@0: michael@0: static void InitializeStaticModules(); michael@0: static void InitializeModuleLocations(); michael@0: michael@0: struct ComponentLocation michael@0: { michael@0: NSLocationType type; michael@0: mozilla::FileLocation location; michael@0: }; michael@0: michael@0: class ComponentLocationComparator michael@0: { michael@0: public: michael@0: bool Equals(const ComponentLocation& a, const ComponentLocation& b) const michael@0: { michael@0: return (a.type == b.type && a.location.Equals(b.location)); michael@0: } michael@0: }; michael@0: michael@0: static nsTArray* sStaticModules; michael@0: static nsTArray* sModuleLocations; michael@0: michael@0: nsNativeModuleLoader mNativeModuleLoader; michael@0: michael@0: class KnownModule michael@0: { michael@0: public: michael@0: /** michael@0: * Static or binary module. michael@0: */ michael@0: KnownModule(const mozilla::Module* aModule, mozilla::FileLocation &aFile) michael@0: : mModule(aModule) michael@0: , mFile(aFile) michael@0: , mLoaded(false) michael@0: , mFailed(false) michael@0: { } michael@0: michael@0: KnownModule(const mozilla::Module* aModule) michael@0: : mModule(aModule) michael@0: , mLoaded(false) michael@0: , mFailed(false) michael@0: { } michael@0: michael@0: KnownModule(mozilla::FileLocation &aFile) michael@0: : mModule(nullptr) michael@0: , mFile(aFile) michael@0: , mLoader(nullptr) michael@0: , mLoaded(false) michael@0: , mFailed(false) michael@0: { } michael@0: michael@0: ~KnownModule() michael@0: { michael@0: if (mLoaded && mModule->unloadProc) michael@0: mModule->unloadProc(); michael@0: } michael@0: michael@0: bool EnsureLoader(); michael@0: bool Load(); michael@0: michael@0: const mozilla::Module* Module() const michael@0: { michael@0: return mModule; michael@0: } michael@0: michael@0: /** michael@0: * For error logging, get a description of this module, either the michael@0: * file path, or . michael@0: */ michael@0: nsCString Description() const; michael@0: michael@0: private: michael@0: const mozilla::Module* mModule; michael@0: mozilla::FileLocation mFile; michael@0: nsCOMPtr mLoader; michael@0: bool mLoaded; michael@0: bool mFailed; michael@0: }; michael@0: michael@0: // The KnownModule is kept alive by these members, it is michael@0: // referenced by pointer from the factory entries. michael@0: nsTArray< nsAutoPtr > mKnownStaticModules; michael@0: // The key is the URI string of the module michael@0: nsClassHashtable mKnownModules; michael@0: michael@0: // Mutex not held michael@0: void RegisterModule(const mozilla::Module* aModule, michael@0: mozilla::FileLocation* aFile); michael@0: michael@0: michael@0: // Mutex held michael@0: void RegisterCIDEntryLocked(const mozilla::Module::CIDEntry* aEntry, michael@0: KnownModule* aModule); michael@0: void RegisterContractIDLocked(const mozilla::Module::ContractIDEntry* aEntry); michael@0: michael@0: // Mutex not held michael@0: void RegisterManifest(NSLocationType aType, mozilla::FileLocation &aFile, michael@0: bool aChromeOnly); michael@0: michael@0: struct ManifestProcessingContext michael@0: { michael@0: ManifestProcessingContext(NSLocationType aType, mozilla::FileLocation &aFile, bool aChromeOnly) michael@0: : mType(aType) michael@0: , mFile(aFile) michael@0: , mChromeOnly(aChromeOnly) michael@0: { } michael@0: michael@0: ~ManifestProcessingContext() { } michael@0: michael@0: NSLocationType mType; michael@0: mozilla::FileLocation mFile; michael@0: bool mChromeOnly; michael@0: }; michael@0: michael@0: void ManifestManifest(ManifestProcessingContext& cx, int lineno, char *const * argv); michael@0: void ManifestBinaryComponent(ManifestProcessingContext& cx, int lineno, char *const * argv); michael@0: void ManifestXPT(ManifestProcessingContext& cx, int lineno, char *const * argv); michael@0: void ManifestComponent(ManifestProcessingContext& cx, int lineno, char *const * argv); michael@0: void ManifestContract(ManifestProcessingContext& cx, int lineno, char* const * argv); michael@0: void ManifestCategory(ManifestProcessingContext& cx, int lineno, char* const * argv); michael@0: michael@0: void RereadChromeManifests(bool aChromeOnly = true); michael@0: michael@0: // Shutdown michael@0: enum { michael@0: NOT_INITIALIZED, michael@0: NORMAL, michael@0: SHUTDOWN_IN_PROGRESS, michael@0: SHUTDOWN_COMPLETE michael@0: } mStatus; michael@0: michael@0: PLArenaPool mArena; michael@0: michael@0: struct PendingServiceInfo { michael@0: const nsCID* cid; michael@0: PRThread* thread; michael@0: }; michael@0: michael@0: inline PendingServiceInfo* AddPendingService(const nsCID& aServiceCID, michael@0: PRThread* aThread); michael@0: inline void RemovePendingService(const nsCID& aServiceCID); michael@0: inline PRThread* GetPendingServiceThread(const nsCID& aServiceCID) const; michael@0: michael@0: nsTArray mPendingServices; michael@0: michael@0: size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf); michael@0: michael@0: private: michael@0: ~nsComponentManagerImpl(); michael@0: }; michael@0: michael@0: michael@0: #define NS_MAX_FILENAME_LEN 1024 michael@0: michael@0: #define NS_ERROR_IS_DIR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_XPCOM, 24) michael@0: michael@0: struct nsFactoryEntry michael@0: { michael@0: nsFactoryEntry(const mozilla::Module::CIDEntry* entry, michael@0: nsComponentManagerImpl::KnownModule* module); michael@0: michael@0: // nsIComponentRegistrar.registerFactory support michael@0: nsFactoryEntry(const nsCID& aClass, nsIFactory* factory); michael@0: michael@0: ~nsFactoryEntry(); michael@0: michael@0: already_AddRefed GetFactory(); michael@0: michael@0: size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf); michael@0: michael@0: const mozilla::Module::CIDEntry* mCIDEntry; michael@0: nsComponentManagerImpl::KnownModule* mModule; michael@0: michael@0: nsCOMPtr mFactory; michael@0: nsCOMPtr mServiceObject; michael@0: }; michael@0: michael@0: #endif // nsComponentManager_h__