xpcom/build/IOInterposer.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial