os/kernelhwsrv/kernel/eka/drivers/trace/btracec.cpp
changeset 0 bde4ae8d615e
     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 +