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

Generated by: LCOV version 1.13