os/kernelhwsrv/kernel/eka/drivers/trace/btracec.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
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".
     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
   216 		if (retries&7==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