LCOV - code coverage report
Current view: top level - xpcom/threads - BackgroundHangMonitor.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 1 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 1 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #ifndef mozilla_BackgroundHangMonitor_h
       8             : #define mozilla_BackgroundHangMonitor_h
       9             : 
      10             : #include "mozilla/HangAnnotations.h"
      11             : #include "mozilla/Monitor.h"
      12             : #include "mozilla/RefPtr.h"
      13             : 
      14             : #include "nsString.h"
      15             : 
      16             : #include <stdint.h>
      17             : 
      18             : namespace mozilla {
      19             : 
      20             : namespace Telemetry {
      21             : class ThreadHangStats;
      22             : } // namespace Telemetry
      23             : 
      24             : class BackgroundHangThread;
      25             : class BackgroundHangManager;
      26             : 
      27             : /**
      28             :  * The background hang monitor is responsible for detecting and reporting
      29             :  * hangs in main and background threads. A thread registers itself using
      30             :  * the BackgroundHangMonitor object and periodically calls its methods to
      31             :  * inform the hang monitor of the thread's activity. Each thread is given
      32             :  * a thread name, a timeout, and a maximum timeout. If one of the thread's
      33             :  * tasks runs for longer than the timeout duration but shorter than the
      34             :  * maximum timeout, a (transient) hang is reported. On the other hand, if
      35             :  * a task runs for longer than the maximum timeout duration or never
      36             :  * finishes (e.g. in a deadlock), a permahang is reported.
      37             :  *
      38             :  * Tasks are defined arbitrarily, but are typically represented by events
      39             :  * in an event loop -- processing one event is equivalent to running one
      40             :  * task. To ensure responsiveness, tasks in a thread often have a target
      41             :  * running time. This is a good starting point for determining the timeout
      42             :  * and maximum timeout values. For example, the Compositor thread has a
      43             :  * responsiveness goal of 60Hz or 17ms, so a starting timeout could be
      44             :  * 100ms. Considering some platforms (e.g. Android) can terminate the app
      45             :  * when a critical thread hangs for longer than a few seconds, a good
      46             :  * starting maximum timeout is 4 or 5 seconds.
      47             :  *
      48             :  * A thread registers itself through the BackgroundHangMonitor constructor.
      49             :  * Multiple BackgroundHangMonitor objects can be used in one thread. The
      50             :  * constructor without arguments can be used when it is known that the thread
      51             :  * already has a BackgroundHangMonitor registered. When all instances of
      52             :  * BackgroundHangMonitor are destroyed, the thread is unregistered.
      53             :  *
      54             :  * The thread then uses two methods to inform BackgroundHangMonitor of the
      55             :  * thread's activity:
      56             :  *
      57             :  *  > BackgroundHangMonitor::NotifyActivity should be called *before*
      58             :  *    starting a task. The task run time is determined by the interval
      59             :  *    between this call and the next NotifyActivity call.
      60             :  *
      61             :  *  > BackgroundHangMonitor::NotifyWait should be called *before* the
      62             :  *    thread enters a wait state (e.g. to wait for a new event). This
      63             :  *    prevents a waiting thread from being detected as hanging. The wait
      64             :  *    state is automatically cleared at the next NotifyActivity call.
      65             :  *
      66             :  * The following example shows hang monitoring in a simple event loop:
      67             :  *
      68             :  *  void thread_main()
      69             :  *  {
      70             :  *    mozilla::BackgroundHangMonitor hangMonitor("example1", 100, 1000);
      71             :  *    while (!exiting) {
      72             :  *      hangMonitor.NotifyActivity();
      73             :  *      process_next_event();
      74             :  *      hangMonitor.NotifyWait();
      75             :  *      wait_for_next_event();
      76             :  *    }
      77             :  *  }
      78             :  *
      79             :  * The following example shows reentrancy in nested event loops:
      80             :  *
      81             :  *  void thread_main()
      82             :  *  {
      83             :  *    mozilla::BackgroundHangMonitor hangMonitor("example2", 100, 1000);
      84             :  *    while (!exiting) {
      85             :  *      hangMonitor.NotifyActivity();
      86             :  *      process_next_event();
      87             :  *      hangMonitor.NotifyWait();
      88             :  *      wait_for_next_event();
      89             :  *    }
      90             :  *  }
      91             :  *
      92             :  *  void process_next_event()
      93             :  *  {
      94             :  *    mozilla::BackgroundHangMonitor hangMonitor();
      95             :  *    if (is_sync_event) {
      96             :  *      while (!finished_event) {
      97             :  *        hangMonitor.NotifyActivity();
      98             :  *        process_next_event();
      99             :  *        hangMonitor.NotifyWait();
     100             :  *        wait_for_next_event();
     101             :  *      }
     102             :  *    } else {
     103             :  *      process_nonsync_event();
     104             :  *    }
     105             :  *  }
     106             :  */
     107             : class BackgroundHangMonitor
     108             : {
     109             : private:
     110             :   friend BackgroundHangManager;
     111             : 
     112             :   RefPtr<BackgroundHangThread> mThread;
     113             : 
     114             :   static bool ShouldDisableOnBeta(const nsCString &);
     115             :   static bool DisableOnBeta();
     116             : 
     117             : public:
     118             :   static const uint32_t kNoTimeout = 0;
     119             :   enum ThreadType {
     120             :     // For a new BackgroundHangMonitor for thread T, only create a new
     121             :     // monitoring thread for T if one doesn't already exist. If one does,
     122             :     // share that pre-existing monitoring thread.
     123             :     THREAD_SHARED,
     124             :     // For a new BackgroundHangMonitor for thread T, create a new
     125             :     // monitoring thread for T even if there are other, pre-existing
     126             :     // monitoring threads for T.
     127             :     THREAD_PRIVATE
     128             :   };
     129             : 
     130             :   /**
     131             :    * ThreadHangStatsIterator is used to iterate through the ThreadHangStats
     132             :    * associated with each active monitored thread. Because of an internal
     133             :    * lock while this object is alive, a thread must use only one instance
     134             :    * of this class at a time and must iterate through the list as fast as
     135             :    * possible. The following example shows using the iterator:
     136             :    *
     137             :    * {
     138             :    *   // Scope the iter variable so it's destroyed as soon as we're done
     139             :    *   BackgroundHangMonitor::ThreadHangStatsIterator iter;
     140             :    *   for (ThreadHangStats* histogram = iter.GetNext();
     141             :    *        histogram; histogram = iter.GetNext()) {
     142             :    *     // Process histogram
     143             :    *   }
     144             :    * }
     145             :    */
     146           0 :   class ThreadHangStatsIterator : public MonitorAutoLock
     147             :   {
     148             :   private:
     149             :     BackgroundHangThread* mThread;
     150             : 
     151             :     ThreadHangStatsIterator(const ThreadHangStatsIterator&);
     152             :     ThreadHangStatsIterator& operator=(const ThreadHangStatsIterator&);
     153             : 
     154             :   public:
     155             :     /**
     156             :      * Create an ThreadHangStatsIterator instance and take the internal lock.
     157             :      * Internal lock is released on destruction.
     158             :      */
     159             :     ThreadHangStatsIterator();
     160             : 
     161             :     /**
     162             :      * Get the next item in the list; the first call returns the first item.
     163             :      * Returns nullptr at the end of the list.
     164             :      */
     165             :     Telemetry::ThreadHangStats* GetNext();
     166             :   };
     167             : 
     168             :   /**
     169             :    * Enable hang monitoring.
     170             :    * Must return before using BackgroundHangMonitor.
     171             :    */
     172             :   static void Startup();
     173             : 
     174             :   /**
     175             :    * Disable hang monitoring.
     176             :    * Can be called without destroying all BackgroundHangMonitors first.
     177             :    */
     178             :   static void Shutdown();
     179             : 
     180             :   /**
     181             :    * Returns true if BHR is disabled.
     182             :    */
     183             :   static bool IsDisabled();
     184             : 
     185             :   /**
     186             :    * Start monitoring hangs for the current thread.
     187             :    *
     188             :    * @param aName Name to identify the thread with
     189             :    * @param aTimeoutMs Amount of time in milliseconds without
     190             :    *  activity before registering a hang
     191             :    * @param aMaxTimeoutMs Amount of time in milliseconds without
     192             :    *  activity before registering a permanent hang
     193             :    * @param aThreadType
     194             :    *  The ThreadType type of monitoring thread that should be created
     195             :    *  for this monitor. See the documentation for ThreadType.
     196             :    */
     197             :   BackgroundHangMonitor(const char* aName,
     198             :                         uint32_t aTimeoutMs,
     199             :                         uint32_t aMaxTimeoutMs,
     200             :                         ThreadType aThreadType = THREAD_SHARED);
     201             : 
     202             :   /**
     203             :    * Monitor hangs using an existing monitor
     204             :    * associated with the current thread.
     205             :    */
     206             :   BackgroundHangMonitor();
     207             : 
     208             :   /**
     209             :    * Destroys the hang monitor; hang monitoring for a thread stops
     210             :    * when all monitors associated with the thread are destroyed.
     211             :    */
     212             :   ~BackgroundHangMonitor();
     213             : 
     214             :   /**
     215             :    * Notify the hang monitor of pending current thread activity.
     216             :    * Call this method before starting an "activity" or after
     217             :    * exiting from a wait state.
     218             :    */
     219             :   void NotifyActivity();
     220             : 
     221             :   /**
     222             :    * Notify the hang monitor of current thread wait.
     223             :    * Call this method before entering a wait state; call
     224             :    * NotifyActivity when subsequently exiting the wait state.
     225             :    */
     226             :   void NotifyWait();
     227             : 
     228             :   /**
     229             :    * Register an annotator with BHR for the current thread.
     230             :    * @param aAnnotator annotator to register
     231             :    * @return true if the annotator was registered, otherwise false.
     232             :    */
     233             :   static bool RegisterAnnotator(HangMonitor::Annotator& aAnnotator);
     234             : 
     235             :   /**
     236             :    * Unregister an annotator that was previously registered via
     237             :    * RegisterAnnotator.
     238             :    * @param aAnnotator annotator to unregister
     239             :    * @return true if there are still remaining annotators registered
     240             :    */
     241             :   static bool UnregisterAnnotator(HangMonitor::Annotator& aAnnotator);
     242             : };
     243             : 
     244             : } // namespace mozilla
     245             : 
     246             : #endif // mozilla_BackgroundHangMonitor_h

Generated by: LCOV version 1.13