kerneltest/e32test/nkernsa/fastbuf.cpp
changeset 0 a41df078684a
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     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