xpcom/build/IOInterposer.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #ifndef mozilla_IOInterposer_h
     6 #define mozilla_IOInterposer_h
     8 #include "mozilla/Attributes.h"
     9 #include "mozilla/TimeStamp.h"
    10 #include "mozilla/XPCOM.h"
    12 namespace mozilla {
    14 /**
    15  * Interface for I/O interposer observers. This is separate from the
    16  * IOInterposer because we have multiple uses for these observations.
    17  */
    18 class IOInterposeObserver
    19 {
    20 public:
    21   enum Operation
    22   {
    23     OpNone = 0,
    24     OpCreateOrOpen = (1 << 0),
    25     OpRead = (1 << 1),
    26     OpWrite = (1 << 2),
    27     OpFSync = (1 << 3),
    28     OpStat = (1 << 4),
    29     OpClose = (1 << 5),
    30     OpNextStage = (1 << 6), // Meta - used when leaving startup, entering shutdown
    31     OpWriteFSync = (OpWrite | OpFSync),
    32     OpAll = (OpCreateOrOpen | OpRead | OpWrite | OpFSync | OpStat | OpClose),
    33     OpAllWithStaging = (OpAll | OpNextStage)
    34   };
    36   /** A representation of an I/O observation  */
    37   class Observation
    38   {
    39   protected:
    40     /**
    41      * This constructor is for use by subclasses that are intended to take
    42      * timing measurements via RAII. The |aShouldReport| parameter may be
    43      * used to make the measurement and reporting conditional on the
    44      * satisfaction of an arbitrary predicate that was evaluated
    45      * in the subclass. Note that IOInterposer::IsObservedOperation() is
    46      * always ANDed with aShouldReport, so the subclass does not need to
    47      * include a call to that function explicitly.
    48      */
    49     Observation(Operation aOperation, const char* aReference,
    50                 bool aShouldReport = true);
    52   public:
    53     /**
    54      * Since this constructor accepts start and end times, it does *not* take
    55      * its own timings, nor does it report itself.
    56      */
    57     Observation(Operation aOperation, const TimeStamp& aStart,
    58                 const TimeStamp& aEnd, const char* aReference);
    60     /**
    61      * Operation observed, this is one of the individual Operation values.
    62      * Combinations of these flags are only used when registering observers.
    63      */
    64     Operation ObservedOperation() const
    65     {
    66       return mOperation;
    67     }
    69     /**
    70      * Return the observed operation as a human-readable string.
    71      */
    72     const char* ObservedOperationString() const;
    74     /** Time at which the I/O operation was started */
    75     TimeStamp Start() const
    76     {
    77       return mStart;
    78     }
    80     /**
    81      * Time at which the I/O operation ended, for asynchronous methods this is
    82      * the time at which the call initiating the asynchronous request returned.
    83      */
    84     TimeStamp End() const
    85     {
    86       return mEnd;
    87     }
    89     /**
    90      * Duration of the operation, for asynchronous I/O methods this is the
    91      * duration of the call initiating the asynchronous request.
    92      */
    93     TimeDuration Duration() const
    94     {
    95       return mEnd - mStart;
    96     }
    98     /**
    99      * IO reference, function name or name of component (sqlite) that did IO
   100      * this is in addition the generic operation. This attribute may be platform
   101      * specific, but should only take a finite number of distinct values.
   102      * E.g. sqlite-commit, CreateFile, NtReadFile, fread, fsync, mmap, etc.
   103      * I.e. typically the platform specific function that did the IO.
   104      */
   105     const char* Reference() const
   106     {
   107       return mReference;
   108     }
   110     /** Request filename associated with the I/O operation, null if unknown */
   111     virtual const char16_t* Filename()
   112     {
   113       return nullptr;
   114     }
   116     virtual ~Observation()
   117     {
   118     }
   120   protected:
   121     void
   122     Report();
   124     Operation   mOperation;
   125     TimeStamp   mStart;
   126     TimeStamp   mEnd;
   127     const char* mReference;     // Identifies the source of the Observation
   128     bool        mShouldReport;  // Measure and report if true
   129   };
   131   /**
   132    * Invoked whenever an implementation of the IOInterposeObserver should
   133    * observe aObservation. Implement this and do your thing...
   134    * But do consider if it is wise to use IO functions in this method, they are
   135    * likely to cause recursion :)
   136    * At least, see PoisonIOInterposer.h and register your handle as a debug file
   137    * even, if you don't initialize the poison IO interposer, someone else might.
   138    *
   139    * Remark: Observations may occur on any thread.
   140    */
   141   virtual void Observe(Observation& aObservation) = 0;
   143   virtual ~IOInterposeObserver()
   144   {
   145   }
   147 protected:
   148   /**
   149    * We don't use NS_IsMainThread() because we need to be able to determine the
   150    * main thread outside of XPCOM Initialization. IOInterposer observers should
   151    * call this function instead.
   152    */
   153   static bool IsMainThread();
   154 };
   156 /**
   157  * These functions are responsible for ensuring that events are routed to the
   158  * appropriate observers.
   159  */
   160 namespace IOInterposer
   161 {
   162   /**
   163    * This function must be called from the main-thread when no other threads are
   164    * running before any of the other methods on this class may be used.
   165    *
   166    * IO reports can however, safely assume that IsObservedOperation() will
   167    * return false until the IOInterposer is initialized.
   168    *
   169    * Remark, it's safe to call this method multiple times, so just call it when
   170    * you to utilize IO interposing.
   171    *
   172    * Using the IOInterposerInit class is preferred to calling this directly.
   173    */
   174   bool Init();
   176   /**
   177    * This function must be called from the main thread, and furthermore
   178    * it must be called when no other threads are executing. Effectively
   179    * restricting us to calling it only during shutdown.
   180    *
   181    * Callers should take care that no other consumers are subscribed to events,
   182    * as these events will stop when this function is called.
   183    *
   184    * In practice, we don't use this method as the IOInterposer is used for
   185    * late-write checks.
   186    */
   187   void Clear();
   189   /**
   190    * This function immediately disables IOInterposer functionality in a fast,
   191    * thread-safe manner. Primarily for use by the crash reporter.
   192    */
   193   void Disable();
   195   /**
   196    * Report IO to registered observers.
   197    * Notice that the reported operation must be either OpRead, OpWrite or
   198    * OpFSync. You are not allowed to report an observation with OpWriteFSync or
   199    * OpAll, these are just auxiliary values for use with Register().
   200    *
   201    * If the IO call you're reporting does multiple things, write and fsync, you
   202    * can choose to call Report() twice once with write and once with FSync. You
   203    * may not call Report() with OpWriteFSync! The Observation::mOperation
   204    * attribute is meant to be generic, not perfect.
   205    *
   206    * Notice that there is no reason to report an observation with an operation
   207    * which is not being observed. Use IsObservedOperation() to check if the
   208    * operation you are about to report is being observed. This is especially
   209    * important if you are constructing expensive observations containing
   210    * filename and full-path.
   211    *
   212    * Remark: Init() must be called before any IO is reported. But
   213    * IsObservedOperation() will return false until Init() is called.
   214    */
   215   void Report(IOInterposeObserver::Observation& aObservation);
   217   /**
   218    * Return whether or not an operation is observed. Reporters should not
   219    * report operations that are not being observed by anybody. This mechanism
   220    * allows us to avoid reporting I/O when no observers are registered.
   221    */
   222   bool IsObservedOperation(IOInterposeObserver::Operation aOp);
   224   /**
   225    * Register IOInterposeObserver, the observer object will receive all
   226    * observations for the given operation aOp.
   227    *
   228    * Remark: Init() must be called before observers are registered.
   229    */
   230   void Register(IOInterposeObserver::Operation aOp,
   231                 IOInterposeObserver* aObserver);
   233   /**
   234    * Unregister an IOInterposeObserver for a given operation
   235    * Remark: It is always safe to unregister for all operations, even if yoú
   236    * didn't register for them all.
   237    * I.e. IOInterposer::Unregister(IOInterposeObserver::OpAll, aObserver)
   238    *
   239    * Remark: Init() must be called before observers are unregistered.
   240    */
   241   void Unregister(IOInterposeObserver::Operation aOp,
   242                   IOInterposeObserver* aObserver);
   244   /**
   245    * Registers the current thread with the IOInterposer. This must be done to
   246    * ensure that per-thread data is created in an orderly fashion.
   247    * We could have written this to initialize that data lazily, however this
   248    * could have unintended consequences if a thread that is not aware of
   249    * IOInterposer was implicitly registered: its per-thread data would never
   250    * be deleted because it would not know to unregister itself.
   251    *
   252    * @param aIsMainThread true if IOInterposer should treat the current thread
   253    *                      as the main thread.
   254    */
   255   void
   256   RegisterCurrentThread(bool aIsMainThread = false);
   258   /**
   259    * Unregisters the current thread with the IOInterposer. This is important
   260    * to call when a thread is shutting down because it cleans up data that
   261    * is stored in a TLS slot.
   262    */
   263   void
   264   UnregisterCurrentThread();
   266   /**
   267    * Called to inform observers that the process has transitioned out of the
   268    * startup stage or into the shutdown stage. Main thread only.
   269    */
   270   void
   271   EnteringNextStage();
   272 } // namespace IOInterposer
   274 class IOInterposerInit
   275 {
   276 public:
   277   IOInterposerInit()
   278   {
   279 #if defined(MOZ_ENABLE_PROFILER_SPS)
   280     IOInterposer::Init();
   281 #endif
   282   }
   284   // No destructor needed at the moment -- this stuff stays active for the
   285   // life of the process. This may change in the future.
   286 };
   288 } // namespace mozilla
   290 #endif // mozilla_IOInterposer_h

mercurial