kerneltest/e32test/nkernsa/nkutils.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 0 a41df078684a
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// e32test\nkernsa\nkutils.cpp
// 
//

#include <nktest/nkutils.h>

extern TDfcQue* CleanupDfcQ;

class NThreadX : public NThread
	{
public:
	NThreadX();
	static void KillDfcFn(TAny*);
	static TDfc* ExitHandler(NThread* aThread);
	static void ExceptionHandler(TAny* aPtr, NThread* aThread);
	static void SignalSemaphoreOnExit(TAny* aP, NThread* aT, TInt aC);
public:
	TDfc iKillDfc;
	TExitFunc iExitFunc;
	TAny* iExitParam;
	};

extern const SNThreadHandlers ThreadHandlers =
	{
	&NThreadX::ExitHandler,
	NTHREAD_DEFAULT_STATE_HANDLER,
	&NThreadX::ExceptionHandler,
	0
	};

NThreadX::NThreadX()
	: iKillDfc(&KillDfcFn, this, 1), iExitFunc(0)
	{
	}

void NThreadX::KillDfcFn(TAny* a)
	{
	NThreadX* t = (NThreadX*)a;
	TExitFunc f = t->iExitFunc;
	TAny* p = t->iExitParam;
	if (f)
		(*f)(p, t, 1);
#ifdef __SMP__
	free((TAny*)t->iNThreadBaseSpare8);
#else
	free((TAny*)t->iSpare8);
#endif
	free((TAny*)t->iStackBase);
	free(t);
	if (f)
		(*f)(p, t, 2);
	}

TDfc* NThreadX::ExitHandler(NThread* aT)
	{
	NThreadX* t = (NThreadX*)aT;
	if (t->iExitFunc)
		(*t->iExitFunc)(t->iExitParam, t, 0);
	return &t->iKillDfc;
	}

extern "C" void ExcFault(TAny*);
void NThreadX::ExceptionHandler(TAny* aPtr, NThread*)
	{
	NKern::DisableAllInterrupts();
	ExcFault(aPtr);
	}

extern "C" unsigned int strlen(const char*);

NThread* CreateThread(const char* aName, NThreadFunction aFunc, TInt aPri, const TAny* aParams, TInt aPSize, TBool aResume, TInt aTimeslice, TExitFunc aExitFunc, TAny* aExitParam, TUint32 aCpuAffinity, NThreadGroup* aGroup)
	{
	__KTRACE_OPT(KTHREAD,DEBUGPRINT("CreateThread %s pri %d", aName, aPri));
	TInt nlen = (TInt)strlen(aName);
	NThreadX* t = new NThreadX;
	TAny* stack = malloc(KStackSize);
	memset(stack, 0xee, KStackSize);
	TAny* namebuf = malloc(nlen+1);
	memcpy(namebuf, aName, nlen+1);
	__KTRACE_OPT(KTHREAD,DEBUGPRINT("CreateThread -> thread at %08x stack %08x", t, stack));

	SNThreadCreateInfo info;

	info.iFunction = aFunc;
	info.iStackBase = stack;
	info.iStackSize = KStackSize;
	info.iPriority = aPri;
	info.iTimeslice = aTimeslice;
	info.iAttributes = 0;
	info.iHandlers = &ThreadHandlers;
	info.iFastExecTable = 0;
	info.iSlowExecTable = 0;
	info.iParameterBlock = (const TUint32*)aParams;
	info.iParameterBlockSize = aPSize;
#ifdef __SMP__
	info.iCpuAffinity = aCpuAffinity;
	info.iGroup = aGroup;
#endif

	TInt r = NKern::ThreadCreate(t, info);
	__NK_ASSERT_ALWAYS(r==KErrNone);
#ifdef __SMP__
	t->iNThreadBaseSpare8 = (TUint32)namebuf;
#else
	t->iSpare8 = (TUint32)namebuf;
#endif
	t->iKillDfc.SetDfcQ(CleanupDfcQ);
	t->iExitFunc = aExitFunc;
	t->iExitParam = aExitParam;
	if (aResume)
		NKern::ThreadResume(t);
	return t;
	}

void NThreadX::SignalSemaphoreOnExit(TAny* aP, NThread* aT, TInt aC)
	{
	NFastSemaphore* s = (NFastSemaphore*)aP;
	(void)aT;
	if (aC==EAfterFree)
		NKern::FSSignal(s);
	}

NThread* CreateThreadSignalOnExit(const char* aName, NThreadFunction aFunc, TInt aPri, const TAny* aParams, TInt aPSize, TInt aTimeslice, NFastSemaphore* aExitSem, TUint32 aCpuAffinity, NThreadGroup* aGroup)
	{
	return CreateThread(aName, aFunc, aPri, aParams, aPSize, TRUE, aTimeslice, &NThreadX::SignalSemaphoreOnExit, aExitSem, aCpuAffinity, aGroup);
	}

