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.
sl@0
     1
// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of the License "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
// e32\drivers\trace\btracec.cpp
sl@0
    15
// 
sl@0
    16
//
sl@0
    17
sl@0
    18
#include <e32std.h>
sl@0
    19
#include <e32std_private.h>
sl@0
    20
#include "d32btrace.h"
sl@0
    21
#include <e32svr.h>
sl@0
    22
#include <e32atomics.h>
sl@0
    23
sl@0
    24
sl@0
    25
void Panic(TInt aPanicNum)
sl@0
    26
	{
sl@0
    27
	_LIT(KRBTracePanic,"RBTrace");
sl@0
    28
	User::Panic(KRBTracePanic,aPanicNum);
sl@0
    29
	}
sl@0
    30
sl@0
    31
EXPORT_C TInt RBTrace::Open()
sl@0
    32
	{
sl@0
    33
	_LIT(KBTraceLddName,"btracex");
sl@0
    34
	TInt r = User::LoadLogicalDevice(KBTraceLddName);
sl@0
    35
	if(r!=KErrNone && r!=KErrAlreadyExists)
sl@0
    36
		return r;
sl@0
    37
	r = DoCreate( Name(), TVersion(), KNullUnit, NULL, NULL, EOwnerThread);
sl@0
    38
	if(r==KErrNone)
sl@0
    39
		{
sl@0
    40
		r = OpenChunk();
sl@0
    41
		if(r!=KErrNone)
sl@0
    42
			Close();
sl@0
    43
		}
sl@0
    44
	return r;
sl@0
    45
	};
sl@0
    46
sl@0
    47
sl@0
    48
TInt RBTrace::OpenChunk()
sl@0
    49
	{
sl@0
    50
	TInt r = iDataChunk.SetReturnedHandle(DoControl(EOpenBuffer));
sl@0
    51
	if(r==KErrNone)
sl@0
    52
		iBuffer = (TBTraceBuffer*)iDataChunk.Base();
sl@0
    53
	iLastGetDataSize = 0;
sl@0
    54
	return r;
sl@0
    55
	}
sl@0
    56
sl@0
    57
sl@0
    58
void RBTrace::CloseChunk()
sl@0
    59
	{
sl@0
    60
	iLastGetDataSize = 0;
sl@0
    61
	iBuffer = NULL;
sl@0
    62
	iDataChunk.Close();
sl@0
    63
	}
sl@0
    64
sl@0
    65
sl@0
    66
EXPORT_C void RBTrace::Close()
sl@0
    67
	{
sl@0
    68
	CloseChunk();
sl@0
    69
	RBusLogicalChannel::Close();
sl@0
    70
	}
sl@0
    71
sl@0
    72
sl@0
    73
EXPORT_C TInt RBTrace::BufferSize()
sl@0
    74
	{
sl@0
    75
	if(!iDataChunk.Handle())
sl@0
    76
		return 0;
sl@0
    77
	return iBuffer->iEnd;
sl@0
    78
	}
sl@0
    79
sl@0
    80
sl@0
    81
EXPORT_C TInt RBTrace::ResizeBuffer(TInt aSize)
sl@0
    82
	{
sl@0
    83
	CloseChunk();
sl@0
    84
	TInt r = DoControl(EResizeBuffer,(TAny*)aSize);
sl@0
    85
	if(r==KErrNone)
sl@0
    86
		r = OpenChunk();
sl@0
    87
	return r;
sl@0
    88
	}
sl@0
    89
sl@0
    90
sl@0
    91
EXPORT_C void RBTrace::Empty()
sl@0
    92
	{
sl@0
    93
	TBTraceBuffer* buffer = iBuffer;
sl@0
    94
	TUint32 mode = __e32_atomic_swp_acq32(&buffer->iMode, 0);	/* read original mode and disable trace */
sl@0
    95
	while(__e32_atomic_load_acq32(&buffer->iGeneration) & 1)	/* wait for trace handler to complete */
sl@0
    96
		{ /* should really __chill() but not available user side */ }
sl@0
    97
	buffer->iTail = buffer->iHead;
sl@0
    98
	__e32_atomic_store_ord32(&buffer->iMode, mode);
sl@0
    99
	}
