author | mikek |
Mon, 05 Jul 2010 08:12:03 +0100 | |
branch | GCC_SURGE |
changeset 193 | 082ffed484fb |
parent 167 | b41fc9c39ca7 |
permissions | -rw-r--r-- |
0 | 1 |
// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). |
2 |
// All rights reserved. |
|
3 |
// This component and the accompanying materials are made available |
|
4 |
// under the terms of the License "Eclipse Public License v1.0" |
|
5 |
// which accompanies this distribution, and is available |
|
6 |
// at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 |
// |
|
8 |
// Initial Contributors: |
|
9 |
// Nokia Corporation - initial contribution. |
|
10 |
// |
|
11 |
// Contributors: |
|
12 |
// |
|
13 |
// Description: |
|
14 |
// e32\drivers\trace\btracec.cpp |
|
15 |
// |
|
16 |
// |
|
17 |
||
18 |
#include <e32std.h> |
|
19 |
#include <e32std_private.h> |
|
20 |
#include "d32btrace.h" |
|
21 |
#include <e32svr.h> |
|
22 |
#include <e32atomics.h> |
|
23 |
||
24 |
||
25 |
void Panic(TInt aPanicNum) |
|
26 |
{ |
|
27 |
_LIT(KRBTracePanic,"RBTrace"); |
|
28 |
User::Panic(KRBTracePanic,aPanicNum); |
|
29 |
} |
|
30 |
||
31 |
EXPORT_C TInt RBTrace::Open() |
|
32 |
{ |
|
33 |
_LIT(KBTraceLddName,"btracex"); |
|
34 |
TInt r = User::LoadLogicalDevice(KBTraceLddName); |
|
35 |
if(r!=KErrNone && r!=KErrAlreadyExists) |
|
36 |
return r; |
|
37 |
r = DoCreate( Name(), TVersion(), KNullUnit, NULL, NULL, EOwnerThread); |
|
38 |
if(r==KErrNone) |
|
39 |
{ |
|
40 |
r = OpenChunk(); |
|
41 |
if(r!=KErrNone) |
|
42 |
Close(); |
|
43 |
} |
|
44 |
return r; |
|
45 |
}; |
|
46 |
||
47 |
||
48 |
TInt RBTrace::OpenChunk() |
|
49 |
{ |
|
50 |
TInt r = iDataChunk.SetReturnedHandle(DoControl(EOpenBuffer)); |
|
51 |
if(r==KErrNone) |
|
52 |
iBuffer = (TBTraceBuffer*)iDataChunk.Base(); |
|
53 |
iLastGetDataSize = 0; |
|
54 |
return r; |
|
55 |
} |
|
56 |
||
57 |
||
58 |
void RBTrace::CloseChunk() |
|
59 |
{ |
|
60 |
iLastGetDataSize = 0; |
|
61 |
iBuffer = NULL; |
|
62 |
iDataChunk.Close(); |
|
63 |
} |
|
64 |
||
65 |
||
66 |
EXPORT_C void RBTrace::Close() |
|
67 |
{ |
|
68 |
CloseChunk(); |
|
69 |
RBusLogicalChannel::Close(); |
|
70 |
} |
|
71 |
||
72 |
||
73 |
EXPORT_C TInt RBTrace::BufferSize() |
|
74 |
{ |
|
75 |
if(!iDataChunk.Handle()) |
|
76 |
return 0; |
|
77 |
return iBuffer->iEnd; |
|
78 |
} |
|
79 |
||
80 |
||
81 |
EXPORT_C TInt RBTrace::ResizeBuffer(TInt aSize) |
|
82 |
{ |
|
83 |
CloseChunk(); |
|
84 |
TInt r = DoControl(EResizeBuffer,(TAny*)aSize); |
|
85 |
if(r==KErrNone) |
|
86 |
r = OpenChunk(); |
|
87 |
return r; |
|
88 |
} |
|
89 |
||
90 |
||
91 |
EXPORT_C void RBTrace::Empty() |
|
92 |
{ |
|
93 |
TBTraceBuffer* buffer = iBuffer; |
|
94 |
TUint32 mode = __e32_atomic_swp_acq32(&buffer->iMode, 0); /* read original mode and disable trace */ |
|
95 |
while(__e32_atomic_load_acq32(&buffer->iGeneration) & 1) /* wait for trace handler to complete */ |
|
96 |
{ /* should really __chill() but not available user side */ } |
|
97 |
buffer->iTail = buffer->iHead; |
|
98 |
__e32_atomic_store_ord32(&buffer->iMode, mode); |
|
99 |
} |
|
100 |
||
101 |
||
102 |
EXPORT_C TUint RBTrace::Mode() |
|
103 |
{ |
|
104 |
return iBuffer->iMode; |
|
105 |
} |
|
106 |
||
107 |
||
108 |
EXPORT_C void RBTrace::SetMode(TUint aMode) |
|
109 |
{ |
|
110 |
iLastGetDataSize = 0; |
|
111 |
__e32_atomic_store_ord32(&iBuffer->iMode, aMode); |
|
112 |
} |
|
113 |
||
114 |
||
115 |
EXPORT_C TInt RBTrace::SetFilter(TUint aCategory, TInt aValue) |
|
116 |
{ |
|
117 |
return (TInt)DoControl(ESetFilter,(TAny*)aCategory,(TAny*)aValue); |
|
118 |
} |
|
119 |
||
120 |
||
121 |
EXPORT_C TInt RBTrace::SetFilter2(TUint32 aUid, TBool aValue) |
|
122 |
{ |
|
123 |
return (TInt)DoControl(ESetFilter2,(TAny*)aUid,(TAny*)aValue); |
|
124 |
} |
|
125 |
||
126 |
||
127 |
EXPORT_C TInt RBTrace::SetFilter2(const TUint32* aUids, TInt aNumUids) |
|
128 |
{ |
|
129 |
return (TInt)DoControl(ESetFilter2Array,(TAny*)aUids,(TAny*)aNumUids); |
|
130 |
} |
|
131 |
||
132 |
||
133 |
EXPORT_C TInt RBTrace::SetFilter2(TInt aGlobalFilter) |
|
134 |
{ |
|
135 |
return DoControl(ESetFilter2Global,(TAny*)aGlobalFilter); |
|
136 |
} |
|
137 |
||
138 |
||
139 |
EXPORT_C TInt RBTrace::Filter2(TUint32*& aUids, TInt& aGlobalFilter) |
|
140 |
{ |
|
141 |
TInt count = (TInt)DoControl(EGetFilter2Part1,&aUids,&aGlobalFilter); |
|
142 |
if(count<=0) |
|
143 |
{ |
|
144 |
aUids = 0; |
|
145 |
return count; |
|
146 |
} |
|
147 |
aUids = (TUint32*)User::Alloc(count*sizeof(TUint32)); |
|
148 |
if(!aUids) |
|
149 |
return KErrNoMemory; |
|
150 |
DoControl(EGetFilter2Part2,aUids,(TAny*)count); |
|
151 |
return count; |
|
152 |
} |
|
153 |
||
154 |
||
155 |
EXPORT_C TInt RBTrace::GetData(TUint8*& aData) |
|
156 |
{ |
|
157 |
TInt size = iBuffer->GetData(aData); |
|
158 |
iLastGetDataSize = size; |
|
159 |
return size; |
|
160 |
} |
|
161 |
||
162 |
EXPORT_C void RBTrace::DataUsed() |
|
163 |
{ |
|
164 |
TBTraceBuffer* buffer = iBuffer; |
|
165 |
if(!(buffer->iMode&RBTrace::EFreeRunning)) |
|
166 |
{ |
|
167 |
/* Make sure change to iTail is not observed before the trace data reads |
|
168 |
which preceded the call to this function. */ |
|
169 |
__e32_memory_barrier(); |
|
170 |
buffer->iTail += iLastGetDataSize; |
|
171 |
} |
|
172 |
iLastGetDataSize = 0; |
|
173 |
} |
|
174 |
||
175 |
||
176 |
EXPORT_C void RBTrace::RequestData(TRequestStatus& aStatus, TInt aSize) |
|
177 |
{ |
|
178 |
if(aSize<0) |
|
179 |
aSize = 0; |
|
180 |
aStatus = KRequestPending; |
|
181 |
if(aSize || iBuffer->iHead==iBuffer->iTail) |
|
182 |
DoControl(ERequestData,&aStatus,(TAny*)aSize); |
|
183 |
else |
|
184 |
{ |
|
185 |
TRequestStatus* s = &aStatus; |
|
186 |
User::RequestComplete(s,KErrNone); |
|
187 |
} |
|
188 |
} |
|
189 |
||
190 |
||
191 |
EXPORT_C void RBTrace::CancelRequestData() |
|
192 |
{ |
|
193 |
DoControl(ECancelRequestData); |
|
194 |
} |
|
195 |
||
196 |
EXPORT_C TBool RBTrace::SetTimestamp2Enabled(TBool aEnable) |
|
197 |
{ |
|
198 |
return (TBool)DoControl(ESetTimestamp2Enabled, (TAny*)aEnable); |
|
199 |
} |
|
200 |
||
201 |
/** |
|
202 |
Find out how much data is available. |
|
203 |
@param aData Set to the buffer offset where the available trace data is located. |
|
204 |
@param aTail Set to the the original value of the iTail pointer |
|
205 |
@return Number of bytes of trace data, or an error. |
|
206 |
*/ |
|
207 |
TInt TBTraceBuffer::Data(TUint& aData, TUint& aTail) |
|
208 |
{ |
|
209 |
TUint head, tail, wrap; |
|
210 |
TUint32 g0; |
|
211 |
TInt retries=64; |
|
212 |
do { |
|
213 |
if (--retries<0) |
|
214 |
return KErrInUse; |
|
215 |
// sleep every 8 tries to give the write a chance |
|
167
b41fc9c39ca7
1) Fix for Bug 3027 - [GCCE] Unintended operator precedence in ambiguous expressions
mikek
parents:
0
diff
changeset
|
216 |
if ((retries&7)==0) |
0 | 217 |
User::AfterHighRes(1); |
218 |
g0 = iGeneration; |
|
219 |
__e32_memory_barrier(); |
|
220 |
head = iHead; |
|
221 |
wrap = iWrap; |
|
222 |
tail = __e32_atomic_and_rlx32(&iTail, ~TUint32(1)); |
|
223 |
__e32_memory_barrier(); |
|
224 |
} while(iGeneration!=g0 || (g0&1)); // repeat until we get a consistent set |
|
225 |
tail &= ~1; |
|
226 |
aTail = tail; |
|
227 |
TUint end = head; |
|
228 |
if (head<tail) |
|
229 |
{ |
|
230 |
end = wrap; |
|
231 |
if (tail>=end) |
|
232 |
{ |
|
233 |
tail = iStart; |
|
234 |
end = head; |
|
235 |
} |
|
236 |
} |
|
237 |
aData = tail; |
|
238 |
return end - tail; |
|
239 |
} |
|
240 |
||
241 |
||
242 |
/** |
|
243 |
Adjust trace data size so it represents a whole number of trace records. |
|
244 |
@param aData The buffer offset where the available trace data is located. |
|
245 |
@param aSize The size of data at aTail. Must be >= KMaxBTraceRecordSize. |
|
246 |
@return An adjusted value for aSize. |
|
247 |
*/ |
|
248 |
TInt TBTraceBuffer::Adjust(TUint aData, TInt aSize) |
|
249 |
{ |
|
250 |
TInt adjustedSize = (aSize&~3) - KMaxBTraceRecordSize; |
|
251 |
if (adjustedSize<0) |
|
252 |
Panic(0); |
|
253 |
volatile TUint8* recordOffsets = (volatile TUint8*)this + iRecordOffsets; |
|
254 |
adjustedSize += recordOffsets[(aData+adjustedSize)>>2]<<2; |
|
255 |
if (adjustedSize>aSize) |
|
256 |
Panic(1); |
|
257 |
return adjustedSize; |
|
258 |
} |
|
259 |
||
260 |
||
261 |
/** |
|
262 |
Update the stored tail offset. |
|
263 |
@param aOld The value which iTail is expected to have if no more overwrites have occurred |
|
264 |
@param aNew The new value for iTail |
|
265 |
@return aNew on success, 0 if the previous tail value had changed before we could update it. |
|
266 |
*/ |
|
267 |
TUint TBTraceBuffer::UpdateTail(TUint32 aOld, TUint32 aNew) |
|
268 |
{ |
|
269 |
if (__e32_atomic_cas_rel32(&iTail, &aOld, aNew)) |
|
270 |
return aNew; // if iTail==aOld, set iTail=aNew and return aNew |
|
271 |
return 0; // else return 0 |
|
272 |
} |
|
273 |
||
274 |
||
275 |
/** |
|
276 |
Copy data out of the main trace buffer into the 'copy buffer'. |
|
277 |
This may fail if the data is overwritten before it hase been successfully copied. |
|
278 |
@param aData The buffer offset where the available trace data is located. |
|
279 |
@param aTail The value which iTail is expected to have if no more overwrites have occurred |
|
280 |
@param aSize The size of data at aTail |
|
281 |
@return The number of bytes successfully copied. |
|
282 |
@post iBuffer.iTail has been updated to point to the trace record following those copied. |
|
283 |
*/ |
|
284 |
TInt TBTraceBuffer::CopyData(TUint aData, TUint aTail, TInt aSize) |
|
285 |
{ |
|
286 |
// clip size to copy buffer |
|
287 |
TInt maxSize = iCopyBufferSize; |
|
288 |
if (aSize>maxSize) |
|
289 |
aSize = Adjust(aData,maxSize); |
|
290 |
||
291 |
if (iTail & 1) |
|
292 |
return 0; // give up if data we're about to copy has been overwritten |
|
293 |
||
294 |
memcpy((TUint8*)this+iCopyBuffer, (TUint8*)this+aData, aSize); |
|
295 |
||
296 |
if (!UpdateTail(aTail, aData+aSize)) |
|
297 |
return 0; |
|
298 |
||
299 |
return aSize; |
|
300 |
} |
|
301 |
||
302 |
||
303 |
/** |
|
304 |
Get pointer to as much contiguous trace data as is available. |
|
305 |
@param aData Pointer to the first byte of trace data. |
|
306 |
@return The number of bytes of trace data available at aData. |
|
307 |
*/ |
|
308 |
TInt TBTraceBuffer::GetData(TUint8*& aData) |
|
309 |
{ |
|
310 |
TInt retries = 4; |
|
311 |
||
312 |
// get availabe data... |
|
313 |
TUint data, tail; |
|
314 |
TInt size = Data(data, tail); |
|
315 |
if (!size) |
|
316 |
return size; // no data available |
|
317 |
||
318 |
if (!(iMode & RBTrace::EFreeRunning)) |
|
319 |
{ |
|
320 |
// if we got an error from Data but aren't in free-running mode, something has |
|
321 |
// been interrupting the writing thread for some time while it has interrupts |
|
322 |
// turned off. give up. |
|
323 |
if (size<0) |
|
324 |
return 0; |
|
325 |
// were not in free-running mode, so we can leave the data where it is... |
|
326 |
aData = (TUint8*)this + data; |
|
327 |
iTail = data; // OK since iTail never updated by kernel in this mode |
|
328 |
return size; |
|
329 |
} |
|
330 |
||
331 |
// if we couldn't get a consistent snapshot of the pointers, we need to disable |
|
332 |
// free running, otherwise we will stall for a very long time. |
|
333 |
if (size==KErrInUse) |
|
334 |
goto giveup; |
|
335 |
||
336 |
// copy data to the copy buffer... |
|
337 |
aData = (TUint8*)this + iCopyBuffer; |
|
338 |
size = CopyData(data, tail, size); |
|
339 |
if (size) |
|
340 |
return size; // success |
|
341 |
||
342 |
// data copy failed because new data was added during copy; this happens when the buffer |
|
343 |
// is full, so now we'll attempt to discard data to give us some breathing space... |
|
344 |
while(retries) |
|
345 |
{ |
|
346 |
// see what data is available... |
|
347 |
size = Data(data, tail); |
|
348 |
if (!size) |
|
349 |
return size; // no data in buffer (shouldn't happen because buffer was full to start with) |
|
350 |
if (size==KErrInUse) |
|
351 |
goto giveup; |
|
352 |
||
353 |
// discard a proportion of the data... |
|
354 |
TInt discard = iCopyBufferSize>>retries; |
|
355 |
if (discard>=size) |
|
356 |
discard = size; |
|
357 |
else |
|
358 |
discard = Adjust(data, discard); // make sure we only discard a whole number of trace records |
|
359 |
size -= discard; |
|
360 |
data = UpdateTail(tail, data+discard); |
|
361 |
if (!data) |
|
362 |
continue; // tail was updated before we could discard, so try again |
|
363 |
if (!size) |
|
364 |
continue; // we discarded everything - make sure and then exit |
|
365 |
||
366 |
// try and copy remaining data... |
|
367 |
size = CopyData(data, data, size); |
|
368 |
if (size) |
|
369 |
break; // success! |
|
370 |
||
371 |
// loop around for another go, discard more this time |
|
372 |
--retries; |
|
373 |
} |
|
374 |
||
375 |
if (!size) |
|
376 |
{ |
|
377 |
giveup: |
|
378 |
// we haven't managed to copy data, so give up and do it with free-running mode off... |
|
379 |
TUint32 mode = __e32_atomic_and_acq32(&iMode, ~(TUint32)RBTrace::EFreeRunning); /* read original mode and disable free running */ |
|
380 |
size = Data(data, tail); |
|
381 |
// as above: if we get an error here then something has been interrupting the writer |
|
382 |
// for an unreasonable time, give up. |
|
383 |
if (size<0) |
|
384 |
return 0; |
|
385 |
size = CopyData(data, tail, size); |
|
386 |
__e32_atomic_store_ord32(&iMode, mode); /* restore original mode */ |
|
387 |
} |
|
388 |
||
389 |
// we discarded some data, so mark first trace record to indicate that some records are missing... |
|
390 |
aData[BTrace::EFlagsIndex] |= BTrace::EMissingRecord; |
|
391 |
||
392 |
return size; |
|
393 |
} |
|
394 |
||
395 |