NThread* CreateUnresumedThreadSignalOnExit(const char* aName, NThreadFunction aFunc, TInt aPri, const TAny* aParams, TInt aPSize, TInt aTimeslice, NFastSemaphore* aExitSem, TUint32 aCpuAffinity, NThreadGroup* aGroup)
	{
	return CreateThread(aName, aFunc, aPri, aParams, aPSize, FALSE, aTimeslice, &NThreadX::SignalSemaphoreOnExit, aExitSem, aCpuAffinity, aGroup);
	}

void CreateThreadAndWaitForExit(const char* aName, NThreadFunction aFunc, TInt aPri, const TAny* aParams, TInt aPSize, TInt aTimeslice, TUint32 aCpuAffinity, NThreadGroup* aGroup)
	{
	NFastSemaphore s(0);
	CreateThread(aName, aFunc, aPri, aParams, aPSize, TRUE, aTimeslice, &NThreadX::SignalSemaphoreOnExit, &s, aCpuAffinity, aGroup);
	NKern::FSWait(&s);
	}

TDfcQue* CreateDfcQ(const char* aName, TInt aPri, TUint32 aCpuAffinity, NThreadGroup* aGroup)
	{
	__KTRACE_OPT(KTHREAD,DEBUGPRINT("CreateDfcQ %s pri %d cpu %08x", aName, aPri, aCpuAffinity));
	__KTRACE_OPT(KTHREAD,DEBUGPRINT("NKern::CurrentThread() = %08x\n", NKern::CurrentThread()));
	TDfcQue* q = new TDfcQue;
	__KTRACE_OPT(KTHREAD,DEBUGPRINT("CreateDfcQ -> %08x", q));
	NThread* t = CreateThread(aName, &TDfcQue::ThreadFunction, aPri, q, 0, FALSE, KTimeslice, 0, 0, aCpuAffinity, aGroup);
	q->iThread = t;
	NKern::ThreadResume(t);
	return q;
	}

void killDfcFn(TAny* aPtr)
	{
	TDfcQue* q = (TDfcQue*)aPtr;
	delete q;
	NKern::Exit();
	}

void DestroyDfcQ(TDfcQue* aQ)
	{
	NFastSemaphore exitSem(0);
	TDfc killDfc(&killDfcFn, aQ, aQ, 0);
	NThreadX* t = (NThreadX*)aQ->iThread;
	t->iExitFunc = &NThreadX::SignalSemaphoreOnExit;
	t->iExitParam = &exitSem;
	killDfc.Enque();
	NKern::FSWait(&exitSem);
	}

#ifdef __SMP__
class NKTest
	{
public:
	static TInt FSWait(NFastSemaphore* aS, TUint32 aTimeout);
	};

TInt WaitWithTimeout(NFastSemaphore* aS, TUint32 aTimeout)
	{
	return NKTest::FSWait(aS, aTimeout);
	}

TInt NKTest::FSWait(NFastSemaphore* aS, TUint32 aTimeout)
	{
	NThreadBase* pC = NKern::LockC();
	pC->iWaitState.SetUpWait(NThreadBase::EWaitFastSemaphore, 0, aS, aTimeout);
	if (aS->Dec(pC))					// full barrier
		pC->iWaitState.CancelWait();	// don't have to wait
	else
		RescheduleNeeded();				// have to wait
	NKern::PreemptionPoint();
	TInt r = pC->iWaitState.iWtC.iRetVal;
	NKern::Unlock();
	return r;
	}
#else
TInt WaitWithTimeout(NFastSemaphore* aS, TUint32 aTimeout)
	{
	NThreadBase* pC = NKern::LockC();
	if (--aS->iCount < 0)
		{
		NKern::NanoBlock(aTimeout, NThreadBase::EWaitFastSemaphore, aS);
		}
	NKern::PreemptionPoint();
	TInt r = pC->iReturnValue;
	if (r == KErrNone)
		pC->Release(KErrNone);	// cancel the timer on normal completion
	NKern::Unlock();
	return r;
	}
#endif

void FMWaitFull(NFastMutex* aMutex)
	{
	NKern::Lock();
	aMutex->Wait();
	NKern::Unlock();
	}

void FMSignalFull(NFastMutex* aMutex)
	{
	NKern::Lock();
	aMutex->Signal();
	NKern::Unlock();
	}

void WaitForRequest(NRequestStatus& aStatus)
	{
	TInt n = -1;
	do	{
		++n;
		NKern::WaitForAnyRequest();
		} while (aStatus == KRequestPending);
	if (n > 0)
		NKern::ThreadRequestSignal(0, n);
	}


extern "C" {
void SpinWait(TUint32 aTicks)
	{
	TUint32 tc = NKern::TickCount() + aTicks;
	TUint32 x;
	do	{
		x = NKern::TickCount();
		} while (TInt(x-tc)<0);
	}
}