kernel/eka/drivers/trace/btracec.cpp
changeset 43 96e5fb8b040d
child 167 b41fc9c39ca7
equal deleted inserted replaced
-1:000000000000 43:96e5fb8b040d
       
     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