sl@0
   100
sl@0
   101
sl@0
   102
EXPORT_C TUint RBTrace::Mode()
sl@0
   103
	{
sl@0
   104
	return iBuffer->iMode;
sl@0
   105
	}
sl@0
   106
sl@0
   107
sl@0
   108
EXPORT_C void RBTrace::SetMode(TUint aMode)
sl@0
   109
	{
sl@0
   110
	iLastGetDataSize = 0;
sl@0
   111
	__e32_atomic_store_ord32(&iBuffer->iMode, aMode);
sl@0
   112
	}
sl@0
   113
sl@0
   114
sl@0
   115
EXPORT_C TInt RBTrace::SetFilter(TUint aCategory, TInt aValue)
sl@0
   116
	{
sl@0
   117
	return (TInt)DoControl(ESetFilter,(TAny*)aCategory,(TAny*)aValue);
sl@0
   118
	}
sl@0
   119
sl@0
   120
sl@0
   121
EXPORT_C TInt RBTrace::SetFilter2(TUint32 aUid, TBool aValue)
sl@0
   122
	{
sl@0
   123
	return (TInt)DoControl(ESetFilter2,(TAny*)aUid,(TAny*)aValue);
sl@0
   124
	}
sl@0
   125
sl@0
   126
sl@0
   127
EXPORT_C TInt RBTrace::SetFilter2(const TUint32* aUids, TInt aNumUids)
sl@0
   128
	{
sl@0
   129
	return (TInt)DoControl(ESetFilter2Array,(TAny*)aUids,(TAny*)aNumUids);
sl@0
   130
	}
sl@0
   131
sl@0
   132
sl@0
   133
EXPORT_C TInt RBTrace::SetFilter2(TInt aGlobalFilter)
sl@0
   134
	{
sl@0
   135
	return DoControl(ESetFilter2Global,(TAny*)aGlobalFilter);
sl@0
   136
	}
sl@0
   137
sl@0
   138
sl@0
   139
EXPORT_C TInt RBTrace::Filter2(TUint32*& aUids, TInt& aGlobalFilter)
sl@0
   140
	{
sl@0
   141
	TInt count = (TInt)DoControl(EGetFilter2Part1,&aUids,&aGlobalFilter);
sl@0
   142
	if(count<=0)
sl@0
   143
		{
sl@0
   144
		aUids = 0;
sl@0
   145
		return count;
sl@0
   146
		}
sl@0
   147
	aUids = (TUint32*)User::Alloc(count*sizeof(TUint32));
sl@0
   148
	if(!aUids)
sl@0
   149
		return KErrNoMemory;
sl@0
   150
	DoControl(EGetFilter2Part2,aUids,(TAny*)count);
sl@0
   151
	return count;
sl@0
   152
	}
sl@0
   153
sl@0
   154
sl@0
   155
EXPORT_C TInt RBTrace::GetData(TUint8*& aData)
sl@0
   156
	{
sl@0
   157
	TInt size = iBuffer->GetData(aData);
sl@0
   158
	iLastGetDataSize = size;
sl@0
   159
	return size;
sl@0
   160
	}
sl@0
   161
sl@0
   162
EXPORT_C void RBTrace::DataUsed()
sl@0
   163
	{
sl@0
   164
	TBTraceBuffer* buffer = iBuffer;
sl@0
   165
	if(!(buffer->iMode&RBTrace::EFreeRunning))
sl@0
   166
		{
sl@0
   167
		/* Make sure change to iTail is not observed before the trace data reads
sl@0
   168
			which preceded the call to this function. */
sl@0
   169
		__e32_memory_barrier();
sl@0
   170
		buffer->iTail += iLastGetDataSize;
sl@0
   171
		}
sl@0
   172
	iLastGetDataSize = 0;
sl@0
   173
	}
