• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "SkRWBuffer.h"
9 
10 #include "SkAtomics.h"
11 #include "SkMalloc.h"
12 #include "SkStream.h"
13 
14 // Force small chunks to be a page's worth
15 static const size_t kMinAllocSize = 4096;
16 
17 struct SkBufferBlock {
18     SkBufferBlock*  fNext;      // updated by the writer
19     size_t          fUsed;      // updated by the writer
20     const size_t    fCapacity;
21 
SkBufferBlockSkBufferBlock22     SkBufferBlock(size_t capacity) : fNext(nullptr), fUsed(0), fCapacity(capacity) {}
23 
startDataSkBufferBlock24     const void* startData() const { return this + 1; }
25 
availSkBufferBlock26     size_t avail() const { return fCapacity - fUsed; }
availDataSkBufferBlock27     void* availData() { return (char*)this->startData() + fUsed; }
28 
AllocSkBufferBlock29     static SkBufferBlock* Alloc(size_t length) {
30         size_t capacity = LengthToCapacity(length);
31         void* buffer = sk_malloc_throw(sizeof(SkBufferBlock) + capacity);
32         return new (buffer) SkBufferBlock(capacity);
33     }
34 
35     // Return number of bytes actually appended. Important that we always completely this block
36     // before spilling into the next, since the reader uses fCapacity to know how many it can read.
37     //
appendSkBufferBlock38     size_t append(const void* src, size_t length) {
39         this->validate();
40         size_t amount = SkTMin(this->avail(), length);
41         memcpy(this->availData(), src, amount);
42         fUsed += amount;
43         this->validate();
44         return amount;
45     }
46 
47     // Do not call in the reader thread, since the writer may be updating fUsed.
48     // (The assertion is still true, but TSAN still may complain about its raciness.)
validateSkBufferBlock49     void validate() const {
50 #ifdef SK_DEBUG
51         SkASSERT(fCapacity > 0);
52         SkASSERT(fUsed <= fCapacity);
53 #endif
54     }
55 
56 private:
LengthToCapacitySkBufferBlock57     static size_t LengthToCapacity(size_t length) {
58         const size_t minSize = kMinAllocSize - sizeof(SkBufferBlock);
59         return SkTMax(length, minSize);
60     }
61 };
62 
63 struct SkBufferHead {
64     mutable int32_t fRefCnt;
65     SkBufferBlock   fBlock;
66 
SkBufferHeadSkBufferHead67     SkBufferHead(size_t capacity) : fRefCnt(1), fBlock(capacity) {}
68 
LengthToCapacitySkBufferHead69     static size_t LengthToCapacity(size_t length) {
70         const size_t minSize = kMinAllocSize - sizeof(SkBufferHead);
71         return SkTMax(length, minSize);
72     }
73 
AllocSkBufferHead74     static SkBufferHead* Alloc(size_t length) {
75         size_t capacity = LengthToCapacity(length);
76         size_t size = sizeof(SkBufferHead) + capacity;
77         void* buffer = sk_malloc_throw(size);
78         return new (buffer) SkBufferHead(capacity);
79     }
80 
refSkBufferHead81     void ref() const {
82         SkASSERT(fRefCnt > 0);
83         sk_atomic_inc(&fRefCnt);
84     }
85 
unrefSkBufferHead86     void unref() const {
87         SkASSERT(fRefCnt > 0);
88         // A release here acts in place of all releases we "should" have been doing in ref().
89         if (1 == sk_atomic_fetch_add(&fRefCnt, -1, sk_memory_order_acq_rel)) {
90             // Like unique(), the acquire is only needed on success.
91             SkBufferBlock* block = fBlock.fNext;
92             sk_free((void*)this);
93             while (block) {
94                 SkBufferBlock* next = block->fNext;
95                 sk_free(block);
96                 block = next;
97             }
98         }
99     }
100 
validateSkBufferHead101     void validate(size_t minUsed, const SkBufferBlock* tail = nullptr) const {
102 #ifdef SK_DEBUG
103         SkASSERT(fRefCnt > 0);
104         size_t totalUsed = 0;
105         const SkBufferBlock* block = &fBlock;
106         const SkBufferBlock* lastBlock = block;
107         while (block) {
108             block->validate();
109             totalUsed += block->fUsed;
110             lastBlock = block;
111             block = block->fNext;
112         }
113         SkASSERT(minUsed <= totalUsed);
114         if (tail) {
115             SkASSERT(tail == lastBlock);
116         }
117 #endif
118     }
119 };
120 
121 ///////////////////////////////////////////////////////////////////////////////////////////////////
122 // The reader can only access block.fCapacity (which never changes), and cannot access
123 // block.fUsed, which may be updated by the writer.
124 //
SkROBuffer(const SkBufferHead * head,size_t available,const SkBufferBlock * tail)125 SkROBuffer::SkROBuffer(const SkBufferHead* head, size_t available, const SkBufferBlock* tail)
126     : fHead(head), fAvailable(available), fTail(tail)
127 {
128     if (head) {
129         fHead->ref();
130         SkASSERT(available > 0);
131         head->validate(available, tail);
132     } else {
133         SkASSERT(0 == available);
134         SkASSERT(!tail);
135     }
136 }
137 
~SkROBuffer()138 SkROBuffer::~SkROBuffer() {
139     if (fHead) {
140         fHead->unref();
141     }
142 }
143 
Iter(const SkROBuffer * buffer)144 SkROBuffer::Iter::Iter(const SkROBuffer* buffer) {
145     this->reset(buffer);
146 }
147 
reset(const SkROBuffer * buffer)148 void SkROBuffer::Iter::reset(const SkROBuffer* buffer) {
149     fBuffer = buffer;
150     if (buffer && buffer->fHead) {
151         fBlock = &buffer->fHead->fBlock;
152         fRemaining = buffer->fAvailable;
153     } else {
154         fBlock = nullptr;
155         fRemaining = 0;
156     }
157 }
158 
data() const159 const void* SkROBuffer::Iter::data() const {
160     return fRemaining ? fBlock->startData() : nullptr;
161 }
162 
size() const163 size_t SkROBuffer::Iter::size() const {
164     if (!fBlock) {
165         return 0;
166     }
167     return SkTMin(fBlock->fCapacity, fRemaining);
168 }
169 
next()170 bool SkROBuffer::Iter::next() {
171     if (fRemaining) {
172         fRemaining -= this->size();
173         if (fBuffer->fTail == fBlock) {
174             // There are more blocks, but fBuffer does not know about them.
175             SkASSERT(0 == fRemaining);
176             fBlock = nullptr;
177         } else {
178             fBlock = fBlock->fNext;
179         }
180     }
181     return fRemaining != 0;
182 }
183 
184 ///////////////////////////////////////////////////////////////////////////////////////////////////
185 
SkRWBuffer(size_t initialCapacity)186 SkRWBuffer::SkRWBuffer(size_t initialCapacity) : fHead(nullptr), fTail(nullptr), fTotalUsed(0) {
187     if (initialCapacity) {
188         fHead = SkBufferHead::Alloc(initialCapacity);
189         fTail = &fHead->fBlock;
190     }
191 }
192 
~SkRWBuffer()193 SkRWBuffer::~SkRWBuffer() {
194     this->validate();
195     if (fHead) {
196         fHead->unref();
197     }
198 }
199 
200 // It is important that we always completely fill the current block before spilling over to the
201 // next, since our reader will be using fCapacity (min'd against its total available) to know how
202 // many bytes to read from a given block.
203 //
append(const void * src,size_t length,size_t reserve)204 void SkRWBuffer::append(const void* src, size_t length, size_t reserve) {
205     this->validate();
206     if (0 == length) {
207         return;
208     }
209 
210     fTotalUsed += length;
211 
212     if (nullptr == fHead) {
213         fHead = SkBufferHead::Alloc(length + reserve);
214         fTail = &fHead->fBlock;
215     }
216 
217     size_t written = fTail->append(src, length);
218     SkASSERT(written <= length);
219     src = (const char*)src + written;
220     length -= written;
221 
222     if (length) {
223         SkBufferBlock* block = SkBufferBlock::Alloc(length + reserve);
224         fTail->fNext = block;
225         fTail = block;
226         written = fTail->append(src, length);
227         SkASSERT(written == length);
228     }
229     this->validate();
230 }
231 
232 #ifdef SK_DEBUG
validate() const233 void SkRWBuffer::validate() const {
234     if (fHead) {
235         fHead->validate(fTotalUsed, fTail);
236     } else {
237         SkASSERT(nullptr == fTail);
238         SkASSERT(0 == fTotalUsed);
239     }
240 }
241 #endif
242 
newRBufferSnapshot() const243 SkROBuffer* SkRWBuffer::newRBufferSnapshot() const {
244     return new SkROBuffer(fHead, fTotalUsed, fTail);
245 }
246 
247 ///////////////////////////////////////////////////////////////////////////////////////////////////
248 
249 class SkROBufferStreamAsset : public SkStreamAsset {
validate() const250     void validate() const {
251 #ifdef SK_DEBUG
252         SkASSERT(fGlobalOffset <= fBuffer->size());
253         SkASSERT(fLocalOffset <= fIter.size());
254         SkASSERT(fLocalOffset <= fGlobalOffset);
255 #endif
256     }
257 
258 #ifdef SK_DEBUG
259     class AutoValidate {
260         SkROBufferStreamAsset* fStream;
261     public:
AutoValidate(SkROBufferStreamAsset * stream)262         AutoValidate(SkROBufferStreamAsset* stream) : fStream(stream) { stream->validate(); }
~AutoValidate()263         ~AutoValidate() { fStream->validate(); }
264     };
265     #define AUTO_VALIDATE   AutoValidate av(this);
266 #else
267     #define AUTO_VALIDATE
268 #endif
269 
270 public:
SkROBufferStreamAsset(const SkROBuffer * buffer)271     SkROBufferStreamAsset(const SkROBuffer* buffer) : fBuffer(SkRef(buffer)), fIter(buffer) {
272         fGlobalOffset = fLocalOffset = 0;
273     }
274 
~SkROBufferStreamAsset()275     ~SkROBufferStreamAsset() override { fBuffer->unref(); }
276 
getLength() const277     size_t getLength() const override { return fBuffer->size(); }
278 
rewind()279     bool rewind() override {
280         AUTO_VALIDATE
281         fIter.reset(fBuffer);
282         fGlobalOffset = fLocalOffset = 0;
283         return true;
284     }
285 
read(void * dst,size_t request)286     size_t read(void* dst, size_t request) override {
287         AUTO_VALIDATE
288         size_t bytesRead = 0;
289         for (;;) {
290             size_t size = fIter.size();
291             SkASSERT(fLocalOffset <= size);
292             size_t avail = SkTMin(size - fLocalOffset, request - bytesRead);
293             if (dst) {
294                 memcpy(dst, (const char*)fIter.data() + fLocalOffset, avail);
295                 dst = (char*)dst + avail;
296             }
297             bytesRead += avail;
298             fLocalOffset += avail;
299             SkASSERT(bytesRead <= request);
300             if (bytesRead == request) {
301                 break;
302             }
303             // If we get here, we've exhausted the current iter
304             SkASSERT(fLocalOffset == size);
305             fLocalOffset = 0;
306             if (!fIter.next()) {
307                 break;   // ran out of data
308             }
309         }
310         fGlobalOffset += bytesRead;
311         SkASSERT(fGlobalOffset <= fBuffer->size());
312         return bytesRead;
313     }
314 
isAtEnd() const315     bool isAtEnd() const override {
316         return fBuffer->size() == fGlobalOffset;
317     }
318 
duplicate() const319     SkStreamAsset* duplicate() const override { return new SkROBufferStreamAsset(fBuffer); }
320 
getPosition() const321     size_t getPosition() const override {
322         return fGlobalOffset;
323     }
324 
seek(size_t position)325     bool seek(size_t position) override {
326         AUTO_VALIDATE
327         if (position < fGlobalOffset) {
328             this->rewind();
329         }
330         (void)this->skip(position - fGlobalOffset);
331         return true;
332     }
333 
move(long offset)334     bool move(long offset)  override{
335         AUTO_VALIDATE
336         offset += fGlobalOffset;
337         if (offset <= 0) {
338             this->rewind();
339         } else {
340             (void)this->seek(SkToSizeT(offset));
341         }
342         return true;
343     }
344 
fork() const345     SkStreamAsset* fork() const override {
346         SkStreamAsset* clone = this->duplicate();
347         clone->seek(this->getPosition());
348         return clone;
349     }
350 
351 
352 private:
353     const SkROBuffer*   fBuffer;
354     SkROBuffer::Iter    fIter;
355     size_t              fLocalOffset;
356     size_t              fGlobalOffset;
357 };
358 
newStreamSnapshot() const359 SkStreamAsset* SkRWBuffer::newStreamSnapshot() const {
360     sk_sp<SkROBuffer> buffer(this->newRBufferSnapshot());
361     return new SkROBufferStreamAsset(buffer.get());
362 }
363