sl@0: // Copyright (c) 2007-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: // e32\include\nkernsmp\dfcs.h sl@0: // sl@0: // WARNING: This file contains some APIs which are internal and are subject sl@0: // to change without notice. Such APIs should therefore not be used sl@0: // outside the Kernel and Hardware Services package. sl@0: // sl@0: sl@0: #ifndef __DFCS_H__ sl@0: #define __DFCS_H__ sl@0: sl@0: #include sl@0: #include sl@0: sl@0: class NTimer; sl@0: class NThreadBase; sl@0: class NThread; sl@0: class NFastSemaphore; sl@0: class NFastMutex; sl@0: class TSubScheduler; sl@0: class TCancelIPI; sl@0: sl@0: /******************************************** sl@0: * Delayed function call queue sl@0: ********************************************/ sl@0: sl@0: /** sl@0: @publishedPartner sl@0: @released sl@0: sl@0: The number of DFC priorities the system has, which range from 0 sl@0: to KNumDfcPriorities - 1. sl@0: */ sl@0: const TInt KNumDfcPriorities=8; sl@0: sl@0: /** sl@0: @publishedPartner sl@0: @released sl@0: sl@0: The highest priority level for a DFC, which is equal to KNumDfcPriorities + 1. sl@0: */ sl@0: const TInt KMaxDfcPriority=KNumDfcPriorities-1; sl@0: sl@0: class TDfc; sl@0: /** sl@0: @publishedPartner sl@0: @prototype sl@0: sl@0: Defines a DFC queue. sl@0: sl@0: Each DFC queue is associated with a thread. sl@0: sl@0: @see TDfc sl@0: */ sl@0: class TDfcQue : public TPriList sl@0: { sl@0: public: sl@0: IMPORT_C TDfcQue(); sl@0: sl@0: inline TBool IsEmpty(); /**< @internalComponent */ sl@0: static void ThreadFunction(TAny* aDfcQ); sl@0: public: sl@0: NThreadBase* iThread; /**< @internalComponent */ sl@0: }; sl@0: sl@0: /** sl@0: @internalComponent sl@0: */ sl@0: inline TBool TDfcQue::IsEmpty() sl@0: { return (iPresent[0]==0); } sl@0: sl@0: /******************************************** sl@0: * Delayed function call sl@0: ********************************************/ sl@0: sl@0: /** sl@0: @publishedPartner sl@0: @released sl@0: sl@0: The function type that can be set to run as a DFC or IDFC. sl@0: sl@0: @see TDfc sl@0: */ sl@0: typedef NEventFn TDfcFn; sl@0: sl@0: /** sl@0: @publishedPartner sl@0: @prototype sl@0: sl@0: Defines a Deferred Function Call (DFC) or Immediate Deferred Function Call (IDFC). sl@0: sl@0: A DFC is a kernel object that specifies a function to be run in a thread, sl@0: which is processing a DFC queue. A DFC is added to a DFC queue that is sl@0: associated with a given thread, where it is cooperatively scheduled with other sl@0: DFCs on that queue. Queued DFCs are run in order of their priority, followed sl@0: by the order they where queued. When the DFC gets to run, the function is run sl@0: kernel side, and no other DFC in this queue will get to run until it sl@0: completes. A DFC can be queued from any context. sl@0: sl@0: An IDFC is run as soon as the scheduler is next run, which is during the IRQ sl@0: postamble if queued from an ISR; when the currently-running IDFC completes if sl@0: queued from an IDFC; or when the kernel is next unlocked if queued from thread sl@0: context. Unlike a DFC, the IDFC is not run from a thread context, and its sl@0: execution time must be much smaller. For these reasons, IDFCs are rarely used sl@0: directly, but are used for implementation of the kernel and RTOS personality sl@0: layers. An important use of IDFCs is in the implementation of queuing DFCs from sl@0: an ISR context. IDFCs are run with interrupts enabled but the kernel locked. sl@0: */ sl@0: class TDfc : public NEventHandler sl@0: { sl@0: // iPriority DFC, otherwise IDFC sl@0: // sl@0: // iHState2 = 0 normally sl@0: // = Bit n is set if CPU n is waiting to cancel this DFC sl@0: // iHState1 = 0 if not on any list sl@0: // = 100nnnnn if on CPU n endogenous IDFC/DFC queue sl@0: // = 101nnnnn if on CPU n exogenous IDFC queue sl@0: // = 110nnnnn if running on CPU n sl@0: // = 111nnnnn if running on CPU n and a second execution is also pending (Add() was called while running) sl@0: // = 011nnnnn if running on CPU n and a second idle queue is also pending (QueueOnIdle() was called while running) sl@0: // = 0010000g if idle DFC generation g (could be either on idle queue or CPU endogenous IDFC/DFC queue) sl@0: // = 00000001 if on final DFC queue sl@0: // iHState1 and iHState2 are accessed together as a single 16 bit iDfcState sl@0: // sl@0: // iHState0 is set to 0 when a DFC/IDFC is added to a CPUs endogenous IDFC sl@0: // queue or to the idle queue. It is set to 1 if and when BeginTiedEvent() sl@0: // is subsequently called (thus only for tied IDFCs). sl@0: // sl@0: // For IDFC iHType = EEventHandlerIDFC sl@0: // For DFC iHType = priority (0 to 7) and iTied points to TDfcQue (since DFCs can't be tied) sl@0: // sl@0: public: sl@0: IMPORT_C TDfc(TDfcFn aFunction, TAny* aPtr); // create IDFC sl@0: IMPORT_C TDfc(NSchedulable* aTied, TDfcFn aFunction, TAny* aPtr); // create IDFC tied to a thread or group sl@0: IMPORT_C TDfc(TDfcFn aFunction, TAny* aPtr, TInt aPriority); // create DFC, queue to be set later sl@0: IMPORT_C TDfc(TDfcFn aFunction, TAny* aPtr, TDfcQue* aDfcQ, TInt aPriority); // create DFC sl@0: IMPORT_C ~TDfc(); sl@0: IMPORT_C TBool Add(); // call from ISR or IDFC or thread with kernel locked sl@0: IMPORT_C TBool Cancel(); // call from anywhere except ISR sl@0: IMPORT_C TBool Enque(); // call from thread sl@0: IMPORT_C TBool Enque(NFastMutex* aMutex); // call from thread, signal fast mutex (anti-thrash) sl@0: IMPORT_C TBool DoEnque(); // call from IDFC or thread with kernel locked sl@0: IMPORT_C TBool RawAdd(); // same as Add() but without checks for 'correct' usage or other instrumentation sl@0: IMPORT_C TBool QueueOnIdle(); // queue the DFC to be run when the system goes idle sl@0: IMPORT_C TInt SetTied(NSchedulable* aTied); // tie an IDFC to a thread or group sl@0: IMPORT_C NThreadBase* Thread(); // thread on which DFC runs, NULL for IDFC sl@0: public: sl@0: inline TBool Queued(); sl@0: inline TBool IsIDFC(); sl@0: inline TBool IsDFC(); sl@0: inline void SetDfcQ(TDfcQue* aDfcQ); sl@0: inline void SetFunction(TDfcFn aDfcFn); sl@0: inline void SetPriority(TInt aPriority); /**< @internalComponent */ sl@0: private: sl@0: inline TBool IsValid(); /**< @internalComponent */ sl@0: private: sl@0: TUint32 AddStateChange(); /**< @internalComponent */ sl@0: TUint32 MoveToFinalQStateChange(); /**< @internalComponent */ sl@0: TUint32 TransferIDFCStateChange(TInt aCpu); /**< @internalComponent */ sl@0: TUint32 RunIDFCStateChange(); /**< @internalComponent */ sl@0: TUint32 EndIDFCStateChange(TSubScheduler*); /**< @internalComponent */ sl@0: TUint32 EndIDFCStateChange2(); /**< @internalComponent */ sl@0: TUint32 CancelInitialStateChange(); /**< @internalComponent */ sl@0: TUint32 CancelFinalStateChange(); /**< @internalComponent */ sl@0: TUint32 QueueOnIdleStateChange(); /**< @internalComponent */ sl@0: void ResetState(); /**< @internalComponent */ sl@0: sl@0: friend class TSubScheduler; sl@0: friend class TCancelIPI; sl@0: friend class TDfcQue; sl@0: friend class NTimer; sl@0: }; sl@0: sl@0: /** sl@0: @publishedPartner sl@0: @prototype sl@0: sl@0: Used to find out if the DFC/IDFC is queued on either the pending or final DFC queue. sl@0: sl@0: @return TRUE if the DFC/IDFC is queued, otherwise FALSE. sl@0: sl@0: */ sl@0: inline TBool TDfc::Queued() sl@0: { TUint32 state = i8816.iHState16; return state && (state&0xE0)!=0xC0; } sl@0: sl@0: /** sl@0: @publishedPartner sl@0: @prototype sl@0: sl@0: Determines if the object represents an IDFC rather than a DFC. sl@0: sl@0: @return TRUE if this represents an IDFC, otherwise FALSE. sl@0: */ sl@0: inline TBool TDfc::IsIDFC() sl@0: { return iHType == EEventHandlerIDFC; } sl@0: sl@0: /** sl@0: @publishedPartner sl@0: @prototype sl@0: sl@0: Determines if the object represents a DFC rather than an IDFC. sl@0: sl@0: @return TRUE if this represents a DFC, otherwise FALSE. sl@0: */ sl@0: inline TBool TDfc::IsDFC() sl@0: { return iHType < KNumDfcPriorities; } sl@0: sl@0: sl@0: /** sl@0: @publishedPartner sl@0: @prototype sl@0: sl@0: Sets the DFC queue that the DFC is to added to and executed by. sl@0: sl@0: Note that this function should only be used in the initialisation of the DFC, sl@0: when it is not on any queue. This function does not move the DFC from one sl@0: queue to another. sl@0: sl@0: @param aDfcQ sl@0: sl@0: The DFC queue that the DFC is to be added to and executed by. sl@0: sl@0: */ sl@0: inline void TDfc::SetDfcQ(TDfcQue* aDfcQ) sl@0: { iDfcQ = aDfcQ; } sl@0: sl@0: /** sl@0: @publishedPartner sl@0: @prototype sl@0: sl@0: Sets the function that is run when the DFC/IDFC is scheduled. sl@0: sl@0: @param aDfcFn sl@0: sl@0: The function that the DFC/IDFC runs when it is scheduled. sl@0: sl@0: */ sl@0: inline void TDfc::SetFunction(TDfcFn aDfcFn) sl@0: { iFn = aDfcFn; } sl@0: sl@0: /** sl@0: @internalComponent sl@0: */ sl@0: inline void TDfc::SetPriority(TInt aPriority) sl@0: { iHState = (TUint8)aPriority; } sl@0: sl@0: #ifdef __INCLUDE_TDFC_DEFINES__ sl@0: /** sl@0: @internalComponent sl@0: */ sl@0: #define iDfcState (i8816.iHState16) sl@0: sl@0: /** sl@0: @internalComponent sl@0: */ sl@0: #define DFC_STATE(p) ((p)->i8816.iHState16) sl@0: #endif sl@0: sl@0: sl@0: /******************************************** sl@0: * Kernel-side asynchronous request, sl@0: * based on DFC queueing sl@0: ********************************************/ sl@0: sl@0: /** sl@0: @internalComponent sl@0: */ sl@0: class TAsyncRequest : protected TDfc sl@0: { sl@0: public: sl@0: IMPORT_C void Send(TDfc* aCompletionDfc); sl@0: IMPORT_C void Send(NFastSemaphore* aCompletionSemaphore); sl@0: IMPORT_C TInt SendReceive(); sl@0: IMPORT_C void Cancel(); sl@0: IMPORT_C void Complete(TInt aResult); sl@0: inline TBool PollForCancel() sl@0: { return iCancel; } sl@0: protected: sl@0: IMPORT_C TAsyncRequest(TDfcFn aFunction, TDfcQue* aDfcQ, TInt aPriority); sl@0: protected: sl@0: TAny* iCompletionObject; sl@0: volatile TBool iCancel; sl@0: TInt iResult; sl@0: }; sl@0: sl@0: sl@0: #endif