sl@0
   174
sl@0
   175
sl@0
   176
EXPORT_C void RBTrace::RequestData(TRequestStatus& aStatus, TInt aSize)
sl@0
   177
	{
sl@0
   178
	if(aSize<0)
sl@0
   179
		aSize = 0;
sl@0
   180
	aStatus = KRequestPending;
sl@0
   181
	if(aSize || iBuffer->iHead==iBuffer->iTail)
sl@0
   182
		DoControl(ERequestData,&aStatus,(TAny*)aSize);
sl@0
   183
	else
sl@0
   184
		{
sl@0
   185
		TRequestStatus* s = &aStatus;
sl@0
   186
		User::RequestComplete(s,KErrNone);
sl@0
   187
		}
sl@0
   188
	}
sl@0
   189
sl@0
   190
sl@0
   191
EXPORT_C void RBTrace::CancelRequestData()
sl@0
   192
	{
sl@0
   193
	DoControl(ECancelRequestData);
sl@0
   194
	}
sl@0
   195
sl@0
   196
EXPORT_C TBool RBTrace::SetTimestamp2Enabled(TBool aEnable)
sl@0
   197
	{
sl@0
   198
	return (TBool)DoControl(ESetTimestamp2Enabled, (TAny*)aEnable);
sl@0
   199
	}
sl@0
   200
sl@0
   201
/**
sl@0
   202
Find out how much data is available.
sl@0
   203
@param aData Set to the buffer offset where the available trace data is located.
sl@0
   204
@param aTail Set to the the original value of the iTail pointer
sl@0
   205
@return Number of bytes of trace data, or an error.
sl@0
   206
*/
sl@0
   207
TInt TBTraceBuffer::Data(TUint& aData, TUint& aTail)
sl@0
   208
	{
sl@0
   209
	TUint head, tail, wrap;
sl@0
   210
	TUint32 g0;
sl@0
   211
	TInt retries=64;
sl@0
   212
	do	{
sl@0
   213
		if (--retries<0)
sl@0
   214
			return KErrInUse;
sl@0
   215
		// sleep every 8 tries to give the write a chance
sl@0
   216
		if (retries&7==0)
sl@0
   217
			User::AfterHighRes(1);
sl@0
   218
		g0 = iGeneration;
sl@0
   219
		__e32_memory_barrier();
sl@0
   220
		head = iHead;
sl@0
   221
		wrap = iWrap;
sl@0
   222
		tail = __e32_atomic_and_rlx32(&iTail, ~TUint32(1));
sl@0
   223
		__e32_memory_barrier();
sl@0
   224
		} while(iGeneration!=g0 || (g0&1));	// repeat until we get a consistent set
sl@0
   225
	tail &= ~1;
sl@0
   226
	aTail = tail;
sl@0
   227
	TUint end = head;
sl@0
   228
	if (head<tail)
sl@0
   229
		{
sl@0
   230
		end = wrap;
sl@0
   231
		if (tail>=end)
sl@0
   232
			{
sl@0
   233
			tail = iStart;
sl@0
   234
			end = head;
sl@0
   235
			}
sl@0
   236
		}
sl@0
   237
	aData = tail;
sl@0
   238
	return end - tail;
sl@0
   239
	}
sl@0
   240
sl@0
   241
sl@0
   242
/**
sl@0
   243
Adjust trace data size so it represents a whole number of trace records.
sl@0
   244
@param aData The buffer offset where the available trace data is located.
sl@0
   245
@param aSize The size of data at aTail. Must be >= KMaxBTraceRecordSize.
sl@0
   246
@return An adjusted value for aSize.
sl@0
   247
*/
sl@0
   248
