Update contrib.
1 // Copyright (c) 1998-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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
19 // NThreadBase member data
20 #define __INCLUDE_NTHREADBASE_DEFINES__
23 #define __INCLUDE_TDFC_DEFINES__
30 @param aFunction = function to call
31 @param aPtr = parameter to be passed to function
33 EXPORT_C TDfc::TDfc(TDfcFn aFunction, TAny* aPtr)
34 : iPtr(aPtr), iFunction(aFunction), iDfcQ(NULL)
43 /** Construct a DFC without specifying a DFC queue.
44 The DFC queue must be set before the DFC may be queued.
46 @param aFunction = function to call
47 @param aPtr = parameter to be passed to function
48 @param aPriority = priority of DFC within the queue (0 to 7, where 7 is highest)
50 EXPORT_C TDfc::TDfc(TDfcFn aFunction, TAny* aPtr, TInt aPriority)
51 : iPtr(aPtr), iFunction(aFunction), iDfcQ(NULL)
53 __NK_ASSERT_DEBUG((TUint)aPriority<(TUint)KNumDfcPriorities);
54 iPriority=TUint8(aPriority);
61 /** Construct a DFC specifying a DFC queue.
63 @param aFunction = function to call
64 @param aPtr = parameter to be passed to function
65 @param aDfcQ = pointer to DFC queue which this DFC should use
66 @param aPriority = priority of DFC within the queue (0-7)
68 EXPORT_C TDfc::TDfc(TDfcFn aFunction, TAny* aPtr, TDfcQue* aDfcQ, TInt aPriority)
69 : iPtr(aPtr), iFunction(aFunction), iDfcQ(aDfcQ)
71 __NK_ASSERT_DEBUG((TUint)aPriority<(TUint)KNumDfcPriorities);
72 iPriority=TUint8(aPriority);
79 /** Construct a DFC queue
80 Kern::DfcQInit() should be called on the new DFC queue before it can be used.
82 EXPORT_C TDfcQue::TDfcQue()
87 #ifndef __DFC_MACHINE_CODED__
89 /** Queue an IDFC or a DFC from an ISR
91 This function is the only way to queue an IDFC and is the only way to queue
92 a DFC from an ISR. To queue a DFC from an IDFC or a thread either Enque()
93 or DoEnque() should be used.
95 This function does nothing if the IDFC/DFC is already queued.
97 @pre Call only from ISR, IDFC or thread with preemption disabled.
98 @pre Do not call from thread with preemption enabled.
99 @return TRUE if DFC was actually queued by this call
100 FALSE if DFC was already queued on entry so this call did nothing
104 EXPORT_C TBool TDfc::Add()
106 __ASSERT_WITH_MESSAGE_DEBUG( NKern::CurrentContext()!=NKern::EThread || TheScheduler.iKernCSLocked,"Do not call from thread with preemption enabled","TDfc::Add");
107 __ASSERT_WITH_MESSAGE_DEBUG( IsIDFC() || iDfcQ != NULL, "DFC queue not set", "TDfc::Add");
109 __NK_ASSERT_ALWAYS(Interrupt.InInterrupt() || TheScheduler.iKernCSLocked);
115 /** Queue an IDFC or a DFC from an ISR
117 This function is identical to TDfc::Add() but no checks are performed for correct usage,
118 and it contains no instrumentation code.
120 @return TRUE if DFC was actually queued by this call
121 FALSE if DFC was already queued on entry so this call did nothing
126 EXPORT_C TBool TDfc::RawAdd()
128 TInt irq=NKern::DisableAllInterrupts();
130 // make sure DFC not already queued
131 TBool ok = !TestAndSetQueued();
134 TheScheduler.iDfcs.Add(this);
135 TheScheduler.iDfcPendingFlag=1;
138 NKern::RestoreInterrupts(irq);
143 /** Queue a DFC (not an IDFC) from an IDFC or thread with preemption disabled.
145 This function is the preferred way to queue a DFC from an IDFC. It should not
146 be used to queue an IDFC - use TDfc::Add() for this.
148 This function does nothing if the DFC is already queued.
150 @return TRUE if DFC was actually queued by this call
151 FALSE if DFC was already queued on entry so this call did nothing
152 @pre Call only from IDFC or thread with preemption disabled.
153 @pre Do not call from ISR or thread with preemption enabled.
158 EXPORT_C TBool TDfc::DoEnque()
160 __ASSERT_WITH_MESSAGE_DEBUG( (NKern::CurrentContext()==NKern::EIDFC )||( NKern::CurrentContext()==NKern::EThread && TheScheduler.iKernCSLocked),"Do not call from ISR or thread with preemption enabled","TDfc::DoEnque");
161 __NK_ASSERT_DEBUG(!IsIDFC());
162 __ASSERT_WITH_MESSAGE_DEBUG( iDfcQ, "DFC queue not set", "TDfc::Add");
164 // Check not already queued and then mark queued to prevent ISRs touching this DFC
165 TBool ok = !TestAndSetQueued();
171 void TDfc::DoEnqueFinal()
173 // Add a DFC to its final queue. Assumes DFC not currently queued.
174 // Enter and return with kernel locked.
179 NThreadBase* pT=iDfcQ->iThread;
180 if (pT->iNState==NThreadBase::EWaitDfc)
181 pT->CheckSuspendThenReady();
184 void TDfcQue::ThreadFunction(TAny* aDfcQ)
186 TDfcQue& q=*(TDfcQue*)aDfcQ;
187 NThreadBase* pC=TheScheduler.iCurrentThread;
193 pC->iNState=NThreadBase::EWaitDfc;
194 TheScheduler.Remove(pC);
205 (*d.iFunction)(d.iPtr);
211 /** Cancels an IDFC or DFC.
213 This function does nothing if the IDFC or DFC is not queued.
215 @return TRUE if the DFC was actually dequeued by this call. In that case
216 it is guaranteed that the DFC will not execute until it is
218 FALSE if the DFC was not queued on entry to the call, or was in
219 the process of being executed or cancelled. In this case
220 it is possible that the DFC executes after this call
223 @post However in either case it is safe to delete the DFC object on
224 return from this call provided only that the DFC function does not
225 refer to the DFC object itself.
227 @pre IDFC or thread context. Do not call from ISRs.
229 @pre If the DFC function accesses the DFC object itself, the user must ensure that
230 Cancel() cannot be called while the DFC function is running.
232 EXPORT_C TBool TDfc::Cancel()
234 CHECK_PRECONDITIONS(MASK_NOT_ISR,"TDfc::Cancel");
237 if (iQueued) // ISRs can't affect this test since they can't de-queue a DFC or IDFC
239 if (!iOnFinalQ) // OK to check this with interrupts enabled since interrupts can't change it
241 // Must disable interrupts to protect the pending queue
242 TInt irq=NKern::DisableAllInterrupts();
243 SDblQueLink::Deque();
244 NKern::RestoreInterrupts(irq);
248 // Final queues can't be modified by interrupts
252 iQueued=FALSE; // must be done last
259 /** Queues a DFC (not an IDFC) from a thread.
261 Does nothing if DFC is already queued.
263 NOTE: Although this can be called in an IDFC context, it is more efficient to call
264 DoEnque() in this case.
266 @return TRUE if DFC was actually queued by this call
267 FALSE if DFC was already queued on entry so this call did nothing
268 @pre Call either in a thread or an IDFC context.
269 @pre Do not call from an ISR.
271 EXPORT_C TBool TDfc::Enque()
273 CHECK_PRECONDITIONS(MASK_NOT_ISR,"TDfc::Enque()");
275 TBool ret = DoEnque();
281 /** Queue a DFC (not an IDFC) from a thread and also signals a fast mutex.
283 The DFC is unaffected if it is already queued.
285 The fast mutex is signalled before preemption is reenabled to avoid potential
288 @param aMutex = pointer to fast mutex to be signalled;
289 NULL means system lock mutex.
290 @return TRUE if DFC was actually queued by this call
291 FALSE if DFC was already queued on entry so this call did nothing
292 @pre Call in a thread context.
293 @pre Kernel must be unlocked.
294 @pre Do not call from an ISR.
295 @pre Do not call from an IDFC.
297 EXPORT_C TBool TDfc::Enque(NFastMutex* aMutex)
299 CHECK_PRECONDITIONS(MASK_KERNEL_UNLOCKED|MASK_NOT_ISR|MASK_NOT_IDFC,"TDfc::Enque(NFastMutex* aMutex)");
301 aMutex=&TheScheduler.iLock;
303 TBool ret = DoEnque();
310 /** Returns a pointer to the thread on which a DFC runs
312 @return If this is a DFC and the DFC queue has been set, a pointer to the
313 thread which will run the DFC.
314 NULL if this is an IDFC or the DFC queue has not been set.
316 EXPORT_C NThreadBase* TDfc::Thread()
320 return iDfcQ ? iDfcQ->iThread : 0;
324 /******************************************************************************
326 ******************************************************************************/
328 /** Register an IDFC or a DFC to be called when the system goes idle
330 This function does nothing if the IDFC/DFC is already queued.
332 @return TRUE if DFC was actually queued by this call
333 FALSE if DFC was already queued on entry so this call did nothing
335 EXPORT_C TBool TDfc::QueueOnIdle()
337 TInt irq=NKern::DisableAllInterrupts();
339 // make sure DFC not already queued
340 TBool ok = !TestAndSetQueued();
342 TheScheduler.iIdleDfcs.Add(this);
344 NKern::RestoreInterrupts(irq);
349 TUint32 NKern::IdleGenerationCount()
351 return TheScheduler.iIdleGenerationCount;
357 TInt irq = NKern::DisableAllInterrupts();
359 if (!TheScheduler.iIdleDfcs.IsEmpty() && TheScheduler.iDelayedQ.IsEmpty())
361 if (!TheScheduler.iIdleDfcs.IsEmpty())
364 ++TheScheduler.iIdleGenerationCount;
365 TheScheduler.iDfcs.MoveFrom(&TheScheduler.iIdleDfcs);
366 TheScheduler.iDfcPendingFlag=1;
367 NKern::RestoreInterrupts(irq);
370 NKern::RestoreInterrupts(irq);
375 /******************************************************************************
376 * Scheduler IDFC/DFC Processing
377 ******************************************************************************/
379 #ifndef __SCHEDULER_MACHINE_CODED__
380 void TScheduler::QueueDfcs()
382 // Enter with interrupts off and kernel locked
383 // Leave with interrupts off and kernel locked
387 BTrace0(BTrace::ECpuUsage,BTrace::EIDFCStart);
390 // remove from pending queue with interrupts disabled
391 TDfc* d=(TDfc*)iDfcs.GetFirst();
394 NKern::EnableAllInterrupts();
398 (*d->iFunction)(d->iPtr);
402 NKern::DisableAllInterrupts();
404 iDfcPendingFlag = FALSE;
405 BTrace0(BTrace::ECpuUsage,BTrace::EIDFCEnd);
411 /******************************************************************************
412 * Kernel-side asynchronous request DFCs
413 ******************************************************************************/
415 EXPORT_C TAsyncRequest::TAsyncRequest(TDfcFn aFunction, TDfcQue* aDfcQ, TInt aPriority)
416 : TDfc(aFunction, this, aDfcQ, aPriority), iCompletionObject(0), iCancel(0), iResult(0)
421 EXPORT_C void TAsyncRequest::Send(TDfc* aCompletionDfc)
423 __NK_ASSERT_DEBUG(!iCompletionObject);
425 iCompletionObject = (TAny*)((TLinAddr)aCompletionDfc|1);
430 EXPORT_C void TAsyncRequest::Send(NFastSemaphore* aCompletionSemaphore)
432 __NK_ASSERT_DEBUG(!iCompletionObject);
434 iCompletionObject = aCompletionSemaphore;
439 EXPORT_C TInt TAsyncRequest::SendReceive()
441 NFastSemaphore signal;
442 NKern::FSSetOwner(&signal, 0);
444 NKern::FSWait(&signal);
449 EXPORT_C void TAsyncRequest::Cancel()
453 Complete(KErrCancel);
457 EXPORT_C void TAsyncRequest::Complete(TInt aResult)
459 TLinAddr signal = (TLinAddr)__e32_atomic_swp_ord_ptr(&iCompletionObject, 0);
464 ((TDfc*)(signal&~1))->Enque();
466 NKern::FSSignal((NFastSemaphore*)signal);