Source code

Revision control

Other Tools

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_layers_CanvasDrawEventRecorder_h
8
#define mozilla_layers_CanvasDrawEventRecorder_h
9
10
#include "mozilla/gfx/DrawEventRecorder.h"
11
#include "mozilla/ipc/CrossProcessSemaphore.h"
12
#include "mozilla/ipc/SharedMemoryBasic.h"
13
14
namespace mozilla {
15
namespace layers {
16
17
class CanvasEventRingBuffer final : public gfx::EventRingBuffer {
18
public:
19
/**
20
* WriterServices allows consumers of CanvasEventRingBuffer to provide
21
* functions required by the write side of a CanvasEventRingBuffer without
22
* introducing unnecessary dependencies on IPC code.
23
*/
24
class WriterServices {
25
public:
26
virtual ~WriterServices() = default;
27
28
/**
29
* @returns true if the reader of the CanvasEventRingBuffer has permanently
30
* stopped processing, otherwise returns false.
31
*/
32
virtual bool ReaderClosed() = 0;
33
34
/**
35
* Causes the reader to resume processing when it is in a stopped state.
36
*/
37
virtual void ResumeReader() = 0;
38
};
39
40
/**
41
* ReaderServices allows consumers of CanvasEventRingBuffer to provide
42
* functions required by the read side of a CanvasEventRingBuffer without
43
* introducing unnecessary dependencies on IPC code.
44
*/
45
class ReaderServices {
46
public:
47
virtual ~ReaderServices() = default;
48
49
/**
50
* @returns true if the writer of the CanvasEventRingBuffer has permanently
51
* stopped processing, otherwise returns false.
52
*/
53
virtual bool WriterClosed() = 0;
54
};
55
56
CanvasEventRingBuffer() {}
57
58
/**
59
* Initialize the write side of a CanvasEventRingBuffer returning handles to
60
* the shared memory for the buffer and the two semaphores for waiting in the
61
* reader and the writer.
62
*
63
* @param aOtherPid process ID to share the handles to
64
* @param aReadHandle handle to the shared memory for the buffer
65
* @param aReaderSem reading blocked semaphore
66
* @param aWriterSem writing blocked semaphore
67
* @param aWriterServices provides functions required by the writer
68
* @returns true if initialization succeeds
69
*/
70
bool InitWriter(base::ProcessId aOtherPid,
71
ipc::SharedMemoryBasic::Handle* aReadHandle,
72
CrossProcessSemaphoreHandle* aReaderSem,
73
CrossProcessSemaphoreHandle* aWriterSem,
74
UniquePtr<WriterServices> aWriterServices);
75
76
/**
77
* Initialize the read side of a CanvasEventRingBuffer.
78
*
79
* @param aReadHandle handle to the shared memory for the buffer
80
* @param aReaderSem reading blocked semaphore
81
* @param aWriterSem writing blocked semaphore
82
* @param aReaderServices provides functions required by the reader
83
* @returns true if initialization succeeds
84
*/
85
bool InitReader(const ipc::SharedMemoryBasic::Handle& aReadHandle,
86
const CrossProcessSemaphoreHandle& aReaderSem,
87
const CrossProcessSemaphoreHandle& aWriterSem,
88
UniquePtr<ReaderServices> aReaderServices);
89
90
bool good() const final { return mGood; }
91
92
void SetIsBad() final { mGood = false; }
93
94
void write(const char* const aData, const size_t aSize) final;
95
96
bool HasDataToRead();
97
98
/*
99
* This will put the reader into a stopped state if there is no more data to
100
* read. If this returns false the caller is responsible for continuing
101
* translation at a later point. If it returns false the writer will start the
102
* translation again when more data is written.
103
*
104
* @returns true if stopped
105
*/
106
bool StopIfEmpty();
107
108
/*
109
* Waits for data to become available. This will wait for aTimeout duration
110
* aRetryCount number of times, checking to see if the other side is closed in
111
* between each one.
112
*
113
* @param aTimeout duration to wait
114
* @param aRetryCount number of times to retry
115
* @returns true if data is available to read.
116
*/
117
bool WaitForDataToRead(TimeDuration aTimeout, int32_t aRetryCount);
118
119
int32_t ReadNextEvent();
120
121
void read(char* const aOut, const size_t aSize) final;
122
123
/**
124
* Writes a checkpoint event to the buffer.
125
*
126
* @returns the write count after the checkpoint has been written
127
*/
128
uint32_t CreateCheckpoint();
129
130
/**
131
* Waits until the given checkpoint has been read from the buffer.
132
*
133
* @params aCheckpoint the checkpoint to wait for
134
* @params aTimeout duration to wait while reader is not active
135
* @returns true if the checkpoint was reached, false if the reader is closed
136
* or we timeout.
137
*/
138
bool WaitForCheckpoint(uint32_t aCheckpoint);
139
140
/**
141
* Used to send data back to the writer. This is done through the same shared
142
* memory so the writer must wait and read the response after it has submitted
143
* the event that uses this.
144
*
145
* @param aData the data to be written back to the writer
146
* @param aSize the number of chars to write
147
*/
148
void ReturnWrite(const char* aData, size_t aSize);
149
150
/**
151
* Used to read data sent back from the reader via ReturnWrite. This is done
152
* through the same shared memory so the writer must wait until all expected
153
* data is read before writing new events to the buffer.
154
*
155
* @param aOut the pointer to read into
156
* @param aSize the number of chars to read
157
*/
158
void ReturnRead(char* aOut, size_t aSize);
159
160
protected:
161
bool WaitForAndRecalculateAvailableSpace() final;
162
void UpdateWriteTotalsBy(uint32_t aCount) final;
163
164
private:
165
enum class State : uint32_t {
166
Processing,
167
168
/**
169
* This is the important state to make sure the other side signals or starts
170
* us as soon as data or space is available. We set AboutToWait first and
171
* then re-check the condition. If we went straight to Waiting or Stopped
172
* then in between the last check and setting the state, the other side
173
* could have used all available data or space and never have signaled us
174
* because it didn't know we were about to wait, causing a deadlock.
175
* While we are in this state, the other side must wait until we resolve the
176
* AboutToWait state to one of the other states and then signal or start us
177
* if it needs to.
178
*/
179
AboutToWait,
180
Waiting,
181
Stopped
182
};
183
184
struct ReadFooter {
185
Atomic<uint32_t, ReleaseAcquire> count;
186
Atomic<uint32_t, ReleaseAcquire> returnCount;
187
Atomic<State, ReleaseAcquire> state;
188
};
189
190
struct WriteFooter {
191
Atomic<uint32_t, ReleaseAcquire> count;
192
Atomic<uint32_t, ReleaseAcquire> returnCount;
193
Atomic<uint32_t, ReleaseAcquire> requiredDifference;
194
Atomic<State, ReleaseAcquire> state;
195
};
196
197
CanvasEventRingBuffer(const CanvasEventRingBuffer&) = delete;
198
void operator=(const CanvasEventRingBuffer&) = delete;
199
200
void IncrementWriteCountBy(uint32_t aCount);
201
202
bool WaitForReadCount(uint32_t aReadCount, TimeDuration aTimeout);
203
204
bool WaitForAndRecalculateAvailableData();
205
206
void UpdateReadTotalsBy(uint32_t aCount);
207
void IncrementReadCountBy(uint32_t aCount);
208
209
void CheckAndSignalReader();
210
211
void CheckAndSignalWriter();
212
213
uint32_t WaitForBytesToWrite();
214
215
uint32_t WaitForBytesToRead();
216
217
RefPtr<ipc::SharedMemoryBasic> mSharedMemory;
218
UniquePtr<CrossProcessSemaphore> mReaderSemaphore;
219
UniquePtr<CrossProcessSemaphore> mWriterSemaphore;
220
UniquePtr<WriterServices> mWriterServices;
221
UniquePtr<ReaderServices> mReaderServices;
222
char* mBuf = nullptr;
223
uint32_t mOurCount = 0;
224
WriteFooter* mWrite = nullptr;
225
ReadFooter* mRead = nullptr;
226
bool mGood = false;
227
};
228
229
class CanvasDrawEventRecorder final : public gfx::DrawEventRecorderPrivate {
230
public:
231
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(CanvasDrawEventRecorder, final)
232
explicit CanvasDrawEventRecorder(){};
233
234
bool Init(base::ProcessId aOtherPid, ipc::SharedMemoryBasic::Handle* aHandle,
235
CrossProcessSemaphoreHandle* aReaderSem,
236
CrossProcessSemaphoreHandle* aWriterSem,
237
UniquePtr<CanvasEventRingBuffer::WriterServices> aWriterServices) {
238
return mOutputStream.InitWriter(aOtherPid, aHandle, aReaderSem, aWriterSem,
239
std::move(aWriterServices));
240
}
241
242
void RecordEvent(const gfx::RecordedEvent& aEvent) final {
243
if (!mOutputStream.good()) {
244
return;
245
}
246
247
aEvent.RecordToStream(mOutputStream);
248
}
249
250
void Flush() final {}
251
252
void ReturnRead(char* aOut, size_t aSize) {
253
mOutputStream.ReturnRead(aOut, aSize);
254
}
255
256
uint32_t CreateCheckpoint() { return mOutputStream.CreateCheckpoint(); }
257
258
/**
259
* Waits until the given checkpoint has been read by the translator.
260
*
261
* @params aCheckpoint the checkpoint to wait for
262
* @returns true if the checkpoint was reached, false if the reader is closed
263
* or we timeout.
264
*/
265
bool WaitForCheckpoint(uint32_t aCheckpoint) {
266
return mOutputStream.WaitForCheckpoint(aCheckpoint);
267
}
268
269
private:
270
CanvasEventRingBuffer mOutputStream;
271
};
272
273
} // namespace layers
274
} // namespace mozilla
275
276
#endif // mozilla_layers_CanvasDrawEventRecorder_h