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_layers_CanvasDrawEventRecorder_h
8 #define mozilla_layers_CanvasDrawEventRecorder_h
10 #include "mozilla/gfx/DrawEventRecorder.h"
11 #include "mozilla/ipc/CrossProcessSemaphore.h"
12 #include "mozilla/ipc/SharedMemoryBasic.h"
17 class CanvasEventRingBuffer final
: public gfx::EventRingBuffer
{
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.
24 class WriterServices
{
26 virtual ~WriterServices() = default;
29 * @returns true if the reader of the CanvasEventRingBuffer has permanently
30 * stopped processing, otherwise returns false.
32 virtual bool ReaderClosed() = 0;
35 * Causes the reader to resume processing when it is in a stopped state.
37 virtual void ResumeReader() = 0;
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.
45 class ReaderServices
{
47 virtual ~ReaderServices() = default;
50 * @returns true if the writer of the CanvasEventRingBuffer has permanently
51 * stopped processing, otherwise returns false.
53 virtual bool WriterClosed() = 0;
56 CanvasEventRingBuffer() {}
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.
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
70 bool InitWriter(base::ProcessId aOtherPid
,
71 ipc::SharedMemoryBasic::Handle
* aReadHandle
,
72 CrossProcessSemaphoreHandle
* aReaderSem
,
73 CrossProcessSemaphoreHandle
* aWriterSem
,
74 UniquePtr
<WriterServices
> aWriterServices
);
77 * Initialize the read side of a CanvasEventRingBuffer.
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
85 bool InitReader(ipc::SharedMemoryBasic::Handle aReadHandle
,
86 CrossProcessSemaphoreHandle aReaderSem
,
87 CrossProcessSemaphoreHandle aWriterSem
,
88 UniquePtr
<ReaderServices
> aReaderServices
);
90 bool good() const final
{ return mGood
; }
92 bool WriterFailed() const { return mWrite
->state
== State::Failed
; }
94 void SetIsBad() final
{
96 mRead
->state
= State::Failed
;
99 void write(const char* const aData
, const size_t aSize
) final
;
101 bool HasDataToRead();
104 * This will put the reader into a stopped state if there is no more data to
105 * read. If this returns false the caller is responsible for continuing
106 * translation at a later point. If it returns false the writer will start the
107 * translation again when more data is written.
109 * @returns true if stopped
114 * Waits for data to become available. This will wait for aTimeout duration
115 * aRetryCount number of times, checking to see if the other side is closed in
118 * @param aTimeout duration to wait
119 * @param aRetryCount number of times to retry
120 * @returns true if data is available to read.
122 bool WaitForDataToRead(TimeDuration aTimeout
, int32_t aRetryCount
);
124 int32_t ReadNextEvent();
126 void read(char* const aOut
, const size_t aSize
) final
;
129 * Writes a checkpoint event to the buffer.
131 * @returns the write count after the checkpoint has been written
133 uint32_t CreateCheckpoint();
136 * Waits until the given checkpoint has been read from the buffer.
138 * @params aCheckpoint the checkpoint to wait for
139 * @params aTimeout duration to wait while reader is not active
140 * @returns true if the checkpoint was reached, false if the reader is closed
143 bool WaitForCheckpoint(uint32_t aCheckpoint
);
146 * Used to send data back to the writer. This is done through the same shared
147 * memory so the writer must wait and read the response after it has submitted
148 * the event that uses this.
150 * @param aData the data to be written back to the writer
151 * @param aSize the number of chars to write
153 void ReturnWrite(const char* aData
, size_t aSize
);
156 * Used to read data sent back from the reader via ReturnWrite. This is done
157 * through the same shared memory so the writer must wait until all expected
158 * data is read before writing new events to the buffer.
160 * @param aOut the pointer to read into
161 * @param aSize the number of chars to read
163 void ReturnRead(char* aOut
, size_t aSize
);
166 bool WaitForAndRecalculateAvailableSpace() final
;
167 void UpdateWriteTotalsBy(uint32_t aCount
) final
;
170 enum class State
: uint32_t {
174 * This is the important state to make sure the other side signals or starts
175 * us as soon as data or space is available. We set AboutToWait first and
176 * then re-check the condition. If we went straight to Waiting or Stopped
177 * then in between the last check and setting the state, the other side
178 * could have used all available data or space and never have signaled us
179 * because it didn't know we were about to wait, causing a deadlock.
180 * While we are in this state, the other side must wait until we resolve the
181 * AboutToWait state to one of the other states and then signal or start us
191 Atomic
<uint32_t> count
;
192 Atomic
<uint32_t> returnCount
;
197 Atomic
<uint32_t> count
;
198 Atomic
<uint32_t> returnCount
;
199 Atomic
<uint32_t> requiredDifference
;
203 CanvasEventRingBuffer(const CanvasEventRingBuffer
&) = delete;
204 void operator=(const CanvasEventRingBuffer
&) = delete;
206 void IncrementWriteCountBy(uint32_t aCount
);
208 bool WaitForReadCount(uint32_t aReadCount
, TimeDuration aTimeout
);
210 bool WaitForAndRecalculateAvailableData();
212 void UpdateReadTotalsBy(uint32_t aCount
);
213 void IncrementReadCountBy(uint32_t aCount
);
215 void CheckAndSignalReader();
217 void CheckAndSignalWriter();
219 uint32_t WaitForBytesToWrite();
221 uint32_t WaitForBytesToRead();
223 RefPtr
<ipc::SharedMemoryBasic
> mSharedMemory
;
224 UniquePtr
<CrossProcessSemaphore
> mReaderSemaphore
;
225 UniquePtr
<CrossProcessSemaphore
> mWriterSemaphore
;
226 UniquePtr
<WriterServices
> mWriterServices
;
227 UniquePtr
<ReaderServices
> mReaderServices
;
228 char* mBuf
= nullptr;
229 uint32_t mOurCount
= 0;
230 WriteFooter
* mWrite
= nullptr;
231 ReadFooter
* mRead
= nullptr;
235 class CanvasDrawEventRecorder final
: public gfx::DrawEventRecorderPrivate
{
237 MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(CanvasDrawEventRecorder
, final
)
238 explicit CanvasDrawEventRecorder(){};
240 bool Init(base::ProcessId aOtherPid
, ipc::SharedMemoryBasic::Handle
* aHandle
,
241 CrossProcessSemaphoreHandle
* aReaderSem
,
242 CrossProcessSemaphoreHandle
* aWriterSem
,
243 UniquePtr
<CanvasEventRingBuffer::WriterServices
> aWriterServices
) {
244 return mOutputStream
.InitWriter(aOtherPid
, aHandle
, aReaderSem
, aWriterSem
,
245 std::move(aWriterServices
));
248 void RecordEvent(const gfx::RecordedEvent
& aEvent
) final
{
249 if (!mOutputStream
.good()) {
253 aEvent
.RecordToStream(mOutputStream
);
256 void StoreSourceSurfaceRecording(gfx::SourceSurface
* aSurface
,
257 const char* aReason
) final
;
259 void Flush() final
{}
261 void ReturnRead(char* aOut
, size_t aSize
) {
262 mOutputStream
.ReturnRead(aOut
, aSize
);
265 uint32_t CreateCheckpoint() { return mOutputStream
.CreateCheckpoint(); }
268 * Waits until the given checkpoint has been read by the translator.
270 * @params aCheckpoint the checkpoint to wait for
271 * @returns true if the checkpoint was reached, false if the reader is closed
274 bool WaitForCheckpoint(uint32_t aCheckpoint
) {
275 return mOutputStream
.WaitForCheckpoint(aCheckpoint
);
279 CanvasEventRingBuffer mOutputStream
;
282 } // namespace layers
283 } // namespace mozilla
285 #endif // mozilla_layers_CanvasDrawEventRecorder_h