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 (4a108e94d3e2)

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
/* -*- 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 nsThreadManager_h__
#define nsThreadManager_h__

#include "mozilla/Mutex.h"
#include "nsIThreadManager.h"
#include "nsRefPtrHashtable.h"
#include "nsThread.h"

class nsIRunnable;

namespace mozilla {
class ReentrantMonitor;
}

class nsThreadManager : public nsIThreadManager
{
public:
#ifdef MOZ_NUWA_PROCESS
  struct ThreadStatusInfo;
  class AllThreadsWereIdleListener {
  public:
    NS_INLINE_DECL_REFCOUNTING(AllThreadsWereIdleListener);
    virtual void OnAllThreadsWereIdle() = 0;
  protected:
    virtual ~AllThreadsWereIdleListener()
    {
    }
  };
#endif // MOZ_NUWA_PROCESS

  NS_DECL_ISUPPORTS
  NS_DECL_NSITHREADMANAGER

  static nsThreadManager* get()
  {
    static nsThreadManager sInstance;
    return &sInstance;
  }

  nsresult Init();

  // Shutdown all threads.  This function should only be called on the main
  // thread of the application process.
  void Shutdown();

  // Called by nsThread to inform the ThreadManager it exists.  This method
  // must be called when the given thread is the current thread.
  void RegisterCurrentThread(nsThread* aThread);

  // Called by nsThread to inform the ThreadManager it is going away.  This
  // method must be called when the given thread is the current thread.
  void UnregisterCurrentThread(nsThread* aThread);

  // Returns the current thread.  Returns null if OOM or if ThreadManager isn't
  // initialized.
  nsThread* GetCurrentThread();

  // Returns the maximal number of threads that have been in existence
  // simultaneously during the execution of the thread manager.
  uint32_t GetHighestNumberOfThreads();

  // This needs to be public in order to support static instantiation of this
  // class with older compilers (e.g., egcs-2.91.66).
  ~nsThreadManager()
  {
  }

#ifdef MOZ_NUWA_PROCESS
  void SetIgnoreThreadStatus();

  // |SetThreadWorking| and |SetThreadIdle| set status of thread that is
  // currently running. They get thread status information from TLS and pass
  // the information to |SetThreadIsWorking|.
  void SetThreadIdle(nsIRunnable** aReturnRunnable);
  void SetThreadWorking();

  // |SetThreadIsWorking| is where is status actually changed. Thread status
  // information is passed as a argument so caller must obtain the structure
  // by itself. If this method is invoked on main thread, |aReturnRunnable|
  // should be provided to receive the runnable of notifying listeners.
  // |ResetIsDispatchingToMainThread| should be invoked after caller on main
  // thread dispatched the task to main thread's queue.
  void SetThreadIsWorking(ThreadStatusInfo* aInfo,
                          bool aIsWorking,
                          nsIRunnable** aReturnRunnable);
  void ResetIsDispatchingToMainThread();

  void AddAllThreadsWereIdleListener(AllThreadsWereIdleListener *listener);
  void RemoveAllThreadsWereIdleListener(AllThreadsWereIdleListener *listener);
  ThreadStatusInfo* GetCurrentThreadStatusInfo();
#endif // MOZ_NUWA_PROCESS

private:
  nsThreadManager()
    : mCurThreadIndex(0)
    , mMainPRThread(nullptr)
    , mLock("nsThreadManager.mLock")
    , mInitialized(false)
    , mCurrentNumberOfThreads(1)
    , mHighestNumberOfThreads(1)
#ifdef MOZ_NUWA_PROCESS
    , mMonitor(nullptr)
    , mMainThreadStatusInfo(nullptr)
    , mDispatchingToMainThread(nullptr)
#endif
  {
  }

  nsRefPtrHashtable<nsPtrHashKey<PRThread>, nsThread> mThreadsByPRThread;
  unsigned            mCurThreadIndex;  // thread-local-storage index
  nsRefPtr<nsThread>  mMainThread;
  PRThread*           mMainPRThread;
  mozilla::OffTheBooksMutex mLock;  // protects tables
  mozilla::Atomic<bool> mInitialized;

  // The current number of threads
  uint32_t            mCurrentNumberOfThreads;
  // The highest number of threads encountered so far during the session
  uint32_t            mHighestNumberOfThreads;

#ifdef MOZ_NUWA_PROCESS
  static void DeleteThreadStatusInfo(void *aData);
  unsigned mThreadStatusInfoIndex;
  nsTArray<nsRefPtr<AllThreadsWereIdleListener>> mThreadsIdledListeners;
  nsTArray<ThreadStatusInfo*> mThreadStatusInfos;
  mozilla::UniquePtr<mozilla::ReentrantMonitor> mMonitor;
  ThreadStatusInfo* mMainThreadStatusInfo;
  // |mDispatchingToMainThread| is set when all thread are found to be idle
  // before task of notifying all listeners are dispatched to main thread.
  // The flag is protected by |mMonitor|.
  bool mDispatchingToMainThread;
#endif // MOZ_NUWA_PROCESS
};

#define NS_THREADMANAGER_CID                       \
{ /* 7a4204c6-e45a-4c37-8ebb-6709a22c917c */       \
  0x7a4204c6,                                      \
  0xe45a,                                          \
  0x4c37,                                          \
  {0x8e, 0xbb, 0x67, 0x09, 0xa2, 0x2c, 0x91, 0x7c} \
}

#endif  // nsThreadManager_h__