sl@0: // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32test\nkernsa\nkutils.cpp sl@0: // sl@0: // sl@0: sl@0: #include sl@0: sl@0: extern TDfcQue* CleanupDfcQ; sl@0: sl@0: class NThreadX : public NThread sl@0: { sl@0: public: sl@0: NThreadX(); sl@0: static void KillDfcFn(TAny*); sl@0: static TDfc* ExitHandler(NThread* aThread); sl@0: static void ExceptionHandler(TAny* aPtr, NThread* aThread); sl@0: static void SignalSemaphoreOnExit(TAny* aP, NThread* aT, TInt aC); sl@0: public: sl@0: TDfc iKillDfc; sl@0: TExitFunc iExitFunc; sl@0: TAny* iExitParam; sl@0: }; sl@0: sl@0: extern const SNThreadHandlers ThreadHandlers = sl@0: { sl@0: &NThreadX::ExitHandler, sl@0: NTHREAD_DEFAULT_STATE_HANDLER, sl@0: &NThreadX::ExceptionHandler, sl@0: 0 sl@0: }; sl@0: sl@0: NThreadX::NThreadX() sl@0: : iKillDfc(&KillDfcFn, this, 1), iExitFunc(0) sl@0: { sl@0: } sl@0: sl@0: void NThreadX::KillDfcFn(TAny* a) sl@0: { sl@0: NThreadX* t = (NThreadX*)a; sl@0: TExitFunc f = t->iExitFunc; sl@0: TAny* p = t->iExitParam; sl@0: if (f) sl@0: (*f)(p, t, 1); sl@0: #ifdef __SMP__ sl@0: free((TAny*)t->iNThreadBaseSpare8); sl@0: #else sl@0: free((TAny*)t->iSpare8); sl@0: #endif sl@0: free((TAny*)t->iStackBase); sl@0: free(t); sl@0: if (f) sl@0: (*f)(p, t, 2); sl@0: } sl@0: sl@0: TDfc* NThreadX::ExitHandler(NThread* aT) sl@0: { sl@0: NThreadX* t = (NThreadX*)aT; sl@0: if (t->iExitFunc) sl@0: (*t->iExitFunc)(t->iExitParam, t, 0); sl@0: return &t->iKillDfc; sl@0: } sl@0: sl@0: extern "C" void ExcFault(TAny*); sl@0: void NThreadX::ExceptionHandler(TAny* aPtr, NThread*) sl@0: { sl@0: NKern::DisableAllInterrupts(); sl@0: ExcFault(aPtr); sl@0: } sl@0: sl@0: extern "C" unsigned int strlen(const char*); sl@0: sl@0: 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) sl@0: { sl@0: __KTRACE_OPT(KTHREAD,DEBUGPRINT("CreateThread %s pri %d", aName, aPri)); sl@0: TInt nlen = (TInt)strlen(aName); sl@0: NThreadX* t = new NThreadX; sl@0: TAny* stack = malloc(KStackSize); sl@0: memset(stack, 0xee, KStackSize); sl@0: TAny* namebuf = malloc(nlen+1); sl@0: memcpy(namebuf, aName, nlen+1); sl@0: __KTRACE_OPT(KTHREAD,DEBUGPRINT("CreateThread -> thread at %08x stack %08x", t, stack)); sl@0: sl@0: SNThreadCreateInfo info; sl@0: sl@0: info.iFunction = aFunc; sl@0: info.iStackBase = stack; sl@0: info.iStackSize = KStackSize; sl@0: info.iPriority = aPri; sl@0: info.iTimeslice = aTimeslice; sl@0: info.iAttributes = 0; sl@0: info.iHandlers = &ThreadHandlers; sl@0: info.iFastExecTable = 0; sl@0: info.iSlowExecTable = 0; sl@0: info.iParameterBlock = (const TUint32*)aParams; sl@0: info.iParameterBlockSize = aPSize; sl@0: #ifdef __SMP__ sl@0: info.iCpuAffinity = aCpuAffinity; sl@0: info.iGroup = aGroup; sl@0: #endif sl@0: sl@0: TInt r = NKern::ThreadCreate(t, info); sl@0: __NK_ASSERT_ALWAYS(r==KErrNone); sl@0: #ifdef __SMP__ sl@0: t->iNThreadBaseSpare8 = (TUint32)namebuf; sl@0: #else sl@0: t->iSpare8 = (TUint32)namebuf; sl@0: #endif sl@0: t->iKillDfc.SetDfcQ(CleanupDfcQ); sl@0: t->iExitFunc = aExitFunc; sl@0: t->iExitParam = aExitParam; sl@0: if (aResume) sl@0: NKern::ThreadResume(t); sl@0: return t; sl@0: } sl@0: sl@0: void NThreadX::SignalSemaphoreOnExit(TAny* aP, NThread* aT, TInt aC) sl@0: { sl@0: NFastSemaphore* s = (NFastSemaphore*)aP; sl@0: (void)aT; sl@0: if (aC==EAfterFree) sl@0: NKern::FSSignal(s); sl@0: } sl@0: sl@0: NThread* CreateThreadSignalOnExit(const char* aName, NThreadFunction aFunc, TInt aPri, const TAny* aParams, TInt aPSize, TInt aTimeslice, NFastSemaphore* aExitSem, TUint32 aCpuAffinity, NThreadGroup* aGroup) sl@0: { sl@0: return CreateThread(aName, aFunc, aPri, aParams, aPSize, TRUE, aTimeslice, &NThreadX::SignalSemaphoreOnExit, aExitSem, aCpuAffinity, aGroup); sl@0: } sl@0: sl@0: NThread* CreateUnresumedThreadSignalOnExit(const char* aName, NThreadFunction aFunc, TInt aPri, const TAny* aParams, TInt aPSize, TInt aTimeslice, NFastSemaphore* aExitSem, TUint32 aCpuAffinity, NThreadGroup* aGroup) sl@0: { sl@0: return CreateThread(aName, aFunc, aPri, aParams, aPSize, FALSE, aTimeslice, &NThreadX::SignalSemaphoreOnExit, aExitSem, aCpuAffinity, aGroup); sl@0: } sl@0: sl@0: void CreateThreadAndWaitForExit(const char* aName, NThreadFunction aFunc, TInt aPri, const TAny* aParams, TInt aPSize, TInt aTimeslice, TUint32 aCpuAffinity, NThreadGroup* aGroup) sl@0: { sl@0: NFastSemaphore s(0); sl@0: CreateThread(aName, aFunc, aPri, aParams, aPSize, TRUE, aTimeslice, &NThreadX::SignalSemaphoreOnExit, &s, aCpuAffinity, aGroup); sl@0: NKern::FSWait(&s); sl@0: } sl@0: sl@0: TDfcQue* CreateDfcQ(const char* aName, TInt aPri, TUint32 aCpuAffinity, NThreadGroup* aGroup) sl@0: { sl@0: __KTRACE_OPT(KTHREAD,DEBUGPRINT("CreateDfcQ %s pri %d cpu %08x", aName, aPri, aCpuAffinity)); sl@0: __KTRACE_OPT(KTHREAD,DEBUGPRINT("NKern::CurrentThread() = %08x\n", NKern::CurrentThread())); sl@0: TDfcQue* q = new TDfcQue; sl@0: __KTRACE_OPT(KTHREAD,DEBUGPRINT("CreateDfcQ -> %08x", q)); sl@0: NThread* t = CreateThread(aName, &TDfcQue::ThreadFunction, aPri, q, 0, FALSE, KTimeslice, 0, 0, aCpuAffinity, aGroup); sl@0: q->iThread = t; sl@0: NKern::ThreadResume(t); sl@0: return q; sl@0: } sl@0: sl@0: void killDfcFn(TAny* aPtr) sl@0: { sl@0: TDfcQue* q = (TDfcQue*)aPtr; sl@0: delete q; sl@0: NKern::Exit(); sl@0: } sl@0: sl@0: void DestroyDfcQ(TDfcQue* aQ) sl@0: { sl@0: NFastSemaphore exitSem(0); sl@0: TDfc killDfc(&killDfcFn, aQ, aQ, 0); sl@0: NThreadX* t = (NThreadX*)aQ->iThread; sl@0: t->iExitFunc = &NThreadX::SignalSemaphoreOnExit; sl@0: t->iExitParam = &exitSem; sl@0: killDfc.Enque(); sl@0: NKern::FSWait(&exitSem); sl@0: } sl@0: sl@0: #ifdef __SMP__ sl@0: class NKTest sl@0: { sl@0: public: sl@0: static TInt FSWait(NFastSemaphore* aS, TUint32 aTimeout); sl@0: }; sl@0: sl@0: TInt WaitWithTimeout(NFastSemaphore* aS, TUint32 aTimeout) sl@0: { sl@0: return NKTest::FSWait(aS, aTimeout); sl@0: } sl@0: sl@0: TInt NKTest::FSWait(NFastSemaphore* aS, TUint32 aTimeout) sl@0: { sl@0: NThreadBase* pC = NKern::LockC(); sl@0: pC->iWaitState.SetUpWait(NThreadBase::EWaitFastSemaphore, 0, aS, aTimeout); sl@0: if (aS->Dec(pC)) // full barrier sl@0: pC->iWaitState.CancelWait(); // don't have to wait sl@0: else sl@0: RescheduleNeeded(); // have to wait sl@0: NKern::PreemptionPoint(); sl@0: TInt r = pC->iWaitState.iWtC.iRetVal; sl@0: NKern::Unlock(); sl@0: return r; sl@0: } sl@0: #else sl@0: TInt WaitWithTimeout(NFastSemaphore* aS, TUint32 aTimeout) sl@0: { sl@0: NThreadBase* pC = NKern::LockC(); sl@0: if (--aS->iCount < 0) sl@0: { sl@0: NKern::NanoBlock(aTimeout, NThreadBase::EWaitFastSemaphore, aS); sl@0: } sl@0: NKern::PreemptionPoint(); sl@0: TInt r = pC->iReturnValue; sl@0: if (r == KErrNone) sl@0: pC->Release(KErrNone); // cancel the timer on normal completion sl@0: NKern::Unlock(); sl@0: return r; sl@0: } sl@0: #endif sl@0: sl@0: void FMWaitFull(NFastMutex* aMutex) sl@0: { sl@0: NKern::Lock(); sl@0: aMutex->Wait(); sl@0: NKern::Unlock(); sl@0: } sl@0: sl@0: void FMSignalFull(NFastMutex* aMutex) sl@0: { sl@0: NKern::Lock(); sl@0: aMutex->Signal(); sl@0: NKern::Unlock(); sl@0: } sl@0: sl@0: void WaitForRequest(NRequestStatus& aStatus) sl@0: { sl@0: TInt n = -1; sl@0: do { sl@0: ++n; sl@0: NKern::WaitForAnyRequest(); sl@0: } while (aStatus == KRequestPending); sl@0: if (n > 0) sl@0: NKern::ThreadRequestSignal(0, n); sl@0: } sl@0: sl@0: sl@0: extern "C" { sl@0: void SpinWait(TUint32 aTicks) sl@0: { sl@0: TUint32 tc = NKern::TickCount() + aTicks; sl@0: TUint32 x; sl@0: do { sl@0: x = NKern::TickCount(); sl@0: } while (TInt(x-tc)<0); sl@0: } sl@0: } sl@0: sl@0: sl@0: sl@0: