os/kernelhwsrv/kerneltest/e32test/nkernsa/fastbuf.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) 2007-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
// e32test\nkernsa\fastbuf.cpp
sl@0
    15
// 
sl@0
    16
//
sl@0
    17
sl@0
    18
#include <nktest/nkutils.h>
sl@0
    19
sl@0
    20
template <class T>
sl@0
    21
class WaitFreePipe
sl@0
    22
	{
sl@0
    23
public:
sl@0
    24
	static WaitFreePipe<T>* New(TInt aSize);
sl@0
    25
	~WaitFreePipe();
sl@0
    26
	void InitReader();
sl@0
    27
	void InitWriter();
sl@0
    28
	void Read(T& aOut);
sl@0
    29
	TInt Write(const T& aIn);
sl@0
    30
	inline TUint32 Waits() {return iWaits;}
sl@0
    31
	inline void ResetWaits() {iWaits = 0;}
sl@0
    32
private:
sl@0
    33
	WaitFreePipe();
sl@0
    34
private:
sl@0
    35
	T* volatile iWrite;
sl@0
    36
	T* volatile iRead;
sl@0
    37
	T* iBase;
sl@0
    38
	T* iEnd;
sl@0
    39
	NRequestStatus* volatile iStat;
sl@0
    40
	NThread* iReader;
sl@0
    41
	volatile TUint32 iWaits;
sl@0
    42
	};
sl@0
    43
sl@0
    44
template <class T>
sl@0
    45
WaitFreePipe<T>::WaitFreePipe()
sl@0
    46
	:	iStat(0),
sl@0
    47
		iReader(0),
sl@0
    48
		iWaits(0)
sl@0
    49
	{
sl@0
    50
	}
sl@0
    51
sl@0
    52
template <class T>
sl@0
    53
WaitFreePipe<T>::~WaitFreePipe()
sl@0
    54
	{
sl@0
    55
	free(iBase);
sl@0
    56
	}
sl@0
    57
sl@0
    58
template <class T>
sl@0
    59
WaitFreePipe<T>* WaitFreePipe<T>::New(TInt aSize)
sl@0
    60
	{
sl@0
    61
	WaitFreePipe<T>* p = new WaitFreePipe<T>;
sl@0
    62
	if (!p)
sl@0
    63
		return 0;
sl@0
    64
	p->iBase = (T*)malloc(aSize * sizeof(T));
sl@0
    65
	if (!p->iBase)
sl@0
    66
		{
sl@0
    67
		delete p;
sl@0
    68
		return 0;
sl@0
    69
		}
sl@0
    70
	p->iEnd = p->iBase + aSize;
sl@0
    71
	p->iWrite = p->iBase;
sl@0
    72
	p->iRead = p->iBase;
sl@0
    73
	return p;
sl@0
    74
	}
sl@0
    75
sl@0
    76
template <class T>
sl@0
    77
void WaitFreePipe<T>::InitWriter()
sl@0
    78
	{
sl@0
    79
	}
sl@0
    80
sl@0
    81
template <class T>
sl@0
    82
void WaitFreePipe<T>::InitReader()
sl@0
    83
	{
sl@0
    84
	iReader = NKern::CurrentThread();
sl@0
    85
	}
sl@0
    86
sl@0
    87
template <class T>
sl@0
    88
void WaitFreePipe<T>::Read(T& aOut)
sl@0
    89
	{
sl@0
    90
	while (iRead == iWrite)
sl@0
    91
		{
sl@0
    92
		NRequestStatus s;
sl@0
    93
		s = KRequestPending;
sl@0
    94
		// make sure set to KRequestPending is seen before iStat write
sl@0
    95
		__e32_atomic_store_ord_ptr(&iStat, &s);
sl@0
    96
		// make sure writer sees our request status before we check for buffer empty again
sl@0
    97
		if (iRead != iWrite)
sl@0
    98
			RequestComplete(iReader, (NRequestStatus*&)iStat, 0);
sl@0
    99
		WaitForRequest(s);
sl@0
   100
		++iWaits;
sl@0
   101
		}
sl@0
   102
	aOut = *iRead;
sl@0
   103
	T* new_read = iRead + 1;
sl@0
   104
	if (new_read == iEnd)
sl@0
   105
		new_read = iBase;
sl@0
   106
	// make sure read of data value is observed before update of read pointer
sl@0
   107
	__e32_atomic_store_rel_ptr(&iRead, new_read);
sl@0
   108
	}
sl@0
   109
sl@0
   110
template <class T>
sl@0
   111
TInt WaitFreePipe<T>::Write(const T& aIn)
sl@0
   112
	{
sl@0
   113
	T* new_write = iWrite + 1;
sl@0
   114
	if (new_write == iEnd)
sl@0
   115
		new_write = iBase;
sl@0
   116
	if (new_write == iRead)
sl@0
   117
		return KErrOverflow;	// buffer full
sl@0
   118
	*iWrite = aIn;
sl@0
   119
	// make sure data is seen before updated write pointer
sl@0
   120
	__e32_atomic_store_ord_ptr(&iWrite, new_write);
sl@0
   121
	if (iStat)
sl@0
   122
		RequestComplete(iReader, (NRequestStatus*&)iStat, 0);
sl@0
   123
	return KErrNone;
sl@0
   124
	}
sl@0
   125
sl@0
   126
sl@0
   127
struct SPipeTest
sl@0
   128
	{
sl@0
   129
	WaitFreePipe<TUint32>* iPipe;
sl@0
   130
	TUint64 iTotalWrites;
sl@0
   131
	TUint64 iTotalReads;
sl@0
   132
	volatile TUint32 iWrites;
sl@0
   133
	volatile TUint32 iReads;
sl@0
   134
	TUint32 iMeasure;
sl@0
   135
	volatile TUint32 iReadTime;
sl@0
   136
	volatile TUint32 iWriteTime;
sl@0
   137
	volatile TBool iStop;
sl@0
   138
	};
sl@0
   139
sl@0
   140
void PipeWriterThread(TAny* aPtr)
sl@0
   141
	{
sl@0
   142
	SPipeTest& a = *(SPipeTest*)aPtr;
sl@0
   143
	a.iPipe->InitWriter();
sl@0
   144
	TUint32 seed[2] = {1,0};
sl@0
   145
	TUint32 seqs[2] = {3,0};
sl@0
   146
	TInt r;
sl@0
   147
	while (!a.iStop)
sl@0
   148
		{
sl@0
   149
		TUint32 x = random(seqs);
sl@0
   150
		do	{
sl@0
   151
			r = a.iPipe->Write(x);
sl@0
   152
			if (r != KErrNone)
sl@0
   153
				fcfspin(2*a.iWriteTime);
sl@0
   154
			} while (r != KErrNone);
sl@0
   155
		++a.iTotalWrites;
sl@0
   156
		++a.iWrites;
sl@0
   157
		while (a.iWrites>=a.iMeasure)
sl@0
   158
			{}
sl@0
   159
		TUint32 time = random(seed) % a.iWriteTime;
sl@0
   160
		fcfspin(time);
sl@0
   161
		}
sl@0
   162
	}
sl@0
   163
sl@0
   164
