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