1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/build/IOInterposer.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,290 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#ifndef mozilla_IOInterposer_h 1.9 +#define mozilla_IOInterposer_h 1.10 + 1.11 +#include "mozilla/Attributes.h" 1.12 +#include "mozilla/TimeStamp.h" 1.13 +#include "mozilla/XPCOM.h" 1.14 + 1.15 +namespace mozilla { 1.16 + 1.17 +/** 1.18 + * Interface for I/O interposer observers. This is separate from the 1.19 + * IOInterposer because we have multiple uses for these observations. 1.20 + */ 1.21 +class IOInterposeObserver 1.22 +{ 1.23 +public: 1.24 + enum Operation 1.25 + { 1.26 + OpNone = 0, 1.27 + OpCreateOrOpen = (1 << 0), 1.28 + OpRead = (1 << 1), 1.29 + OpWrite = (1 << 2), 1.30 + OpFSync = (1 << 3), 1.31 + OpStat = (1 << 4), 1.32 + OpClose = (1 << 5), 1.33 + OpNextStage = (1 << 6), // Meta - used when leaving startup, entering shutdown 1.34 + OpWriteFSync = (OpWrite | OpFSync), 1.35 + OpAll = (OpCreateOrOpen | OpRead | OpWrite | OpFSync | OpStat | OpClose), 1.36 + OpAllWithStaging = (OpAll | OpNextStage) 1.37 + }; 1.38 + 1.39 + /** A representation of an I/O observation */ 1.40 + class Observation 1.41 + { 1.42 + protected: 1.43 + /** 1.44 + * This constructor is for use by subclasses that are intended to take 1.45 + * timing measurements via RAII. The |aShouldReport| parameter may be 1.46 + * used to make the measurement and reporting conditional on the 1.47 + * satisfaction of an arbitrary predicate that was evaluated 1.48 + * in the subclass. Note that IOInterposer::IsObservedOperation() is 1.49 + * always ANDed with aShouldReport, so the subclass does not need to 1.50 + * include a call to that function explicitly. 1.51 + */ 1.52 + Observation(Operation aOperation, const char* aReference, 1.53 + bool aShouldReport = true); 1.54 + 1.55 + public: 1.56 + /** 1.57 + * Since this constructor accepts start and end times, it does *not* take 1.58 + * its own timings, nor does it report itself. 1.59 + */ 1.60 + Observation(Operation aOperation, const TimeStamp& aStart, 1.61 + const TimeStamp& aEnd, const char* aReference); 1.62 + 1.63 + /** 1.64 + * Operation observed, this is one of the individual Operation values. 1.65 + * Combinations of these flags are only used when registering observers. 1.66 + */ 1.67 + Operation ObservedOperation() const 1.68 + { 1.69 + return mOperation; 1.70 + } 1.71 + 1.72 + /** 1.73 + * Return the observed operation as a human-readable string. 1.74 + */ 1.75 + const char* ObservedOperationString() const; 1.76 + 1.77 + /** Time at which the I/O operation was started */ 1.78 + TimeStamp Start() const 1.79 + { 1.80 + return mStart; 1.81 + } 1.82 + 1.83 + /** 1.84 + * Time at which the I/O operation ended, for asynchronous methods this is 1.85 + * the time at which the call initiating the asynchronous request returned. 1.86 + */ 1.87 + TimeStamp End() const 1.88 + { 1.89 + return mEnd; 1.90 + } 1.91 + 1.92 + /** 1.93 + * Duration of the operation, for asynchronous I/O methods this is the 1.94 + * duration of the call initiating the asynchronous request. 1.95 + */ 1.96 + TimeDuration Duration() const 1.97 + { 1.98 + return mEnd - mStart; 1.99 + } 1.100 + 1.101 + /** 1.102 + * IO reference, function name or name of component (sqlite) that did IO 1.103 + * this is in addition the generic operation. This attribute may be platform 1.104 + * specific, but should only take a finite number of distinct values. 1.105 + * E.g. sqlite-commit, CreateFile, NtReadFile, fread, fsync, mmap, etc. 1.106 + * I.e. typically the platform specific function that did the IO. 1.107 + */ 1.108 + const char* Reference() const 1.109 + { 1.110 + return mReference; 1.111 + } 1.112 + 1.113 + /** Request filename associated with the I/O operation, null if unknown */ 1.114 + virtual const char16_t* Filename() 1.115 + { 1.116 + return nullptr; 1.117 + } 1.118 + 1.119 + virtual ~Observation() 1.120 + { 1.121 + } 1.122 + 1.123 + protected: 1.124 + void 1.125 + Report(); 1.126 + 1.127 + Operation mOperation; 1.128 + TimeStamp mStart; 1.129 + TimeStamp mEnd; 1.130 + const char* mReference; // Identifies the source of the Observation 1.131 + bool mShouldReport; // Measure and report if true 1.132 + }; 1.133 + 1.134 + /** 1.135 + * Invoked whenever an implementation of the IOInterposeObserver should 1.136 + * observe aObservation. Implement this and do your thing... 1.137 + * But do consider if it is wise to use IO functions in this method, they are 1.138 + * likely to cause recursion :) 1.139 + * At least, see PoisonIOInterposer.h and register your handle as a debug file 1.140 + * even, if you don't initialize the poison IO interposer, someone else might. 1.141 + * 1.142 + * Remark: Observations may occur on any thread. 1.143 + */ 1.144 + virtual void Observe(Observation& aObservation) = 0; 1.145 + 1.146 + virtual ~IOInterposeObserver() 1.147 + { 1.148 + } 1.149 + 1.150 +protected: 1.151 + /** 1.152 + * We don't use NS_IsMainThread() because we need to be able to determine the 1.153 + * main thread outside of XPCOM Initialization. IOInterposer observers should 1.154 + * call this function instead. 1.155 + */ 1.156 + static bool IsMainThread(); 1.157 +}; 1.158 + 1.159 +/** 1.160 + * These functions are responsible for ensuring that events are routed to the 1.161 + * appropriate observers. 1.162 + */ 1.163 +namespace IOInterposer 1.164 +{ 1.165 + /** 1.166 + * This function must be called from the main-thread when no other threads are 1.167 + * running before any of the other methods on this class may be used. 1.168 + * 1.169 + * IO reports can however, safely assume that IsObservedOperation() will 1.170 + * return false until the IOInterposer is initialized. 1.171 + * 1.172 + * Remark, it's safe to call this method multiple times, so just call it when 1.173 + * you to utilize IO interposing. 1.174 + * 1.175 + * Using the IOInterposerInit class is preferred to calling this directly. 1.176 + */ 1.177 + bool Init(); 1.178 + 1.179 + /** 1.180 + * This function must be called from the main thread, and furthermore 1.181 + * it must be called when no other threads are executing. Effectively 1.182 + * restricting us to calling it only during shutdown. 1.183 + * 1.184 + * Callers should take care that no other consumers are subscribed to events, 1.185 + * as these events will stop when this function is called. 1.186 + * 1.187 + * In practice, we don't use this method as the IOInterposer is used for 1.188 + * late-write checks. 1.189 + */ 1.190 + void Clear(); 1.191 + 1.192 + /** 1.193 + * This function immediately disables IOInterposer functionality in a fast, 1.194 + * thread-safe manner. Primarily for use by the crash reporter. 1.195 + */ 1.196 + void Disable(); 1.197 + 1.198 + /** 1.199 + * Report IO to registered observers. 1.200 + * Notice that the reported operation must be either OpRead, OpWrite or 1.201 + * OpFSync. You are not allowed to report an observation with OpWriteFSync or 1.202 + * OpAll, these are just auxiliary values for use with Register(). 1.203 + * 1.204 + * If the IO call you're reporting does multiple things, write and fsync, you 1.205 + * can choose to call Report() twice once with write and once with FSync. You 1.206 + * may not call Report() with OpWriteFSync! The Observation::mOperation 1.207 + * attribute is meant to be generic, not perfect. 1.208 + * 1.209 + * Notice that there is no reason to report an observation with an operation 1.210 + * which is not being observed. Use IsObservedOperation() to check if the 1.211 + * operation you are about to report is being observed. This is especially 1.212 + * important if you are constructing expensive observations containing 1.213 + * filename and full-path. 1.214 + * 1.215 + * Remark: Init() must be called before any IO is reported. But 1.216 + * IsObservedOperation() will return false until Init() is called. 1.217 + */ 1.218 + void Report(IOInterposeObserver::Observation& aObservation); 1.219 + 1.220 + /** 1.221 + * Return whether or not an operation is observed. Reporters should not 1.222 + * report operations that are not being observed by anybody. This mechanism 1.223 + * allows us to avoid reporting I/O when no observers are registered. 1.224 + */ 1.225 + bool IsObservedOperation(IOInterposeObserver::Operation aOp); 1.226 + 1.227 + /** 1.228 + * Register IOInterposeObserver, the observer object will receive all 1.229 + * observations for the given operation aOp. 1.230 + * 1.231 + * Remark: Init() must be called before observers are registered. 1.232 + */ 1.233 + void Register(IOInterposeObserver::Operation aOp, 1.234 + IOInterposeObserver* aObserver); 1.235 + 1.236 + /** 1.237 + * Unregister an IOInterposeObserver for a given operation 1.238 + * Remark: It is always safe to unregister for all operations, even if yoú 1.239 + * didn't register for them all. 1.240 + * I.e. IOInterposer::Unregister(IOInterposeObserver::OpAll, aObserver) 1.241 + * 1.242 + * Remark: Init() must be called before observers are unregistered. 1.243 + */ 1.244 + void Unregister(IOInterposeObserver::Operation aOp, 1.245 + IOInterposeObserver* aObserver); 1.246 + 1.247 + /** 1.248 + * Registers the current thread with the IOInterposer. This must be done to 1.249 + * ensure that per-thread data is created in an orderly fashion. 1.250 + * We could have written this to initialize that data lazily, however this 1.251 + * could have unintended consequences if a thread that is not aware of 1.252 + * IOInterposer was implicitly registered: its per-thread data would never 1.253 + * be deleted because it would not know to unregister itself. 1.254 + * 1.255 + * @param aIsMainThread true if IOInterposer should treat the current thread 1.256 + * as the main thread. 1.257 + */ 1.258 + void 1.259 + RegisterCurrentThread(bool aIsMainThread = false); 1.260 + 1.261 + /** 1.262 + * Unregisters the current thread with the IOInterposer. This is important 1.263 + * to call when a thread is shutting down because it cleans up data that 1.264 + * is stored in a TLS slot. 1.265 + */ 1.266 + void 1.267 + UnregisterCurrentThread(); 1.268 + 1.269 + /** 1.270 + * Called to inform observers that the process has transitioned out of the 1.271 + * startup stage or into the shutdown stage. Main thread only. 1.272 + */ 1.273 + void 1.274 + EnteringNextStage(); 1.275 +} // namespace IOInterposer 1.276 + 1.277 +class IOInterposerInit 1.278 +{ 1.279 +public: 1.280 + IOInterposerInit() 1.281 + { 1.282 +#if defined(MOZ_ENABLE_PROFILER_SPS) 1.283 + IOInterposer::Init(); 1.284 +#endif 1.285 + } 1.286 + 1.287 + // No destructor needed at the moment -- this stuff stays active for the 1.288 + // life of the process. This may change in the future. 1.289 +}; 1.290 + 1.291 +} // namespace mozilla 1.292 + 1.293 +#endif // mozilla_IOInterposer_h