1 /*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "ReadBuffer.h"
17
18 #include "ErrorLog.h"
19
20 #include <algorithm>
21
22 #include <assert.h>
23 #include <string.h>
24 #include <limits.h>
25
26 namespace emugl {
27
ReadBuffer(size_t bufsize)28 ReadBuffer::ReadBuffer(size_t bufsize) {
29 m_size = bufsize;
30 m_buf = (unsigned char*)malloc(m_size);
31 m_validData = 0;
32 m_readPtr = m_buf;
33 }
34
~ReadBuffer()35 ReadBuffer::~ReadBuffer() {
36 free(m_buf);
37 }
38
setNeededFreeTailSize(int size)39 void ReadBuffer::setNeededFreeTailSize(int size) {
40 m_neededFreeTailSize = size;
41 }
42
getData(IOStream * stream,int minSize)43 int ReadBuffer::getData(IOStream* stream, int minSize) {
44 assert(stream);
45 assert(minSize > (int)m_validData);
46
47 const int minSizeToRead = minSize - m_validData;
48 const int neededFreeTailThisTime =
49 std::max(minSizeToRead,
50 m_neededFreeTailSize);
51
52 int maxSizeToRead;
53 const int freeTailSize = m_buf + m_size - (m_readPtr + m_validData);
54 if (freeTailSize >= neededFreeTailThisTime) {
55 maxSizeToRead = freeTailSize;
56 } else {
57 if (freeTailSize + (m_readPtr - m_buf) >= neededFreeTailThisTime) {
58 // There's some gap in the beginning, if we move the data over it
59 // that's going to be enough.
60 memmove(m_buf, m_readPtr, m_validData);
61 } else {
62 // Not enough space even with moving, reallocate.
63 // Note: make sure we can fit at least two of the requested packets
64 // into the new buffer to minimize the reallocations and
65 // memmove()-ing stuff around.
66 size_t new_size = std::max<size_t>(
67 2 * minSizeToRead + m_validData,
68 2 * m_size);
69 if (new_size < m_size) { // overflow check
70 new_size = INT_MAX;
71 }
72
73 const auto new_buf = (unsigned char*)malloc(new_size);
74 if (!new_buf) {
75 ERR("Failed to alloc %zu bytes for ReadBuffer\n", new_size);
76 return -1;
77 }
78
79 memcpy(new_buf, m_readPtr, m_validData);
80 free(m_buf);
81 m_buf = new_buf;
82 m_size = new_size;
83 }
84 // We can read more now, let's request it in case all data is ready
85 // for reading.
86 maxSizeToRead = m_size - m_validData;
87 m_readPtr = m_buf;
88 }
89
90 // get fresh data into the buffer;
91 int readTotal = 0;
92 do {
93 const size_t readNow = stream->read(m_readPtr + m_validData,
94 maxSizeToRead - readTotal);
95
96 if (!readNow) {
97 if (readTotal > 0) {
98 return readTotal;
99 } else {
100 return -1;
101 }
102 }
103 readTotal += readNow;
104 m_validData += readNow;
105 } while (readTotal < minSizeToRead);
106
107 return readTotal;
108 }
109
consume(size_t amount)110 void ReadBuffer::consume(size_t amount) {
111 assert(amount <= m_validData);
112 m_validData -= amount;
113 m_readPtr += amount;
114 }
115
onSave(android::base::Stream * stream)116 void ReadBuffer::onSave(android::base::Stream* stream) {
117 stream->putBe32(m_size);
118 stream->putBe32(m_validData);
119 stream->write(m_readPtr, m_validData);
120 }
121
onLoad(android::base::Stream * stream)122 void ReadBuffer::onLoad(android::base::Stream* stream) {
123 const auto size = stream->getBe32();
124 if (size > m_size) {
125 m_size = size;
126 free(m_buf);
127 m_buf = (unsigned char*)malloc(m_size);
128 }
129 m_readPtr = m_buf;
130 m_validData = stream->getBe32();
131 assert(m_validData <= m_size);
132 stream->read(m_readPtr, m_validData);
133 }
134
printStats()135 void ReadBuffer::printStats() {
136 printf("ReadBuffer::%s: tail move time %f ms\n", __func__,
137 (float)m_tailMoveTimeUs / 1000.0f);
138 m_tailMoveTimeUs = 0;
139 }
140 } // namespace emugl
141