diff -r 000000000000 -r a41df078684a kernel/eka/include/nkern/nk_priv.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/include/nkern/nk_priv.h Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,603 @@ +// Copyright (c) 1998-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: +// e32\include\nkern\nk_priv.h +// +// WARNING: This file contains some APIs which are internal and are subject +// to change without notice. Such APIs should therefore not be used +// outside the Kernel and Hardware Services package. +// + +#ifndef __NK_PRIV_H__ +#define __NK_PRIV_H__ +#include +#include + +/******************************************** + * DFCs + ********************************************/ + +/** +@internalComponent +*/ +inline TBool TDfc::TestAndSetQueued() + { return __e32_atomic_swp_ord8(&iSpare3, 1); } + +/******************************************** + * Thread + ********************************************/ + +class TUserModeCallback; + +/** +@publishedPartner +@released + +Base class for a nanokernel thread. +*/ +class NThreadBase : public TPriListLink + { +public: + /** + Defines the possible states of a nanokernel thread. + */ + enum NThreadState + { + /** + The thread is eligible for execution. + + Threads in this state are linked into the ready list. + The highest priority READY thread is the one that will run, unless it + is blocked on a fast mutex. + */ + EReady, + + /** + The thread is explicitly suspended (rather than blocking on + a wait object). + */ + ESuspended, + + /** + The thread is blocked waiting for a fast semaphore to be signalled. + */ + EWaitFastSemaphore, + + /** + The thread is blocked waiting for a specific time period to elapse. + */ + ESleep, + + /** + The thread is blocked on a wait object implemented in a layer above + the nanokernel. + + In practice, this means that it is blocked on a Symbian OS + semaphore or mutex. + */ + EBlocked, + + /** + The thread has terminated and will not execute again. + */ + EDead, + + /** + The thread is a DFC-handling thread and it is blocked waiting for + the DFC to be queued. + */ + EWaitDfc, + + /** + Not a thread state, but defines the maximum number of states. + */ + ENumNStates + }; + + + + + /** + Defines a set of values that, when passed to a nanokernel state handler, + indicates which operation is being performed on the thread. + + Every thread that can use a new type of wait object, must have a nanokernel + state handler installed to handle operations on that thread while it is + waiting on that wait object. + + A wait handler has the signature: + @code + void StateHandler(NThread* aThread, TInt aOp, TInt aParam); + @endcode + + where aOp is one of these enum values. + + The state handler is always called with preemption disabled. + */ + enum NThreadOperation + { + /** + Indicates that the thread is suspended while not in a critical section, + and not holding a fast mutex. + + StateHandler() is called in whichever context + NThreadBase::Suspend() is called from. + + Note that the third parameter passed to StateHandler() contains + the requested suspension count. + */ + ESuspend=0, + + /** + Indicates that the thread is being resumed while suspended, and + the last suspension has been removed. + + StateHandler() is called in whichever context + NThreadBase::Resume() is called from. + */ + EResume=1, + + /** + Indicates that the thread has all suspensions cancelled while + actually suspended. + + Statehandler() is called in whichever context + NThreadBase::ForceResume() is called from. + */ + EForceResume=2, + + /** + Indicates that the thread is being released from its wait. + + Statehandler() is called in whichever context + NThreadBase::Release() is called from. + */ + ERelease=3, + + /** + Indicates that the thread's priority is being changed. + + StateHandler() is called in whichever context + NThreadBase::SetPriority() is called from. + */ + EChangePriority=4, + + /** + Indicates that the thread has called NKern::ThreadLeaveCS() with + an unknown NThreadBase::iCsFunction that is negative, but not equal + to NThreadBase::ECsExitPending. + + Note that NThreadBase::iCsFunction is internal to Symbian OS. + */ + ELeaveCS=5, + + /** + Indicates that the thread's wait timeout has expired, and no timeout + handler has been defined for that thread. + + StateHandler() is called in the context of the nanokernel + timer thread, DfcThread1. + */ + ETimeout=6, + }; + + enum NThreadCSFunction + { + ECSExitPending=-1, + ECSExitInProgress=-2 + }; + + enum NThreadTimeoutOp + { + ETimeoutPreamble=0, + ETimeoutPostamble=1, + ETimeoutSpurious=2, + }; +public: + NThreadBase(); + TInt Create(SNThreadCreateInfo& anInfo, TBool aInitial); + IMPORT_C void CheckSuspendThenReady(); + IMPORT_C void Ready(); + void DoReady(); + void DoCsFunction(); + IMPORT_C TBool Suspend(TInt aCount); + IMPORT_C TBool Resume(); + IMPORT_C TBool ForceResume(); + IMPORT_C void Release(TInt aReturnCode); + IMPORT_C void RequestSignal(); + IMPORT_C void SetPriority(TInt aPriority); + void SetEntry(NThreadFunction aFunction); + IMPORT_C void Kill(); + void Exit(); + void ForceExit(); + // hooks for platform-specific code + void OnKill(); + void OnExit(); +public: + static void TimerExpired(TAny* aPtr); + inline void UnknownState(TInt aOp, TInt aParam) + { (*iHandlers->iStateHandler)((NThread*)this,aOp,aParam); } + + /** @internalComponent */ + inline TUint8 Attributes() + { return iSpare2; } + + /** @internalComponent */ + inline TUint8 SetAttributes(TUint8 aNewAtt) + { return __e32_atomic_swp_ord8(&iSpare2, aNewAtt); } + + /** @internalComponent */ + inline TUint8 ModifyAttributes(TUint8 aClearMask, TUint8 aSetMask) + { return __e32_atomic_axo_ord8(&iSpare2, (TUint8)~(aClearMask|aSetMask), aSetMask); } + + /** @internalComponent */ + inline void SetAddressSpace(TAny* a) + { iAddressSpace=a; } + + inline void SetReturnValue(TInt aValue) + { iReturnValue=aValue; } + inline void SetExtraContext(TAny* a, TInt aSize) + { iExtraContext = a; iExtraContextSize = aSize; } + + /** @internalComponent */ + void CallUserModeCallbacks(); +public: +// TUint8 iNState; // use iSpare1 for state +// TUint8 i_ThrdAttr; /**< @internalComponent */ // use iSpare2 for attributes +// TUint8 iUserContextType; // use iSpare3 + NFastMutex* iHeldFastMutex; /**< @internalComponent */ // fast mutex held by this thread + NFastMutex* iWaitFastMutex; /**< @internalComponent */ // fast mutex on which this thread is blocked + TAny* iAddressSpace; /**< @internalComponent */ + TInt iTime; // time remaining + TInt iTimeslice; // timeslice for this thread + NFastSemaphore iRequestSemaphore; /**< @internalComponent */ + TAny* iWaitObj; // object on which this thread is waiting + TInt iSuspendCount; /**< @internalComponent */ // -how many times we have been suspended + TInt iCsCount; /**< @internalComponent */ // critical section count + TInt iCsFunction; /**< @internalComponent */ // what to do on leaving CS: +n=suspend n times, 0=nothing, -1=exit + NTimer iTimer; /**< @internalComponent */ + TInt iReturnValue; + TLinAddr iStackBase; /**< @internalComponent */ + TInt iStackSize; /**< @internalComponent */ + const SNThreadHandlers* iHandlers; /**< @internalComponent */ // additional thread event handlers + const SFastExecTable* iFastExecTable; /**< @internalComponent */ + const SSlowExecEntry* iSlowExecTable; /**< @internalComponent */ // points to first entry iEntries[0] + TLinAddr iSavedSP; /**< @internalComponent */ + TAny* iExtraContext; /**< @internalComponent */ // parent FPSCR value (iExtraContextSize == -1), coprocessor context (iExtraContextSize > 0) or NULL + TInt iExtraContextSize; /**< @internalComponent */ // +ve=dynamically allocated, 0=none, -1=iExtraContext stores parent FPSCR value + TUint iLastStartTime; /**< @internalComponent */ // last start of execution timestamp + TUint64 iTotalCpuTime; /**< @internalComponent */ // total time spent running, in hi-res timer ticks + TUint32 iTag; /**< @internalComponent */ // User defined set of bits which is ANDed with a mask when the thread is scheduled, and indicates if a DFC should be scheduled. + TAny* iVemsData; /**< @internalComponent */ // This pointer can be used by any VEMS to store any data associated with the thread. This data must be clean up before the Thread Exit Monitor completes. + TUserModeCallback* volatile iUserModeCallbacks; /**< @internalComponent */ // Head of singly-linked list of callbacks + TUint32 iSpare7; /**< @internalComponent */ // spare to allow growth while preserving BC + TUint32 iSpare8; /**< @internalComponent */ // spare to allow growth while preserving BC + }; + +__ASSERT_COMPILE(!(_FOFF(NThreadBase,iTotalCpuTime)&7)); + +#ifdef __INCLUDE_NTHREADBASE_DEFINES__ +#define iNState iSpare1 +#define i_ThrdAttr iSpare2 +#define iUserContextType iSpare3 +#endif + +#define i_NThread_BasePri iPriority + +/******************************************** + * Scheduler + ********************************************/ + +/** +@internalComponent +*/ +class TScheduler : public TPriListBase + { +public: + TScheduler(); + void Remove(NThreadBase* aThread); + void RotateReadyList(TInt aPriority); + void QueueDfcs(); + static void Reschedule(); + static void YieldTo(NThreadBase* aThread); + void TimesliceTick(); + IMPORT_C static TScheduler* Ptr(); + inline void SetProcessHandler(TLinAddr aHandler) {iProcessHandler=aHandler;} +private: + SDblQueLink* iExtraQueues[KNumPriorities-1]; +public: + TUint8 iRescheduleNeededFlag; + TUint8 iDfcPendingFlag; + TInt iKernCSLocked; + SDblQue iDfcs; + TLinAddr iMonitorExceptionHandler; + TLinAddr iProcessHandler; + TLinAddr iRescheduleHook; + TUint8 iInIDFC; + NFastMutex iLock; + NThreadBase* iCurrentThread; + TAny* iAddressSpace; + TAny* iExtras[16]; + // For EMI support + NThread* iSigma; + TDfc* iEmiDfc; + TUint32 iEmiMask; + TUint32 iEmiState; + TUint32 iEmiDfcTrigger; + TBool iLogging; + TAny* iBufferStart; + TAny* iBufferEnd; + TAny* iBufferTail; + TAny* iBufferHead; + // For BTrace suport + TUint8 iCpuUsageFilter; + TUint8 iFastMutexFilter; + BTrace::THandler iBTraceHandler; + // Idle notification + SDblQue iIdleDfcs; + TUint32 iIdleGenerationCount; + // Delayed threads + SDblQue iDelayedQ; + TDfc iDelayDfc; + }; + +GLREF_D TScheduler TheScheduler; + +/** +@internalComponent +*/ +inline void RescheduleNeeded() + {TheScheduler.iRescheduleNeededFlag=TRUE;} + +#include + +/** +@internalComponent +*/ +inline NThread* NCurrentThread() + { return (NThread*)TheScheduler.iCurrentThread; } + + +/** +@internalComponent +*/ +#define __NK_ASSERT_UNLOCKED __NK_ASSERT_DEBUG(TheScheduler.iKernCSLocked==0) + +/** +@internalComponent +*/ +#define __NK_ASSERT_LOCKED __NK_ASSERT_DEBUG(TheScheduler.iKernCSLocked!=0) + +#ifdef _DEBUG +/** +@publishedPartner +@released +*/ +#define __ASSERT_NO_FAST_MUTEX { \ + NThread* nt=NKern::CurrentThread(); \ + __NK_ASSERT_DEBUG(!nt->iHeldFastMutex); \ + } + +/** +@publishedPartner +@released +*/ +#define __ASSERT_FAST_MUTEX(m) { \ + NThread* nt=NKern::CurrentThread(); \ + __NK_ASSERT_DEBUG(nt->iHeldFastMutex==(m) && (m)->iHoldingThread==nt); \ + } + +/** +@publishedPartner +@released +*/ +#define __ASSERT_SYSTEM_LOCK { \ + NThread* nt=NKern::CurrentThread(); \ + NFastMutex& m=TScheduler::Ptr()->iLock; \ + __NK_ASSERT_DEBUG(nt->iHeldFastMutex==&m && m.iHoldingThread==nt); \ + } + +#define __ASSERT_NOT_ISR __NK_ASSERT_DEBUG(NKern::CurrentContext()!=NKern::EInterrupt) + +#else +#define __ASSERT_NO_FAST_MUTEX +#define __ASSERT_FAST_MUTEX(m) +#define __ASSERT_SYSTEM_LOCK +#define __ASSERT_NOT_ISR +#endif + +/******************************************** + * System timer queue + ********************************************/ + +/** +@publishedPartner +@released +*/ +class NTimerQ + { + friend class NTimer; +public: + typedef void (*TDebugFn)(TAny* aPtr, TInt aPos); /**< @internalComponent */ + enum { ETimerQMask=31, ENumTimerQueues=32 }; /**< @internalComponent */ // these are not easily modifiable + + /** @internalComponent */ + struct STimerQ + { + SDblQue iIntQ; + SDblQue iDfcQ; + }; +public: + NTimerQ(); + static void Init1(TInt aTickPeriod); + static void Init3(TDfcQue* aDfcQ); + IMPORT_C static TAny* TimerAddress(); + IMPORT_C void Tick(); + IMPORT_C static TInt IdleTime(); + IMPORT_C static void Advance(TInt aTicks); +private: + static void DfcFn(TAny* aPtr); + void Dfc(); + void Add(NTimer* aTimer); + void AddFinal(NTimer* aTimer); +public: + STimerQ iTickQ[ENumTimerQueues]; /**< @internalComponent */ // NOTE: the order of member data is important + TUint32 iPresent; /**< @internalComponent */ // The assembler code relies on it + TUint32 iMsCount; /**< @internalComponent */ + SDblQue iHoldingQ; /**< @internalComponent */ + SDblQue iOrderedQ; /**< @internalComponent */ + SDblQue iCompletedQ; /**< @internalComponent */ + TDfc iDfc; /**< @internalComponent */ + TUint8 iTransferringCancelled; /**< @internalComponent */ + TUint8 iCriticalCancelled; /**< @internalComponent */ + TUint8 iPad1; /**< @internalComponent */ + TUint8 iPad2; /**< @internalComponent */ + TDebugFn iDebugFn; /**< @internalComponent */ + TAny* iDebugPtr; /**< @internalComponent */ + TInt iTickPeriod; /**< @internalComponent */ // in microseconds + /** + This member is intended for use by ASSP/variant interrupt code as a convenient + location to store rounding error information where hardware interrupts are not + exactly one millisecond. The Symbian kernel does not make any use of this member. + @publishedPartner + @released + */ + TInt iRounding; + }; + +GLREF_D NTimerQ TheTimerQ; + +/** +@internalComponent +*/ +inline TUint32 NTickCount() + {return TheTimerQ.iMsCount;} + +/** +@internalComponent +*/ +inline TInt NTickPeriod() + {return TheTimerQ.iTickPeriod;} + + +extern "C" { +/** +@internalComponent +*/ +extern void NKCrashHandler(TInt aPhase, const TAny* a0, TInt a1); + +/** +@internalComponent +*/ +extern TUint32 CrashState; +} + + +#define __ACQUIRE_BTRACE_LOCK() +#define __RELEASE_BTRACE_LOCK() + +/** +@internalComponent +*/ +TBool InterruptsStatus(TBool aRequest); + + +//declarations for the checking of kernel precoditions +#ifdef _DEBUG + +/** +@internalComponent +*/ +#define MASK_NO_FAST_MUTEX 0x1 +#define MASK_CRITICAL 0x2 +#define MASK_NO_CRITICAL 0x4 +#define MASK_KERNEL_LOCKED 0x8 +#define MASK_KERNEL_UNLOCKED 0x10 +#define MASK_KERNEL_LOCKED_ONCE 0x20 +#define MASK_INTERRUPTS_ENABLED 0x40 +#define MASK_INTERRUPTS_DISABLED 0x80 +#define MASK_SYSTEM_LOCKED 0x100 +#define MASK_NOT_ISR 0x400 +#define MASK_NOT_IDFC 0x800 +#define MASK_NOT_THREAD 0x1000 +#define MASK_NO_CRITICAL_IF_USER 0x2000 +#define MASK_THREAD_STANDARD ( MASK_NO_FAST_MUTEX | MASK_KERNEL_UNLOCKED | MASK_INTERRUPTS_ENABLED | MASK_NOT_ISR | MASK_NOT_IDFC ) +#define MASK_THREAD_CRITICAL ( MASK_THREAD_STANDARD | MASK_CRITICAL ) +#define MASK_ALWAYS_FAIL 0x4000 +#define MASK_NO_RESCHED 0x8000 + +#if defined(__STANDALONE_NANOKERNEL__) || (!defined (__KERNEL_APIS_CONTEXT_CHECKS_WARNING__)&&!defined (__KERNEL_APIS_CONTEXT_CHECKS_FAULT__)) +#define CHECK_PRECONDITIONS(mask,function) +#define __ASSERT_WITH_MESSAGE_DEBUG(cond,message,function) + +#else +/** +@internalComponent +*/ +extern "C" TInt CheckPreconditions(TUint32 aConditionMask, const char* aFunction, TLinAddr aAddr); +/** +@internalComponent +*/ +#define CHECK_PRECONDITIONS(mask,function) CheckPreconditions(mask,function,0) + +#ifdef __KERNEL_APIS_CONTEXT_CHECKS_FAULT__ + +/** +@internalComponent +*/ +#define __ASSERT_WITH_MESSAGE_DEBUG(cond,message,function) \ + __ASSERT_DEBUG( (cond), ( \ + DEBUGPRINT("Assertion failed: %s\nFunction: %s\n",message,function),\ + NKFault(function, 0))) + +#else//!__KERNEL_APIS_CONTEXT_CHECKS_FAULT__ +/** +@internalComponent +*/ +#define __ASSERT_WITH_MESSAGE_DEBUG(cond,message,function) \ + __ASSERT_DEBUG( (cond), \ + DEBUGPRINT("Assertion failed: %s\nFunction: %s\n",message,function)) + + +#endif//__KERNEL_APIS_CONTEXT_CHECKS_FAULT__ +#endif//(!defined (__KERNEL_APIS_CONTEXT_CHECKS_WARNING__)&&!defined (__KERNEL_APIS_CONTEXT_CHECKS_FAULT__)) + +#else//if !DEBUG + +#define CHECK_PRECONDITIONS(mask,function) +#define __ASSERT_WITH_MESSAGE_DEBUG(cond,message,function) + +#endif//_DEBUG + +#if (!defined (__KERNEL_APIS_CONTEXT_CHECKS_WARNING__)&&!defined (__KERNEL_APIS_CONTEXT_CHECKS_FAULT__)) +#define __ASSERT_WITH_MESSAGE_ALWAYS(cond,message,function) +#else +#ifdef __KERNEL_APIS_CONTEXT_CHECKS_FAULT__ +/** +@internalComponent +*/ +#define __ASSERT_WITH_MESSAGE_ALWAYS(cond,message,function) \ + __ASSERT_ALWAYS( (cond), ( \ + DEBUGPRINT("Assertion failed: %s\nFunction: %s\n",message,function),\ + NKFault(function, 0))) +#else +/** +@internalComponent +*/ +#define __ASSERT_WITH_MESSAGE_ALWAYS(cond,message,function) \ + __ASSERT_ALWAYS( (cond), \ + DEBUGPRINT("Assertion failed: %s\nFunction: %s\n",message,function)) +#endif//__KERNEL_APIS_CONTEXT_CHECKS_FAULT__ +#endif//(!defined (__KERNEL_APIS_CONTEXT_CHECKS_WARNING__)&&!defined (__KERNEL_APIS_CONTEXT_CHECKS_FAULT__)) + +#endif