DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (b6d82b1a6b02)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_ClearOnShutdown_h
#define mozilla_ClearOnShutdown_h

#include "mozilla/LinkedList.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/Array.h"
#include "MainThreadUtils.h"

#include <functional>

/*
 * This header exports two public methods in the mozilla namespace:
 *
 *   template<class SmartPtr>
 *   void ClearOnShutdown(SmartPtr *aPtr, aPhase=ShutdownPhase::ShutdownFinal)
 *
 * This function takes a pointer to a smart pointer and nulls the smart pointer
 * on shutdown (and a particular phase of shutdown as needed).  If a phase
 * is specified, the ptr will be cleared at the start of that phase.  Also,
 * if a phase has already occurred when ClearOnShutdown() is called it will
 * cause a MOZ_ASSERT.  In case a phase is not explicitly cleared we will
 * clear it on the next phase that occurs.
 *
 * This is useful if you have a global smart pointer object which you don't
 * want to "leak" on shutdown.
 *
 * Although ClearOnShutdown will work with any smart pointer (i.e., nsCOMPtr,
 * nsRefPtr, nsAutoPtr, StaticRefPtr, and StaticAutoPtr), you probably want to
 * use it only with StaticRefPtr and StaticAutoPtr.  There is no way to undo a
 * call to ClearOnShutdown, so you can call it only on smart pointers which you
 * know will live until the program shuts down.  In practice, these are likely
 * global variables, which should be Static{Ref,Auto}Ptr.
 *
 *   template <typename CallableT>
 *   void RunOnShutdown(CallableT&& aCallable,
 *                      aPhase = ShutdownPhase::ShutdownFinal)
 *
 * This function takes a callable and executes it upon shutdown at the start of
 * the specified phase. If the phase has already occurred when RunOnShutdown()
 * is called, it will cause a MOZ_ASSERT. In case a phase is not explicitly
 * cleared, we will clear it on the next phase that occurs.
 *
 * ClearOnShutdown and RunOnShutdown are both currently main-thread only because
 * we don't want to accidentally free an object from a different thread than the
 * one it was created on.
 */

namespace mozilla {

// Must be contiguous starting at 0
enum class ShutdownPhase {
  NotInShutdown = 0,
  WillShutdown,
  Shutdown,
  ShutdownThreads,
  ShutdownLoaders,
  ShutdownFinal,
  ShutdownPostLastCycleCollection,
  ShutdownPhase_Length,  // never pass this value
  First = WillShutdown,  // for iteration
  Last = ShutdownFinal
};

namespace ClearOnShutdown_Internal {

class ShutdownObserver : public LinkedListElement<ShutdownObserver> {
 public:
  virtual void Shutdown() = 0;
  virtual ~ShutdownObserver() {}
};

template <class SmartPtr>
class PointerClearer : public ShutdownObserver {
 public:
  explicit PointerClearer(SmartPtr* aPtr) : mPtr(aPtr) {}

  virtual void Shutdown() override {
    if (mPtr) {
      *mPtr = nullptr;
    }
  }

 private:
  SmartPtr* mPtr;
};

class FunctionInvoker : public ShutdownObserver {
 public:
  template <typename CallableT>
  explicit FunctionInvoker(CallableT&& aCallable)
      : mCallable(std::forward<CallableT>(aCallable)) {}

  virtual void Shutdown() override {
    if (!mCallable) {
      return;
    }

    mCallable();
  }

 private:
  std::function<void()> mCallable;
};

void InsertIntoShutdownList(ShutdownObserver* aShutdownObserver,
                            ShutdownPhase aPhase);

typedef LinkedList<ShutdownObserver> ShutdownList;
extern Array<StaticAutoPtr<ShutdownList>,
             static_cast<size_t>(ShutdownPhase::ShutdownPhase_Length)>
    sShutdownObservers;
extern ShutdownPhase sCurrentShutdownPhase;

}  // namespace ClearOnShutdown_Internal

template <class SmartPtr>
inline void ClearOnShutdown(
    SmartPtr* aPtr, ShutdownPhase aPhase = ShutdownPhase::ShutdownFinal) {
  using namespace ClearOnShutdown_Internal;

  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(aPhase != ShutdownPhase::ShutdownPhase_Length);

  InsertIntoShutdownList(new PointerClearer<SmartPtr>(aPtr), aPhase);
}

template <typename CallableT>
inline void RunOnShutdown(CallableT&& aCallable,
                          ShutdownPhase aPhase = ShutdownPhase::ShutdownFinal) {
  using namespace ClearOnShutdown_Internal;

  MOZ_ASSERT(NS_IsMainThread());
  MOZ_ASSERT(aPhase != ShutdownPhase::ShutdownPhase_Length);

  InsertIntoShutdownList(
      new FunctionInvoker(std::forward<CallableT>(aCallable)), aPhase);
}

// Called when XPCOM is shutting down, after all shutdown notifications have
// been sent and after all threads' event loops have been purged.
void KillClearOnShutdown(ShutdownPhase aPhase);

}  // namespace mozilla

#endif