void PipeReaderThread(TAny* aPtr)
sl@0
   165
	{
sl@0
   166
	SPipeTest& a = *(SPipeTest*)aPtr;
sl@0
   167
	TUint32 seed[2] = {2,0};
sl@0
   168
	TUint32 seqs[2] = {3,0};
sl@0
   169
	a.iPipe->InitReader();
sl@0
   170
	a.iPipe->ResetWaits();
sl@0
   171
	while (!a.iStop)
sl@0
   172
		{
sl@0
   173
		TUint32 x = random(seqs);
sl@0
   174
		TUint32 y;
sl@0
   175
		a.iPipe->Read(y);
sl@0
   176
		TEST_RESULT(x==y, "Wrong value");
sl@0
   177
		++a.iTotalReads;
sl@0
   178
		++a.iReads;
sl@0
   179
		if (a.iReads < a.iMeasure)
sl@0
   180
			{
sl@0
   181
			TUint32 time = random(seed) % a.iReadTime;
sl@0
   182
			fcfspin(time);
sl@0
   183
			continue;
sl@0
   184
			}
sl@0
   185
		TUint32 w = a.iPipe->Waits();
sl@0
   186
		TUint32 wr = (w<<4)/a.iMeasure;
sl@0
   187
		TEST_PRINT3("%d waits out of %d (wr=%d)", w, a.iMeasure, wr);
sl@0
   188
		TUint32 rt = a.iReadTime;
sl@0
   189
		TUint32 wt = a.iWriteTime;
sl@0
   190
		switch (wr)
sl@0
   191
			{
sl@0
   192
			case 0:
sl@0
   193
				a.iReadTime = rt>>1;
sl@0
   194
				a.iWriteTime = wt<<1;
sl@0
   195
				break;
sl@0
   196
			case 1:
sl@0
   197
			case 2:
sl@0
   198
			case 3:
sl@0
   199
				a.iReadTime = rt - (rt>>2);
sl@0
   200
				a.iWriteTime = wt + (wt>>2);
sl@0
   201
				break;
sl@0
   202
			case 4:
sl@0
   203
			case 5:
sl@0
   204
			case 6:
sl@0
   205
				a.iReadTime = rt - (rt>>3);
sl@0
   206
				a.iWriteTime = wt + (wt>>3);
sl@0
   207
				break;
sl@0
   208
			case 7:
sl@0
   209
			case 8:
sl@0
   210
				// ok
sl@0
   211
				break;
sl@0
   212
			case 9:
sl@0
   213
			case 10:
sl@0
   214
			case 11:
sl@0
   215
				a.iReadTime = rt - (rt>>3);
sl@0
   216
				a.iWriteTime = wt + (wt>>3);
sl@0
   217
				break;
sl@0
   218
			case 12:
sl@0
   219
			case 13:
sl@0
   220
			case 14:
sl@0
   221
				a.iReadTime = rt + (rt>>2);
sl@0
   222
				a.iWriteTime = wt - (wt>>2);
sl@0
   223
				break;
sl@0
   224
			case 15:
sl@0
   225
			case 16:
sl@0
   226
				a.iReadTime = rt<<1;
sl@0
   227
				a.iWriteTime = wt>>1;
sl@0
   228
				break;
sl@0
   229
			}
sl@0
   230
		TEST_PRINT4("RT: %d->%d WT: %d->%d", rt, a.iReadTime, wt, a.iWriteTime);
sl@0
   231
		a.iPipe->ResetWaits();
sl@0
   232
		a.iReads = 0;
sl@0
   233
		a.iWrites = 0;
sl@0
   234
		}
sl@0
   235
	}
sl@0
   236
sl@0
   237
void DoPipeTest()
sl@0
   238
	{
sl@0
   239
	SPipeTest a;
sl@0
   240
	memclr(&a, sizeof(a));
sl@0
   241
	a.iPipe = WaitFreePipe<TUint32>::New(1024);
sl@0
   242
	TEST_OOM(a.iPipe);
sl@0
   243
	a.iMeasure = 131072;
sl@0
   244
	a.iReadTime = 1024;
sl@0
   245
	a.iWriteTime = 1024;
sl@0
   246
sl@0
   247
	NFastSemaphore exitSem(0);
sl@0
   248
	NThread* reader = CreateThreadSignalOnExit("Reader", &PipeReaderThread, 11, &a, 0, -1, &exitSem, 0);
sl@0
   249
	TEST_OOM(reader);
sl@0
   250
	NThread* writer = CreateThreadSignalOnExit("Writer", &PipeWriterThread, 11, &a, 0, -1, &exitSem, 1);
sl@0
   251
	TEST_OOM(writer);
sl@0
   252
sl@0
   253
	while (a.iTotalWrites < 0x01000000u)
sl@0
   254
		NKern::Sleep(1000);
sl@0
   255
	a.iStop = TRUE;
sl@0
   256
sl@0
   257
	NKern::FSWait(&exitSem);
sl@0
   258
	NKern::FSWait(&exitSem);
sl@0
   259
	}
sl@0
   260
sl@0
   261
void TestWaitFreePipe()
sl@0
   262
	{
sl@0
   263
	DoPipeTest();
sl@0
   264
	}
sl@0
   265
sl@0
   266