Bug 1600800: Force device pixels to be 1.0 for wpt reftests r=jgraham
[gecko.git] / toolkit / recordreplay / File.h
blob093d5a43164a6d3438cedc38a1186d9c63d0de93
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_recordreplay_File_h
8 #define mozilla_recordreplay_File_h
10 #include "InfallibleVector.h"
11 #include "ProcessRecordReplay.h"
12 #include "SpinLock.h"
14 #include "mozilla/PodOperations.h"
15 #include "mozilla/RecordReplay.h"
16 #include "mozilla/UniquePtr.h"
18 namespace mozilla {
19 namespace recordreplay {
21 // Structure managing file I/O. Each file contains an index for a set of named
22 // streams, whose contents are compressed and interleaved throughout the file.
23 // Additionally, we directly manage the file handle and all associated memory.
24 // This makes it easier to restore memory snapshots without getting confused
25 // about the state of the file handles which the process has opened. Data
26 // written and read from files is automatically compressed with LZ4.
28 // Files are used internally for any disk accesses which the record/replay
29 // infrastructure needs to make. Currently, this is only for accessing the
30 // recording file.
32 // File is threadsafe for simultaneous read/read and write/write accesses.
33 // Stream is not threadsafe.
35 // A location of a chunk of a stream within a file.
36 struct StreamChunkLocation {
37 // Offset into the file of the start of the chunk.
38 uint64_t mOffset;
40 // Compressed (stored) size of the chunk.
41 uint32_t mCompressedSize;
43 // Decompressed size of the chunk.
44 uint32_t mDecompressedSize;
46 // Hash of the compressed chunk data.
47 uint32_t mHash;
49 // Position in the stream of the start of this chunk.
50 uint64_t mStreamPos;
53 enum class StreamName { Main, Lock, Event, Count };
55 class File;
56 class RecordingEventSection;
58 class Stream {
59 friend class File;
60 friend class RecordingEventSection;
62 // File this stream belongs to.
63 File* mFile;
65 // Prefix name for this stream.
66 StreamName mName;
68 // Index which, when combined to mName, uniquely identifies this stream in
69 // the file.
70 size_t mNameIndex;
72 // When writing, all chunks that have been flushed to disk. When reading, all
73 // chunks in the entire stream.
74 InfallibleVector<StreamChunkLocation> mChunks;
76 // Data buffer.
77 UniquePtr<char[]> mBuffer;
79 // The maximum number of bytes to buffer before compressing and writing to
80 // disk, and the maximum number of bytes that can be decompressed at once.
81 static const size_t BUFFER_MAX = 1024 * 1024;
83 // The capacity of mBuffer, at most BUFFER_MAX.
84 size_t mBufferSize;
86 // During reading, the number of accessible bytes in mBuffer.
87 size_t mBufferLength;
89 // The number of bytes read or written from mBuffer.
90 size_t mBufferPos;
92 // The number of uncompressed bytes read or written from the stream.
93 size_t mStreamPos;
95 // Any buffer available for use when decompressing or compressing data.
96 UniquePtr<char[]> mBallast;
97 size_t mBallastSize;
99 // Any buffer available to check for input mismatches.
100 UniquePtr<char[]> mInputBallast;
101 size_t mInputBallastSize;
103 // The last event in this stream, in case of an input mismatch.
104 ThreadEvent mLastEvent;
106 // The number of chunks that have been completely read or written. When
107 // writing, this equals mChunks.length().
108 size_t mChunkIndex;
110 // When writing, the number of chunks in this stream when the file was last
111 // flushed.
112 size_t mFlushedChunks;
114 // Whether there is a RecordingEventSection instance active for this stream.
115 bool mInRecordingEventSection;
117 Stream(File* aFile, StreamName aName, size_t aNameIndex)
118 : mFile(aFile),
119 mName(aName),
120 mNameIndex(aNameIndex),
121 mBuffer(nullptr),
122 mBufferSize(0),
123 mBufferLength(0),
124 mBufferPos(0),
125 mStreamPos(0),
126 mBallast(nullptr),
127 mBallastSize(0),
128 mInputBallast(nullptr),
129 mInputBallastSize(0),
130 mLastEvent((ThreadEvent)0),
131 mChunkIndex(0),
132 mFlushedChunks(0),
133 mInRecordingEventSection(false) {}
135 public:
136 StreamName Name() const { return mName; }
137 size_t NameIndex() const { return mNameIndex; }
139 void ReadBytes(void* aData, size_t aSize);
140 void WriteBytes(const void* aData, size_t aSize);
141 size_t ReadScalar();
142 void WriteScalar(size_t aValue);
143 bool AtEnd();
145 inline void RecordOrReplayBytes(void* aData, size_t aSize) {
146 if (IsRecording()) {
147 WriteBytes(aData, aSize);
148 } else {
149 ReadBytes(aData, aSize);
153 template <typename T>
154 inline void RecordOrReplayScalar(T* aPtr) {
155 if (IsRecording()) {
156 WriteScalar((size_t)*aPtr);
157 } else {
158 *aPtr = (T)ReadScalar();
162 template <typename T>
163 inline void RecordOrReplayValue(T* aPtr) {
164 RecordOrReplayBytes(aPtr, sizeof(T));
167 // Note a new thread event for this stream, and make sure it is the same
168 // while replaying as it was while recording.
169 void RecordOrReplayThreadEvent(ThreadEvent aEvent);
171 // Replay a thread event without requiring it to be a specific event.
172 ThreadEvent ReplayThreadEvent();
174 // Make sure that a value or buffer is the same while replaying as it was
175 // while recording.
176 void CheckInput(size_t aValue);
177 void CheckInput(const char* aValue);
178 void CheckInput(const void* aData, size_t aSize);
180 inline size_t StreamPosition() { return mStreamPos; }
182 private:
183 enum ShouldCopy { DontCopyExistingData, CopyExistingData };
185 void EnsureMemory(UniquePtr<char[]>* aBuf, size_t* aSize, size_t aNeededSize,
186 size_t aMaxSize, ShouldCopy aCopy);
187 void EnsureInputBallast(size_t aSize);
188 void Flush(bool aTakeLock);
189 const char* ReadInputString();
191 static size_t BallastMaxSize();
194 class File {
195 public:
196 enum Mode { WRITE, READ };
198 friend class Stream;
199 friend class RecordingEventSection;
201 private:
202 // Open file handle, or 0 if closed.
203 FileHandle mFd;
205 // Whether this file is open for writing or reading.
206 Mode mMode;
208 // When writing, the current offset into the file.
209 uint64_t mWriteOffset;
211 // The offset of the last index read or written to the file.
212 uint64_t mLastIndexOffset;
214 // All streams in this file, indexed by stream name and name index.
215 typedef InfallibleVector<UniquePtr<Stream>> StreamVector;
216 StreamVector mStreams[(size_t)StreamName::Count];
218 // Lock protecting access to this file.
219 SpinLock mLock;
221 // When writing, lock for synchronizing file flushes (writer) with other
222 // threads writing to streams in this file (readers).
223 ReadWriteSpinLock mStreamLock;
225 void Clear() {
226 mFd = 0;
227 mMode = READ;
228 mWriteOffset = 0;
229 mLastIndexOffset = 0;
230 for (auto& vector : mStreams) {
231 vector.clear();
233 PodZero(&mLock);
234 PodZero(&mStreamLock);
237 public:
238 File() { Clear(); }
239 ~File() { Close(); }
241 bool Open(const char* aName, Mode aMode);
242 void Close();
244 bool OpenForWriting() const { return mFd && mMode == WRITE; }
245 bool OpenForReading() const { return mFd && mMode == READ; }
247 Stream* OpenStream(StreamName aName, size_t aNameIndex);
249 // Prevent/allow other threads to write to streams in this file.
250 void PreventStreamWrites() { mStreamLock.WriteLock(); }
251 void AllowStreamWrites() { mStreamLock.WriteUnlock(); }
253 // Flush any changes since the last Flush() call to disk, returning whether
254 // there were such changes.
255 bool Flush();
257 enum class ReadIndexResult { InvalidFile, EndOfFile, FoundIndex };
259 // Read any data added to the file by a Flush() call. aUpdatedStreams is
260 // optional and filled in with streams whose contents have changed, and may
261 // have duplicates.
262 ReadIndexResult ReadNextIndex(InfallibleVector<Stream*>* aUpdatedStreams);
264 private:
265 StreamChunkLocation WriteChunk(const char* aStart, size_t aCompressedSize,
266 size_t aDecompressedSize, uint64_t aStreamPos,
267 bool aTakeLock);
268 void ReadChunk(char* aDest, const StreamChunkLocation& aChunk);
271 } // namespace recordreplay
272 } // namespace mozilla
274 #endif // mozilla_recordreplay_File_h