TInt TBTraceBuffer::Adjust(TUint aData, TInt aSize)
sl@0
   249
	{
sl@0
   250
	TInt adjustedSize = (aSize&~3) - KMaxBTraceRecordSize;
sl@0
   251
	if (adjustedSize<0)
sl@0
   252
		Panic(0);
sl@0
   253
	volatile TUint8* recordOffsets = (volatile TUint8*)this + iRecordOffsets;
sl@0
   254
	adjustedSize += recordOffsets[(aData+adjustedSize)>>2]<<2;
sl@0
   255
	if (adjustedSize>aSize)
sl@0
   256
		Panic(1);
sl@0
   257
	return adjustedSize;
sl@0
   258
	}
sl@0
   259
sl@0
   260
sl@0
   261
/**
sl@0
   262
Update the stored tail offset.
sl@0
   263
@param aOld The value which iTail is expected to have if no more overwrites have occurred
sl@0
   264
@param aNew The new value for iTail
sl@0
   265
@return aNew on success, 0 if the previous tail value had changed before we could update it.
sl@0
   266
*/
sl@0
   267
TUint TBTraceBuffer::UpdateTail(TUint32 aOld, TUint32 aNew)
sl@0
   268
	{
sl@0
   269
	if (__e32_atomic_cas_rel32(&iTail, &aOld, aNew))
sl@0
   270
		return aNew;	// if iTail==aOld, set iTail=aNew and return aNew
sl@0
   271
	return 0;	// else return 0
sl@0
   272
	}
sl@0
   273
sl@0
   274
sl@0
   275
/**
sl@0
   276
Copy data out of the main trace buffer into the 'copy buffer'.
sl@0
   277
This may fail if the data is overwritten before it hase been successfully copied.
sl@0
   278
@param aData The buffer offset where the available trace data is located.
sl@0
   279
@param aTail The value which iTail is expected to have if no more overwrites have occurred
sl@0
   280
@param aSize The size of data at aTail
sl@0
   281
@return The number of bytes successfully copied.
sl@0
   282
@post iBuffer.iTail has been updated to point to the trace record following those copied.
sl@0
   283
*/
sl@0
   284
TInt TBTraceBuffer::CopyData(TUint aData, TUint aTail, TInt aSize)
sl@0
   285
	{
sl@0
   286
	// clip size to copy buffer
sl@0
   287
	TInt maxSize = iCopyBufferSize;
sl@0
   288
	if (aSize>maxSize)
sl@0
   289
		aSize = Adjust(aData,maxSize);
sl@0
   290
sl@0
   291
	if (iTail & 1)
sl@0
   292
		return 0; // give up if data we're about to copy has been overwritten
sl@0
   293
sl@0
   294
	memcpy((TUint8*)this+iCopyBuffer, (TUint8*)this+aData, aSize);
sl@0
   295
sl@0
   296
	if (!UpdateTail(aTail, aData+aSize))
sl@0
   297
		return 0;
sl@0
   298
sl@0
   299
	return aSize;
sl@0
   300
	}
sl@0
   301
sl@0
   302
sl@0
   303
/**
sl@0
   304
Get pointer to as much contiguous trace data as is available.
sl@0
   305
@param aData Pointer to the first byte of trace data.
sl@0
   306
@return The number of bytes of trace data available at aData.
sl@0
   307
*/
sl@0
   308
