blob: 56cf42cb7749a9a627abd08429d28cd1b1f9e16c [file] [log] [blame]
Jon Medhurstaaf37a32013-06-11 12:10:56 +01001/**
2 * Copyright (C) ARM Limited 2013. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "Buffer.h"
10
11#include "Logging.h"
12#include "Sender.h"
13#include "SessionData.h"
14
15#define mask (size - 1)
16
17Buffer::Buffer (const int32_t core, const int32_t buftype, const int size, sem_t *const readerSem) : core(core), buftype(buftype), size(size), readPos(0), writePos(0), commitPos(0), available(true), done(false), buf(new char[size]),
18#ifdef GATOR_LIVE
19 commitTime(gSessionData->mLiveRate),
20#endif
21 readerSem(readerSem) {
22 if ((size & mask) != 0) {
23 logg->logError(__FILE__, __LINE__, "Buffer size is not a power of 2");
24 handleException();
25 }
26 frame();
27}
28
29Buffer::~Buffer () {
30 delete [] buf;
31}
32
33void Buffer::write (Sender * const sender) {
34 if (!commitReady()) {
35 return;
36 }
37
38 // determine the size of two halves
39 int length1 = commitPos - readPos;
40 char * buffer1 = buf + readPos;
41 int length2 = 0;
42 char * buffer2 = buf;
43 if (length1 < 0) {
44 length1 = size - readPos;
45 length2 = commitPos;
46 }
47
48 logg->logMessage("Sending data length1: %i length2: %i", length1, length2);
49
50 // start, middle or end
51 if (length1 > 0) {
52 sender->writeData(buffer1, length1, RESPONSE_APC_DATA);
53 }
54
55 // possible wrap around
56 if (length2 > 0) {
57 sender->writeData(buffer2, length2, RESPONSE_APC_DATA);
58 }
59
60 readPos = commitPos;
61}
62
63bool Buffer::commitReady () const {
64 return commitPos != readPos;
65}
66
67int Buffer::bytesAvailable () const {
68 int filled = writePos - readPos;
69 if (filled < 0) {
70 filled += size;
71 }
72
73 int remaining = size - filled;
74
75 if (available) {
76 // Give some extra room; also allows space to insert the overflow error packet
77 remaining -= 200;
78 } else {
79 // Hysteresis, prevents multiple overflow messages
80 remaining -= 2000;
81 }
82
83 return remaining;
84}
85
86bool Buffer::checkSpace (const int bytes) {
87 const int remaining = bytesAvailable();
88
89 if (remaining < bytes) {
90 available = false;
91 } else {
92 available = true;
93 }
94
95 return available;
96}
97
98void Buffer::commit (const uint64_t time) {
99 // post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload
100 const int typeLength = gSessionData->mLocalCapture ? 0 : 1;
101 int length = writePos - commitPos;
102 if (length < 0) {
103 length += size;
104 }
105 length = length - typeLength - sizeof(int32_t);
106 for (size_t byte = 0; byte < sizeof(int32_t); byte++) {
107 buf[(commitPos + typeLength + byte) & mask] = (length >> byte * 8) & 0xFF;
108 }
109
110 logg->logMessage("Committing data readPos: %i writePos: %i commitPos: %i", readPos, writePos, commitPos);
111 commitPos = writePos;
112
113#ifdef GATOR_LIVE
114 if (gSessionData->mLiveRate > 0) {
115 while (time > commitTime) {
116 commitTime += gSessionData->mLiveRate;
117 }
118 }
119#endif
120
121 if (!done) {
122 frame();
123 }
124
125 // send a notification that data is ready
126 sem_post(readerSem);
127}
128
129void Buffer::check (const uint64_t time) {
130 int filled = writePos - commitPos;
131 if (filled < 0) {
132 filled += size;
133 }
134 if (filled >= ((size * 3) / 4)
135#ifdef GATOR_LIVE
136 || (gSessionData->mLiveRate > 0 && time >= commitTime)
137#endif
138 ) {
139 commit(time);
140 }
141}
142
143void Buffer::packInt (int32_t x) {
144 int packedBytes = 0;
145 int more = true;
146 while (more) {
147 // low order 7 bits of x
148 char b = x & 0x7f;
149 x >>= 7;
150
151 if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) {
152 more = false;
153 } else {
154 b |= 0x80;
155 }
156
157 buf[(writePos + packedBytes) & mask] = b;
158 packedBytes++;
159 }
160
161 writePos = (writePos + packedBytes) & mask;
162}
163
164void Buffer::packInt64 (int64_t x) {
165 int packedBytes = 0;
166 int more = true;
167 while (more) {
168 // low order 7 bits of x
169 char b = x & 0x7f;
170 x >>= 7;
171
172 if ((x == 0 && (b & 0x40) == 0) || (x == -1 && (b & 0x40) != 0)) {
173 more = false;
174 } else {
175 b |= 0x80;
176 }
177
178 buf[(writePos + packedBytes) & mask] = b;
179 packedBytes++;
180 }
181
182 writePos = (writePos + packedBytes) & mask;
183}
184
185void Buffer::frame () {
186 if (!gSessionData->mLocalCapture) {
187 packInt(RESPONSE_APC_DATA);
188 }
189 // Reserve space for the length
190 writePos += sizeof(int32_t);
191 packInt(buftype);
192 packInt(core);
193}
194
195bool Buffer::eventHeader (const uint64_t curr_time) {
196 bool retval = false;
197 if (checkSpace(MAXSIZE_PACK32 + MAXSIZE_PACK64)) {
198 packInt(0); // key of zero indicates a timestamp
199 packInt64(curr_time);
200 retval = true;
201 }
202
203 return retval;
204}
205
206void Buffer::event (const int32_t key, const int32_t value) {
207 if (checkSpace(2 * MAXSIZE_PACK32)) {
208 packInt(key);
209 packInt(value);
210 }
211}
212
213void Buffer::event64 (const int64_t key, const int64_t value) {
214 if (checkSpace(2 * MAXSIZE_PACK64)) {
215 packInt64(key);
216 packInt64(value);
217 }
218}
219
220void Buffer::setDone () {
221 done = true;
222 commit(0);
223}
224
225bool Buffer::isDone () const {
226 return done && readPos == commitPos && commitPos == writePos;
227}