First public contribution.
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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // e32\drivers\trace\btracec.cpp
19 #include <e32std_private.h>
20 #include "d32btrace.h"
22 #include <e32atomics.h>
25 void Panic(TInt aPanicNum)
27 _LIT(KRBTracePanic,"RBTrace");
28 User::Panic(KRBTracePanic,aPanicNum);
31 EXPORT_C TInt RBTrace::Open()
33 _LIT(KBTraceLddName,"btracex");
34 TInt r = User::LoadLogicalDevice(KBTraceLddName);
35 if(r!=KErrNone && r!=KErrAlreadyExists)
37 r = DoCreate( Name(), TVersion(), KNullUnit, NULL, NULL, EOwnerThread);
48 TInt RBTrace::OpenChunk()
50 TInt r = iDataChunk.SetReturnedHandle(DoControl(EOpenBuffer));
52 iBuffer = (TBTraceBuffer*)iDataChunk.Base();
58 void RBTrace::CloseChunk()
66 EXPORT_C void RBTrace::Close()
69 RBusLogicalChannel::Close();
73 EXPORT_C TInt RBTrace::BufferSize()
75 if(!iDataChunk.Handle())
81 EXPORT_C TInt RBTrace::ResizeBuffer(TInt aSize)
84 TInt r = DoControl(EResizeBuffer,(TAny*)aSize);
91 EXPORT_C void RBTrace::Empty()
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);
102 EXPORT_C TUint RBTrace::Mode()
104 return iBuffer->iMode;
108 EXPORT_C void RBTrace::SetMode(TUint aMode)
110 iLastGetDataSize = 0;
111 __e32_atomic_store_ord32(&iBuffer->iMode, aMode);
115 EXPORT_C TInt RBTrace::SetFilter(TUint aCategory, TInt aValue)
117 return (TInt)DoControl(ESetFilter,(TAny*)aCategory,(TAny*)aValue);
121 EXPORT_C TInt RBTrace::SetFilter2(TUint32 aUid, TBool aValue)
123 return (TInt)DoControl(ESetFilter2,(TAny*)aUid,(TAny*)aValue);
127 EXPORT_C TInt RBTrace::SetFilter2(const TUint32* aUids, TInt aNumUids)
129 return (TInt)DoControl(ESetFilter2Array,(TAny*)aUids,(TAny*)aNumUids);
133 EXPORT_C TInt RBTrace::SetFilter2(TInt aGlobalFilter)
135 return DoControl(ESetFilter2Global,(TAny*)aGlobalFilter);
139 EXPORT_C TInt RBTrace::Filter2(TUint32*& aUids, TInt& aGlobalFilter)
141 TInt count = (TInt)DoControl(EGetFilter2Part1,&aUids,&aGlobalFilter);
147 aUids = (TUint32*)User::Alloc(count*sizeof(TUint32));
150 DoControl(EGetFilter2Part2,aUids,(TAny*)count);
155 EXPORT_C TInt RBTrace::GetData(TUint8*& aData)
157 TInt size = iBuffer->GetData(aData);
158 iLastGetDataSize = size;
162 EXPORT_C void RBTrace::DataUsed()
164 TBTraceBuffer* buffer = iBuffer;
165 if(!(buffer->iMode&RBTrace::EFreeRunning))
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;
172 iLastGetDataSize = 0;
176 EXPORT_C void RBTrace::RequestData(TRequestStatus& aStatus, TInt aSize)
180 aStatus = KRequestPending;
181 if(aSize || iBuffer->iHead==iBuffer->iTail)
182 DoControl(ERequestData,&aStatus,(TAny*)aSize);
185 TRequestStatus* s = &aStatus;
186 User::RequestComplete(s,KErrNone);
191 EXPORT_C void RBTrace::CancelRequestData()
193 DoControl(ECancelRequestData);
196 EXPORT_C TBool RBTrace::SetTimestamp2Enabled(TBool aEnable)
198 return (TBool)DoControl(ESetTimestamp2Enabled, (TAny*)aEnable);
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.
207 TInt TBTraceBuffer::Data(TUint& aData, TUint& aTail)
209 TUint head, tail, wrap;
215 // sleep every 8 tries to give the write a chance
217 User::AfterHighRes(1);
219 __e32_memory_barrier();
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
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.
248 TInt TBTraceBuffer::Adjust(TUint aData, TInt aSize)
250 TInt adjustedSize = (aSize&~3) - KMaxBTraceRecordSize;
253 volatile TUint8* recordOffsets = (volatile TUint8*)this + iRecordOffsets;
254 adjustedSize += recordOffsets[(aData+adjustedSize)>>2]<<2;
255 if (adjustedSize>aSize)
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.
267 TUint TBTraceBuffer::UpdateTail(TUint32 aOld, TUint32 aNew)
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
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.
284 TInt TBTraceBuffer::CopyData(TUint aData, TUint aTail, TInt aSize)
286 // clip size to copy buffer
287 TInt maxSize = iCopyBufferSize;
289 aSize = Adjust(aData,maxSize);
292 return 0; // give up if data we're about to copy has been overwritten
294 memcpy((TUint8*)this+iCopyBuffer, (TUint8*)this+aData, aSize);
296 if (!UpdateTail(aTail, aData+aSize))
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.
308 TInt TBTraceBuffer::GetData(TUint8*& aData)
312 // get availabe data...
314 TInt size = Data(data, tail);
316 return size; // no data available
318 if (!(iMode & RBTrace::EFreeRunning))
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.
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
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.
336 // copy data to the copy buffer...
337 aData = (TUint8*)this + iCopyBuffer;
338 size = CopyData(data, tail, size);
340 return size; // success
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...
346 // see what data is available...
347 size = Data(data, tail);
349 return size; // no data in buffer (shouldn't happen because buffer was full to start with)
353 // discard a proportion of the data...
354 TInt discard = iCopyBufferSize>>retries;
358 discard = Adjust(data, discard); // make sure we only discard a whole number of trace records
360 data = UpdateTail(tail, data+discard);
362 continue; // tail was updated before we could discard, so try again
364 continue; // we discarded everything - make sure and then exit
366 // try and copy remaining data...
367 size = CopyData(data, data, size);
371 // loop around for another go, discard more this time
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.
385 size = CopyData(data, tail, size);
386 __e32_atomic_store_ord32(&iMode, mode); /* restore original mode */
389 // we discarded some data, so mark first trace record to indicate that some records are missing...
390 aData[BTrace::EFlagsIndex] |= BTrace::EMissingRecord;