Bug 1883861 - Part 1: Move visitMemoryBarrier into the common CodeGenerator file...
[gecko.git] / xpcom / build / IOInterposer.h
blob34dd337e11a567d3a217ffd2a2bdf6ec80760640
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/. */
7 #ifndef mozilla_IOInterposer_h
8 #define mozilla_IOInterposer_h
10 #include "mozilla/Attributes.h"
11 #include "mozilla/TimeStamp.h"
12 #include "nsString.h"
14 namespace mozilla {
16 /**
17 * Interface for I/O interposer observers. This is separate from the
18 * IOInterposer because we have multiple uses for these observations.
20 class IOInterposeObserver {
21 public:
22 enum Operation {
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 =
31 (1 << 6), // Meta - used when leaving startup, entering shutdown
32 OpWriteFSync = (OpWrite | OpFSync),
33 OpAll = (OpCreateOrOpen | OpRead | OpWrite | OpFSync | OpStat | OpClose),
34 OpAllWithStaging = (OpAll | OpNextStage)
37 /** A representation of an I/O observation */
38 class Observation {
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.
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.
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.
64 Operation ObservedOperation() const { return mOperation; }
66 /**
67 * Return the observed operation as a human-readable string.
69 const char* ObservedOperationString() const;
71 /** Time at which the I/O operation was started */
72 TimeStamp Start() const { return mStart; }
74 /**
75 * Time at which the I/O operation ended, for asynchronous methods this is
76 * the time at which the call initiating the asynchronous request returned.
78 TimeStamp End() const { return mEnd; }
80 /**
81 * Duration of the operation, for asynchronous I/O methods this is the
82 * duration of the call initiating the asynchronous request.
84 TimeDuration Duration() const { return mEnd - mStart; }
86 /**
87 * IO reference, function name or name of component (sqlite) that did IO
88 * this is in addition the generic operation. This attribute may be platform
89 * specific, but should only take a finite number of distinct values.
90 * E.g. sqlite-commit, CreateFile, NtReadFile, fread, fsync, mmap, etc.
91 * I.e. typically the platform specific function that did the IO.
93 const char* Reference() const { return mReference; }
95 virtual const char* FileType() const { return "File"; }
97 /** Request filename associated with the I/O operation, empty if unknown */
98 virtual void Filename(nsAString& aString) { aString.Truncate(); }
100 virtual ~Observation() = default;
102 protected:
103 void Report();
105 Operation mOperation;
106 TimeStamp mStart;
107 TimeStamp mEnd;
108 const char* mReference; // Identifies the source of the Observation
109 bool mShouldReport; // Measure and report if true
113 * Invoked whenever an implementation of the IOInterposeObserver should
114 * observe aObservation. Implement this and do your thing...
115 * But do consider if it is wise to use IO functions in this method, they are
116 * likely to cause recursion :)
117 * At least, see PoisonIOInterposer.h and register your handle as a debug file
118 * even, if you don't initialize the poison IO interposer, someone else might.
120 * Remark: Observations may occur on any thread.
122 virtual void Observe(Observation& aObservation) = 0;
124 virtual ~IOInterposeObserver() = default;
126 protected:
128 * We don't use NS_IsMainThread() because we need to be able to determine the
129 * main thread outside of XPCOM Initialization. IOInterposer observers should
130 * call this function instead.
132 static bool IsMainThread();
136 * These functions are responsible for ensuring that events are routed to the
137 * appropriate observers.
139 namespace IOInterposer {
142 * This function must be called from the main-thread when no other threads are
143 * running before any of the other methods on this class may be used.
145 * IO reports can however, safely assume that IsObservedOperation() will
146 * return false until the IOInterposer is initialized.
148 * Remark, it's safe to call this method multiple times, so just call it when
149 * you to utilize IO interposing.
151 * Using the IOInterposerInit class is preferred to calling this directly.
153 bool Init();
156 * This function must be called from the main thread, and furthermore
157 * it must be called when no other threads are executing. Effectively
158 * restricting us to calling it only during shutdown.
160 * Callers should take care that no other consumers are subscribed to events,
161 * as these events will stop when this function is called.
163 * In practice, we don't use this method as the IOInterposer is used for
164 * late-write checks.
166 void Clear();
169 * This function immediately disables IOInterposer functionality in a fast,
170 * thread-safe manner. Primarily for use by the crash reporter.
172 void Disable();
175 * This function re-enables IOInterposer functionality in a fast, thread-safe
176 * manner. Primarily for use by the crash reporter.
178 void Enable();
181 * Report IO to registered observers.
182 * Notice that the reported operation must be either OpRead, OpWrite or
183 * OpFSync. You are not allowed to report an observation with OpWriteFSync or
184 * OpAll, these are just auxiliary values for use with Register().
186 * If the IO call you're reporting does multiple things, write and fsync, you
187 * can choose to call Report() twice once with write and once with FSync. You
188 * may not call Report() with OpWriteFSync! The Observation::mOperation
189 * attribute is meant to be generic, not perfect.
191 * Notice that there is no reason to report an observation with an operation
192 * which is not being observed. Use IsObservedOperation() to check if the
193 * operation you are about to report is being observed. This is especially
194 * important if you are constructing expensive observations containing
195 * filename and full-path.
197 * Remark: Init() must be called before any IO is reported. But
198 * IsObservedOperation() will return false until Init() is called.
200 void Report(IOInterposeObserver::Observation& aObservation);
203 * Return whether or not an operation is observed. Reporters should not
204 * report operations that are not being observed by anybody. This mechanism
205 * allows us to avoid reporting I/O when no observers are registered.
207 bool IsObservedOperation(IOInterposeObserver::Operation aOp);
210 * Register IOInterposeObserver, the observer object will receive all
211 * observations for the given operation aOp.
213 * Remarks:
214 * - Init() must be called before observers are registered.
215 * - The IOInterposeObserver object should be static, because it could still be
216 * used on another thread shortly after Unregister().
218 void Register(IOInterposeObserver::Operation aOp,
219 IOInterposeObserver* aStaticObserver);
222 * Unregister an IOInterposeObserver for a given operation
223 * Remark: It is always safe to unregister for all operations, even if yoú
224 * didn't register for them all.
225 * I.e. IOInterposer::Unregister(IOInterposeObserver::OpAll, aObserver)
227 * Remarks:
228 * - Init() must be called before observers are registered.
229 * - The IOInterposeObserver object should be static, because it could still be
230 * used on another thread shortly after this Unregister() call.
232 void Unregister(IOInterposeObserver::Operation aOp,
233 IOInterposeObserver* aStaticObserver);
236 * Registers the current thread with the IOInterposer. This must be done to
237 * ensure that per-thread data is created in an orderly fashion.
238 * We could have written this to initialize that data lazily, however this
239 * could have unintended consequences if a thread that is not aware of
240 * IOInterposer was implicitly registered: its per-thread data would never
241 * be deleted because it would not know to unregister itself.
243 * @param aIsMainThread true if IOInterposer should treat the current thread
244 * as the main thread.
246 void RegisterCurrentThread(bool aIsMainThread = false);
249 * Unregisters the current thread with the IOInterposer. This is important
250 * to call when a thread is shutting down because it cleans up data that
251 * is stored in a TLS slot.
253 void UnregisterCurrentThread();
256 * Called to inform observers that the process has transitioned out of the
257 * startup stage or into the shutdown stage. Main thread only.
259 void EnteringNextStage();
261 } // namespace IOInterposer
263 class MOZ_RAII AutoIOInterposer {
264 public:
265 AutoIOInterposer() = default;
267 void Init() {
268 #if defined(EARLY_BETA_OR_EARLIER)
269 IOInterposer::Init();
270 #endif
273 ~AutoIOInterposer() {
274 #if defined(EARLY_BETA_OR_EARLIER)
275 IOInterposer::Clear();
276 #endif
280 class MOZ_RAII AutoIOInterposerDisable final {
281 public:
282 explicit AutoIOInterposerDisable() { IOInterposer::Disable(); }
283 ~AutoIOInterposerDisable() { IOInterposer::Enable(); }
285 private:
288 } // namespace mozilla
290 #endif // mozilla_IOInterposer_h