michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set sw=2 ts=8 et ft=cpp : */ 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 mozilla_ClearOnShutdown_h michael@0: #define mozilla_ClearOnShutdown_h michael@0: michael@0: #include "mozilla/LinkedList.h" michael@0: #include "mozilla/StaticPtr.h" michael@0: #include "MainThreadUtils.h" michael@0: michael@0: /* michael@0: * This header exports one public method in the mozilla namespace: michael@0: * michael@0: * template michael@0: * void ClearOnShutdown(SmartPtr *aPtr) michael@0: * michael@0: * This function takes a pointer to a smart pointer and nulls the smart pointer michael@0: * on shutdown. michael@0: * michael@0: * This is useful if you have a global smart pointer object which you don't michael@0: * want to "leak" on shutdown. michael@0: * michael@0: * Although ClearOnShutdown will work with any smart pointer (i.e., nsCOMPtr, michael@0: * nsRefPtr, nsAutoPtr, StaticRefPtr, and StaticAutoPtr), you probably want to michael@0: * use it only with StaticRefPtr and StaticAutoPtr. There is no way to undo a michael@0: * call to ClearOnShutdown, so you can call it only on smart pointers which you michael@0: * know will live until the program shuts down. In practice, these are likely michael@0: * global variables, which should be Static{Ref,Auto}Ptr. michael@0: * michael@0: * ClearOnShutdown is currently main-thread only because we don't want to michael@0: * accidentally free an object from a different thread than the one it was michael@0: * created on. michael@0: */ michael@0: michael@0: namespace mozilla { michael@0: namespace ClearOnShutdown_Internal { michael@0: michael@0: class ShutdownObserver : public LinkedListElement michael@0: { michael@0: public: michael@0: virtual void Shutdown() = 0; michael@0: virtual ~ShutdownObserver() {} michael@0: }; michael@0: michael@0: template michael@0: class PointerClearer : public ShutdownObserver michael@0: { michael@0: public: michael@0: PointerClearer(SmartPtr *aPtr) michael@0: : mPtr(aPtr) michael@0: {} michael@0: michael@0: virtual void Shutdown() michael@0: { michael@0: if (mPtr) { michael@0: *mPtr = nullptr; michael@0: } michael@0: } michael@0: michael@0: private: michael@0: SmartPtr *mPtr; michael@0: }; michael@0: michael@0: extern bool sHasShutDown; michael@0: extern StaticAutoPtr > sShutdownObservers; michael@0: michael@0: } // namespace ClearOnShutdown_Internal michael@0: michael@0: template michael@0: inline void ClearOnShutdown(SmartPtr *aPtr) michael@0: { michael@0: using namespace ClearOnShutdown_Internal; michael@0: michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: MOZ_ASSERT(!sHasShutDown); michael@0: michael@0: if (!sShutdownObservers) { michael@0: sShutdownObservers = new LinkedList(); michael@0: } michael@0: sShutdownObservers->insertBack(new PointerClearer(aPtr)); michael@0: } michael@0: michael@0: // Called when XPCOM is shutting down, after all shutdown notifications have michael@0: // been sent and after all threads' event loops have been purged. michael@0: inline void KillClearOnShutdown() michael@0: { michael@0: using namespace ClearOnShutdown_Internal; michael@0: michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: if (sShutdownObservers) { michael@0: ShutdownObserver *observer; michael@0: while ((observer = sShutdownObservers->popFirst())) { michael@0: observer->Shutdown(); michael@0: delete observer; michael@0: } michael@0: } michael@0: michael@0: sShutdownObservers = nullptr; michael@0: sHasShutDown = true; michael@0: } michael@0: michael@0: } // namespace mozilla michael@0: michael@0: #endif