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