1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kernel/eka/drivers/trace/btracec.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,395 @@
1.4 +// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32\drivers\trace\btracec.cpp
1.18 +//
1.19 +//
1.20 +
1.21 +#include <e32std.h>
1.22 +#include <e32std_private.h>
1.23 +#include "d32btrace.h"
1.24 +#include <e32svr.h>
1.25 +#include <e32atomics.h>
1.26 +
1.27 +
1.28 +void Panic(TInt aPanicNum)
1.29 + {
1.30 + _LIT(KRBTracePanic,"RBTrace");
1.31 + User::Panic(KRBTracePanic,aPanicNum);
1.32 + }
1.33 +
1.34 +EXPORT_C TInt RBTrace::Open()
1.35 + {
1.36 + _LIT(KBTraceLddName,"btracex");
1.37 + TInt r = User::LoadLogicalDevice(KBTraceLddName);
1.38 + if(r!=KErrNone && r!=KErrAlreadyExists)
1.39 + return r;
1.40 + r = DoCreate( Name(), TVersion(), KNullUnit, NULL, NULL, EOwnerThread);
1.41 + if(r==KErrNone)
1.42 + {
1.43 + r = OpenChunk();
1.44 + if(r!=KErrNone)
1.45 + Close();
1.46 + }
1.47 + return r;
1.48 + };
1.49 +
1.50 +
1.51 +TInt RBTrace::OpenChunk()
1.52 + {
1.53 + TInt r = iDataChunk.SetReturnedHandle(DoControl(EOpenBuffer));
1.54 + if(r==KErrNone)
1.55 + iBuffer = (TBTraceBuffer*)iDataChunk.Base();
1.56 + iLastGetDataSize = 0;
1.57 + return r;
1.58 + }
1.59 +
1.60 +
1.61 +void RBTrace::CloseChunk()
1.62 + {
1.63 + iLastGetDataSize = 0;
1.64 + iBuffer = NULL;
1.65 + iDataChunk.Close();
1.66 + }
1.67 +
1.68 +
1.69 +EXPORT_C void RBTrace::Close()
1.70 + {
1.71 + CloseChunk();
1.72 + RBusLogicalChannel::Close();
1.73 + }
1.74 +
1.75 +
1.76 +EXPORT_C TInt RBTrace::BufferSize()
1.77 + {
1.78 + if(!iDataChunk.Handle())
1.79 + return 0;
1.80 + return iBuffer->iEnd;
1.81 + }
1.82 +
1.83 +
1.84 +EXPORT_C TInt RBTrace::ResizeBuffer(TInt aSize)
1.85 + {
1.86 + CloseChunk();
1.87 + TInt r = DoControl(EResizeBuffer,(TAny*)aSize);
1.88 + if(r==KErrNone)
1.89 + r = OpenChunk();
1.90 + return r;
1.91 + }
1.92 +
1.93 +
1.94 +EXPORT_C void RBTrace::Empty()
1.95 + {
1.96 + TBTraceBuffer* buffer = iBuffer;
1.97 + TUint32 mode = __e32_atomic_swp_acq32(&buffer->iMode, 0); /* read original mode and disable trace */
1.98 + while(__e32_atomic_load_acq32(&buffer->iGeneration) & 1) /* wait for trace handler to complete */
1.99 + { /* should really __chill() but not available user side */ }
1.100 + buffer->iTail = buffer->iHead;
1.101 + __e32_atomic_store_ord32(&buffer->iMode, mode);
1.102 + }
1.103 +
1.104 +
1.105 +EXPORT_C TUint RBTrace::Mode()
1.106 + {
1.107 + return iBuffer->iMode;
1.108 + }
1.109 +
1.110 +
1.111 +EXPORT_C void RBTrace::SetMode(TUint aMode)
1.112 + {
1.113 + iLastGetDataSize = 0;
1.114 + __e32_atomic_store_ord32(&iBuffer->iMode, aMode);
1.115 + }
1.116 +
1.117 +
1.118 +EXPORT_C TInt RBTrace::SetFilter(TUint aCategory, TInt aValue)
1.119 + {
1.120 + return (TInt)DoControl(ESetFilter,(TAny*)aCategory,(TAny*)aValue);
1.121 + }
1.122 +
1.123 +
1.124 +EXPORT_C TInt RBTrace::SetFilter2(TUint32 aUid, TBool aValue)
1.125 + {
1.126 + return (TInt)DoControl(ESetFilter2,(TAny*)aUid,(TAny*)aValue);
1.127 + }
1.128 +
1.129 +
1.130 +EXPORT_C TInt RBTrace::SetFilter2(const TUint32* aUids, TInt aNumUids)
1.131 + {
1.132 + return (TInt)DoControl(ESetFilter2Array,(TAny*)aUids,(TAny*)aNumUids);
1.133 + }
1.134 +
1.135 +
1.136 +EXPORT_C TInt RBTrace::SetFilter2(TInt aGlobalFilter)
1.137 + {
1.138 + return DoControl(ESetFilter2Global,(TAny*)aGlobalFilter);
1.139 + }
1.140 +
1.141 +
1.142 +EXPORT_C TInt RBTrace::Filter2(TUint32*& aUids, TInt& aGlobalFilter)
1.143 + {
1.144 + TInt count = (TInt)DoControl(EGetFilter2Part1,&aUids,&aGlobalFilter);
1.145 + if(count<=0)
1.146 + {
1.147 + aUids = 0;
1.148 + return count;
1.149 + }
1.150 + aUids = (TUint32*)User::Alloc(count*sizeof(TUint32));
1.151 + if(!aUids)
1.152 + return KErrNoMemory;
1.153 + DoControl(EGetFilter2Part2,aUids,(TAny*)count);
1.154 + return count;
1.155 + }
1.156 +
1.157 +
1.158 +EXPORT_C TInt RBTrace::GetData(TUint8*& aData)
1.159 + {
1.160 + TInt size = iBuffer->GetData(aData);
1.161 + iLastGetDataSize = size;
1.162 + return size;
1.163 + }
1.164 +
1.165 +EXPORT_C void RBTrace::DataUsed()
1.166 + {
1.167 + TBTraceBuffer* buffer = iBuffer;
1.168 + if(!(buffer->iMode&RBTrace::EFreeRunning))
1.169 + {
1.170 + /* Make sure change to iTail is not observed before the trace data reads
1.171 + which preceded the call to this function. */
1.172 + __e32_memory_barrier();
1.173 + buffer->iTail += iLastGetDataSize;
1.174 + }
1.175 + iLastGetDataSize = 0;
1.176 + }
1.177 +
1.178 +
1.179 +EXPORT_C void RBTrace::RequestData(TRequestStatus& aStatus, TInt aSize)
1.180 + {
1.181 + if(aSize<0)
1.182 + aSize = 0;
1.183 + aStatus = KRequestPending;
1.184 + if(aSize || iBuffer->iHead==iBuffer->iTail)
1.185 + DoControl(ERequestData,&aStatus,(TAny*)aSize);
1.186 + else
1.187 + {
1.188 + TRequestStatus* s = &aStatus;
1.189 + User::RequestComplete(s,KErrNone);
1.190 + }
1.191 + }
1.192 +
1.193 +
1.194 +EXPORT_C void RBTrace::CancelRequestData()
1.195 + {
1.196 + DoControl(ECancelRequestData);
1.197 + }
1.198 +
1.199 +EXPORT_C TBool RBTrace::SetTimestamp2Enabled(TBool aEnable)
1.200 + {
1.201 + return (TBool)DoControl(ESetTimestamp2Enabled, (TAny*)aEnable);
1.202 + }
1.203 +
1.204 +/**
1.205 +Find out how much data is available.
1.206 +@param aData Set to the buffer offset where the available trace data is located.
1.207 +@param aTail Set to the the original value of the iTail pointer
1.208 +@return Number of bytes of trace data, or an error.
1.209 +*/
1.210 +TInt TBTraceBuffer::Data(TUint& aData, TUint& aTail)
1.211 + {
1.212 + TUint head, tail, wrap;
1.213 + TUint32 g0;
1.214 + TInt retries=64;
1.215 + do {
1.216 + if (--retries<0)
1.217 + return KErrInUse;
1.218 + // sleep every 8 tries to give the write a chance
1.219 + if (retries&7==0)
1.220 + User::AfterHighRes(1);
1.221 + g0 = iGeneration;
1.222 + __e32_memory_barrier();
1.223 + head = iHead;
1.224 + wrap = iWrap;
1.225 + tail = __e32_atomic_and_rlx32(&iTail, ~TUint32(1));
1.226 + __e32_memory_barrier();
1.227 + } while(iGeneration!=g0 || (g0&1)); // repeat until we get a consistent set
1.228 + tail &= ~1;
1.229 + aTail = tail;
1.230 + TUint end = head;
1.231 + if (head<tail)
1.232 + {
1.233 + end = wrap;
1.234 + if (tail>=end)
1.235 + {
1.236 + tail = iStart;
1.237 + end = head;
1.238 + }
1.239 + }
1.240 + aData = tail;
1.241 + return end - tail;
1.242 + }
1.243 +
1.244 +
1.245 +/**
1.246 +Adjust trace data size so it represents a whole number of trace records.
1.247 +@param aData The buffer offset where the available trace data is located.
1.248 +@param aSize The size of data at aTail. Must be >= KMaxBTraceRecordSize.
1.249 +@return An adjusted value for aSize.
1.250 +*/
1.251 +TInt TBTraceBuffer::Adjust(TUint aData, TInt aSize)
1.252 + {
1.253 + TInt adjustedSize = (aSize&~3) - KMaxBTraceRecordSize;
1.254 + if (adjustedSize<0)
1.255 + Panic(0);
1.256 + volatile TUint8* recordOffsets = (volatile TUint8*)this + iRecordOffsets;
1.257 + adjustedSize += recordOffsets[(aData+adjustedSize)>>2]<<2;
1.258 + if (adjustedSize>aSize)
1.259 + Panic(1);
1.260 + return adjustedSize;
1.261 + }
1.262 +
1.263 +
1.264 +/**
1.265 +Update the stored tail offset.
1.266 +@param aOld The value which iTail is expected to have if no more overwrites have occurred
1.267 +@param aNew The new value for iTail
1.268 +@return aNew on success, 0 if the previous tail value had changed before we could update it.
1.269 +*/
1.270 +TUint TBTraceBuffer::UpdateTail(TUint32 aOld, TUint32 aNew)
1.271 + {
1.272 + if (__e32_atomic_cas_rel32(&iTail, &aOld, aNew))
1.273 + return aNew; // if iTail==aOld, set iTail=aNew and return aNew
1.274 + return 0; // else return 0
1.275 + }
1.276 +
1.277 +
1.278 +/**
1.279 +Copy data out of the main trace buffer into the 'copy buffer'.
1.280 +This may fail if the data is overwritten before it hase been successfully copied.
1.281 +@param aData The buffer offset where the available trace data is located.
1.282 +@param aTail The value which iTail is expected to have if no more overwrites have occurred
1.283 +@param aSize The size of data at aTail
1.284 +@return The number of bytes successfully copied.
1.285 +@post iBuffer.iTail has been updated to point to the trace record following those copied.
1.286 +*/
1.287 +TInt TBTraceBuffer::CopyData(TUint aData, TUint aTail, TInt aSize)
1.288 + {
1.289 + // clip size to copy buffer
1.290 + TInt maxSize = iCopyBufferSize;
1.291 + if (aSize>maxSize)
1.292 + aSize = Adjust(aData,maxSize);
1.293 +
1.294 + if (iTail & 1)
1.295 + return 0; // give up if data we're about to copy has been overwritten
1.296 +
1.297 + memcpy((TUint8*)this+iCopyBuffer, (TUint8*)this+aData, aSize);
1.298 +
1.299 + if (!UpdateTail(aTail, aData+aSize))
1.300 + return 0;
1.301 +
1.302 + return aSize;
1.303 + }
1.304 +
1.305 +
1.306 +/**
1.307 +Get pointer to as much contiguous trace data as is available.
1.308 +@param aData Pointer to the first byte of trace data.
1.309 +@return The number of bytes of trace data available at aData.
1.310 +*/
1.311 +TInt TBTraceBuffer::GetData(TUint8*& aData)
1.312 + {
1.313 + TInt retries = 4;
1.314 +
1.315 + // get availabe data...
1.316 + TUint data, tail;
1.317 + TInt size = Data(data, tail);
1.318 + if (!size)
1.319 + return size; // no data available
1.320 +
1.321 + if (!(iMode & RBTrace::EFreeRunning))
1.322 + {
1.323 + // if we got an error from Data but aren't in free-running mode, something has
1.324 + // been interrupting the writing thread for some time while it has interrupts
1.325 + // turned off. give up.
1.326 + if (size<0)
1.327 + return 0;
1.328 + // were not in free-running mode, so we can leave the data where it is...
1.329 + aData = (TUint8*)this + data;
1.330 + iTail = data; // OK since iTail never updated by kernel in this mode
1.331 + return size;
1.332 + }
1.333 +
1.334 + // if we couldn't get a consistent snapshot of the pointers, we need to disable
1.335 + // free running, otherwise we will stall for a very long time.
1.336 + if (size==KErrInUse)
1.337 + goto giveup;
1.338 +
1.339 + // copy data to the copy buffer...
1.340 + aData = (TUint8*)this + iCopyBuffer;
1.341 + size = CopyData(data, tail, size);
1.342 + if (size)
1.343 + return size; // success
1.344 +
1.345 + // data copy failed because new data was added during copy; this happens when the buffer
1.346 + // is full, so now we'll attempt to discard data to give us some breathing space...
1.347 + while(retries)
1.348 + {
1.349 + // see what data is available...
1.350 + size = Data(data, tail);
1.351 + if (!size)
1.352 + return size; // no data in buffer (shouldn't happen because buffer was full to start with)
1.353 + if (size==KErrInUse)
1.354 + goto giveup;
1.355 +
1.356 + // discard a proportion of the data...
1.357 + TInt discard = iCopyBufferSize>>retries;
1.358 + if (discard>=size)
1.359 + discard = size;
1.360 + else
1.361 + discard = Adjust(data, discard); // make sure we only discard a whole number of trace records
1.362 + size -= discard;
1.363 + data = UpdateTail(tail, data+discard);
1.364 + if (!data)
1.365 + continue; // tail was updated before we could discard, so try again
1.366 + if (!size)
1.367 + continue; // we discarded everything - make sure and then exit
1.368 +
1.369 + // try and copy remaining data...
1.370 + size = CopyData(data, data, size);
1.371 + if (size)
1.372 + break; // success!
1.373 +
1.374 + // loop around for another go, discard more this time
1.375 + --retries;
1.376 + }
1.377 +
1.378 + if (!size)
1.379 + {
1.380 +giveup:
1.381 + // we haven't managed to copy data, so give up and do it with free-running mode off...
1.382 + TUint32 mode = __e32_atomic_and_acq32(&iMode, ~(TUint32)RBTrace::EFreeRunning); /* read original mode and disable free running */
1.383 + size = Data(data, tail);
1.384 + // as above: if we get an error here then something has been interrupting the writer
1.385 + // for an unreasonable time, give up.
1.386 + if (size<0)
1.387 + return 0;
1.388 + size = CopyData(data, tail, size);
1.389 + __e32_atomic_store_ord32(&iMode, mode); /* restore original mode */
1.390 + }
1.391 +
1.392 + // we discarded some data, so mark first trace record to indicate that some records are missing...
1.393 + aData[BTrace::EFlagsIndex] |= BTrace::EMissingRecord;
1.394 +
1.395 + return size;
1.396 + }
1.397 +
1.398 +