TInt TBTraceBuffer::GetData(TUint8*& aData)
sl@0
   309
	{
sl@0
   310
	TInt retries = 4;
sl@0
   311
sl@0
   312
	// get availabe data...
sl@0
   313
	TUint data, tail;
sl@0
   314
	TInt size = Data(data, tail);
sl@0
   315
	if (!size)
sl@0
   316
		return size; // no data available
sl@0
   317
sl@0
   318
	if (!(iMode & RBTrace::EFreeRunning))
sl@0
   319
		{
sl@0
   320
		// if we got an error from Data but aren't in free-running mode, something has
sl@0
   321
		// been interrupting the writing thread for some time while it has interrupts
sl@0
   322
		// turned off. give up.
sl@0
   323
		if (size<0)
sl@0
   324
			return 0;
sl@0
   325
		// were not in free-running mode, so we can leave the data where it is...
sl@0
   326
		aData = (TUint8*)this + data;
sl@0
   327
		iTail = data;	// OK since iTail never updated by kernel in this mode
sl@0
   328
		return size;
sl@0
   329
		}
sl@0
   330
sl@0
   331
	// if we couldn't get a consistent snapshot of the pointers, we need to disable
sl@0
   332
	// free running, otherwise we will stall for a very long time.
sl@0
   333
	if (size==KErrInUse)
sl@0
   334
		goto giveup;
sl@0
   335
sl@0
   336
	// copy data to the copy buffer...
sl@0
   337
	aData = (TUint8*)this + iCopyBuffer;
sl@0
   338
	size = CopyData(data, tail, size);
sl@0
   339
	if (size)
sl@0
   340
		return size; // success
sl@0
   341
sl@0
   342
	// data copy failed because new data was added during copy; this happens when the buffer
sl@0
   343
	// is full, so now we'll attempt to discard data to give us some breathing space...
sl@0
   344
	while(retries)
sl@0
   345
		{
sl@0
   346
		// see what data is available...
sl@0
   347
		size = Data(data, tail);
sl@0
   348
		if (!size)
sl@0
   349
			return size; // no data in buffer (shouldn't happen because buffer was full to start with)
sl@0
   350
		if (size==KErrInUse)
sl@0
   351
			goto giveup;
sl@0
   352
sl@0
   353
		// discard a proportion of the data...
sl@0
   354
		TInt discard = iCopyBufferSize>>retries;
sl@0
   355
		if (discard>=size)
sl@0
   356
			discard = size;
sl@0
   357
		else
sl@0
   358
			discard = Adjust(data, discard); // make sure we only discard a whole number of trace records
sl@0
   359
		size -= discard;
sl@0
   360
		data = UpdateTail(tail, data+discard);
sl@0
   361
		if (!data)
sl@0
   362
			continue;	// tail was updated before we could discard, so try again
sl@0
   363
		if (!size)
sl@0
   364
			continue;	// we discarded everything - make sure and then exit
sl@0
   365
sl@0
   366
		// try and copy remaining data...
sl@0
   367
		size = CopyData(data, data, size);
sl@0
   368
		if (size)
sl@0
   369
			break; // success!
sl@0
   370
sl@0
   371
		// loop around for another go, discard more this time
sl@0
   372
		--retries;
sl@0
   373
		}
sl@0
   374
sl@0
   375
	if (!size)
sl@0
   376
		{
sl@0
   377
giveup:
sl@0
   378
		// we haven't managed to copy data, so give up and do it with free-running mode off...
sl@0
   379
		TUint32 mode = __e32_atomic_and_acq32(&iMode, ~(TUint32)RBTrace::EFreeRunning);	/* read original mode and disable free running */
sl@0
   380
		size = Data(data, tail);
sl@0
   381
		// as above: if we get an error here then something has been interrupting the writer
sl@0
   382
		// for an unreasonable time, give up.
sl@0
   383
		if (size<0)
sl@0
   384
			return 0;
sl@0
   385
		size = CopyData(data, tail, size);
sl@0
   386
		__e32_atomic_store_ord32(&iMode, mode);	/* restore original mode */
sl@0
   387
		}
sl@0
   388
sl@0
   389
	// we discarded some data, so mark first trace record to indicate that some records are missing...
sl@0
   390
	aData[BTrace::EFlagsIndex] |= BTrace::EMissingRecord;
sl@0
   391
sl@0
   392
	return size;
sl@0
   393
	}
sl@0
   394
sl@0
   395