Update contrib.
1 // Copyright (c) 2006-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.
14 // e32\nkernsmp\dfcs.cpp
19 // NThreadBase member data
20 #define __INCLUDE_NTHREADBASE_DEFINES__
23 #define __INCLUDE_TDFC_DEFINES__
27 extern "C" void send_self_resched_ipi();
31 @param aFunction = function to call
32 @param aPtr = parameter to be passed to function
34 EXPORT_C TDfc::TDfc(TDfcFn aFunction, TAny* aPtr)
39 iHType = EEventHandlerIDFC;
47 /** Construct an IDFC tied to a thread or group
49 @param aTied = pointer to thread or group to which IDFC should be tied
50 @param aFunction = function to call
51 @param aPtr = parameter to be passed to function
53 @pre Call in thread context, interrupts enabled
55 EXPORT_C TDfc::TDfc(NSchedulable* aTied, TDfcFn aFunction, TAny* aPtr)
60 iHType = EEventHandlerIDFC;
72 /** Construct a DFC without specifying a DFC queue.
73 The DFC queue must be set before the DFC may be queued.
75 @param aFunction = function to call
76 @param aPtr = parameter to be passed to function
77 @param aPriority = priority of DFC within the queue (0 to 7, where 7 is highest)
79 EXPORT_C TDfc::TDfc(TDfcFn aFunction, TAny* aPtr, TInt aPriority)
81 __NK_ASSERT_DEBUG((TUint)aPriority<(TUint)KNumDfcPriorities);
85 iHType = TUint8(aPriority);
93 /** Construct a DFC specifying a DFC queue.
95 @param aFunction = function to call
96 @param aPtr = parameter to be passed to function
97 @param aDfcQ = pointer to DFC queue which this DFC should use
98 @param aPriority = priority of DFC within the queue (0-7)
100 EXPORT_C TDfc::TDfc(TDfcFn aFunction, TAny* aPtr, TDfcQue* aDfcQ, TInt aPriority)
102 __NK_ASSERT_DEBUG((TUint)aPriority<(TUint)KNumDfcPriorities);
106 iHType = TUint8(aPriority);
114 /** Tie an IDFC to a thread or group
116 @param aTied = pointer to thread or group to which IDFC should be tied
117 @return KErrNone if successful
118 @return KErrDied if thread has exited or group has been destroyed.
120 @pre Call in thread context, interrupts enabled
121 @pre Must be IDFC not DFC
122 @pre IDFC must not be queued or running
123 @pre IDFC must not already be tied
125 EXPORT_C TInt TDfc::SetTied(NSchedulable* aTied)
127 __NK_ASSERT_ALWAYS(IsIDFC() && i8816.iHState16==0);
128 __NK_ASSERT_ALWAYS(aTied && !iTied);
130 TInt r = aTied->AddTiedEvent(this);
131 __NK_ASSERT_ALWAYS(r==KErrNone || r==KErrDied);
137 /** Destroy a DFC or IDFC
139 @pre Call from thread context with interrupts and preemption enabled
140 @pre Calling thread holds no fast mutex
141 @pre Calling thread in critical section
143 EXPORT_C TDfc::~TDfc()
145 CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL,"TDfc::~TDfc");
147 NEventHandler::TiedLock.LockOnly();
148 NSchedulable* tied = iTied;
149 if (IsDFC() || (IsIDFC() && !tied))
152 iHType = (TUint8)EEventHandlerDummy;
156 __NK_ASSERT_ALWAYS(tied!=0);
165 iHType = (TUint8)EEventHandlerDummy;
168 NEventHandler::TiedLock.UnlockOnly();
173 /** Construct a DFC queue
174 Kern::DfcQInit() should be called on the new DFC queue before it can be used.
176 EXPORT_C TDfcQue::TDfcQue()
182 /** Queue an IDFC or a DFC from an ISR
184 This function is the only way to queue an IDFC and is the only way to queue
185 a DFC from an ISR. To queue a DFC from an IDFC or a thread either Enque()
186 or DoEnque() should be used.
188 This function does nothing if the IDFC/DFC is already queued.
190 @pre Call only from ISR, IDFC or thread with preemption disabled.
191 @pre Do not call from thread with preemption enabled.
192 @return TRUE if DFC was actually queued by this call
193 FALSE if DFC was already queued on entry so this call did nothing
198 EXPORT_C TBool TDfc::Add()
200 __ASSERT_DEBUG(NKern::CurrentContext()!=NKern::EThread || NKern::KernelLocked(), *(int*)0xdfcadd01=0);
201 __ASSERT_DEBUG(IsIDFC() || (IsDFC() && iDfcQ), *(int*)0xdfcadd03=0);
202 // __ASSERT_WITH_MESSAGE_DEBUG( NKern::CurrentContext()!=NKern::EThread || NKern::KernelLocked(),"Do not call from thread with preemption enabled","TDfc::Add");
203 // __ASSERT_WITH_MESSAGE_DEBUG( IsIDFC() || (IsDFC() && iDfcQ), "DFC queue not set", "TDfc::Add");
205 __NK_ASSERT_ALWAYS(Interrupt.InInterrupt() || NKern::KernelLocked());
207 TInt irq = NKern::DisableAllInterrupts();
208 TSubScheduler& ss = SubScheduler();
209 TUint32 orig = 0xFF00;
211 // Transition the state to 'on normal IDFC queue'
214 // All other states unchanged
215 // Return original state
216 if (IsValid()) // don't add if tied and tied thread/group is being/has been destroyed
217 orig = AddStateChange();
220 // wasn't already queued
221 i8888.iHState0 = 0; // BeginTiedEvent() not done
223 ss.iDfcPendingFlag = 1;
225 TUint32 st8 = DFC_STATE(this) & 0xFF;
226 if (st8 != (0x80|ss.iCpuNum))
230 NKern::RestoreInterrupts(irq);
231 return (orig==0 || (orig&0xFFE0)==0x00C0);
235 /** Queue an IDFC or a DFC from any context
237 This function is identical to TDfc::Add() but no checks are performed for correct usage,
238 and it contains no instrumentation code.
240 @return TRUE if DFC was actually queued by this call
241 FALSE if DFC was already queued on entry so this call did nothing
247 EXPORT_C TBool TDfc::RawAdd()
249 TInt irq = NKern::DisableAllInterrupts();
250 TSubScheduler& ss = SubScheduler();
251 TUint32 orig = 0xFF00;
252 if (IsValid()) // don't add if tied and tied thread/group is being/has been destroyed
253 orig = AddStateChange();
256 // wasn't already queued
257 i8888.iHState0 = 0; // BeginTiedEvent() not done
259 ss.iDfcPendingFlag = 1;
260 send_self_resched_ipi(); // ensure current CPU runs the DFC
262 TUint32 st8 = DFC_STATE(this) & 0xFF;
263 if (st8 != (0x80|ss.iCpuNum))
266 // FIXME: Need to wait to ensure IRQ is active before reenabling interrupts
268 NKern::RestoreInterrupts(irq);
269 return (orig==0 || (orig&0xFFE0)==0x00C0);
273 /** Queue a DFC (not an IDFC) from an IDFC or thread with preemption disabled.
275 This function is the preferred way to queue a DFC from an IDFC. It should not
276 be used to queue an IDFC - use TDfc::Add() for this.
278 This function does nothing if the DFC is already queued.
280 @pre Call only from IDFC or thread with preemption disabled.
281 @pre Do not call from ISR or thread with preemption enabled.
282 @return TRUE if DFC was actually queued by this call
283 FALSE if DFC was already queued on entry so this call did nothing
288 EXPORT_C TBool TDfc::DoEnque()
290 __ASSERT_WITH_MESSAGE_DEBUG( (NKern::CurrentContext()==NKern::EIDFC )||( NKern::CurrentContext()==NKern::EThread && NKern::KernelLocked()),"Do not call from ISR or thread with preemption enabled","TDfc::DoEnque");
291 __NK_ASSERT_DEBUG(IsDFC());
292 __ASSERT_WITH_MESSAGE_DEBUG(iDfcQ, "DFC queue not set", "TDfc::DoEnque");
294 // Check not already queued and then mark queued to prevent ISRs touching this DFC
296 NThreadBase* t = q->iThread;
297 t->AcqSLock(); // also protects DFC queue
299 TBool ok = __e32_atomic_cas_acq16(&iDfcState, &expect, 1);
302 // wasn't already queued, now marked as on final queue, which means
303 // attempts to cancel will block on the thread spin lock
304 TUint present = q->iPresent[0];
305 q->Add((TPriListLink*)this);
307 t->iWaitState.UnBlockT(NThreadBase::EWaitDfc, q, KErrNone);
309 t->RelSLock(); // also protects DFC queue
313 void TDfcQue::ThreadFunction(TAny* aDfcQ)
315 TDfcQue& q = *(TDfcQue*)aDfcQ;
316 NThreadBase* t = NKern::CurrentThread();
320 t->AcqSLock(); // also protects DFC queue
323 t->iWaitState.SetUpWait(NThreadBase::EWaitDfc, 0, &q);
325 t->RelSLock(); // also protects DFC queue
331 q.Remove((TPriListLink*)d);
335 t->RelSLock(); // also protects DFC queue
344 void TCancelIPI::Send(TDfc* aDfc, TInt aCpu)
347 Queue(&Isr, 1u<<aCpu);
350 void TCancelIPI::Isr(TGenericIPI* aIPI)
352 TCancelIPI* p = (TCancelIPI*)aIPI;
356 // QueueDfcs() hasn't dequeued it yet
357 // just dequeue it here and reset the state - QueueDfcs() will never see it
358 // Note that this means we have to release the tied thread/group if necessary
359 // BeginTiedEvent() has occurred if iHState0 is set and it's actually an IDFC not an NTimer
360 NSchedulable* tied = (d->iHType==NEventHandler::EEventHandlerIDFC && d->i8888.iHState0) ? d->iTied : 0;
364 tied->EndTiedEvent();
368 // QueueDfcs() has already dequeued it
372 // QueueDfcs() will take care of the tied thread/group
373 d->CancelFinalStateChange();
378 /** Cancels an IDFC or DFC.
380 This function does nothing if the IDFC or DFC is not queued.
382 For any DFC or IDFC the following identity holds:
383 Number of times Add() is called and returns TRUE
384 + Number of times DoEnque() is called and returns TRUE
385 + Number of times Enque() is called and returns TRUE
386 + Number of times QueueOnIdle() is called and returns TRUE
387 = Number of times Cancel() is called and returns TRUE
388 + Number of times the DFC/IDFC function executes
390 @pre IDFC or thread context. Do not call from ISRs.
392 @pre If the DFC function accesses the DFC object itself, the user must ensure that
393 Cancel() cannot be called while the DFC function is running.
395 @return TRUE if the DFC was actually dequeued by this call - i.e. an
396 instance of the DFC's execution has been prevented. It
397 is still possible that a previous execution is still in
399 FALSE if the DFC was not queued on entry to the call, or was in
400 the process of being executed or cancelled. In this case
401 it is possible that the DFC executes after this call
404 @post However in either case it is safe to delete the DFC object on
405 return from this call provided only that the DFC function does not
406 refer to the DFC object itself.
408 EXPORT_C TBool TDfc::Cancel()
410 enum TAction { EDeque=1, EReset=2, EIdleUnlock=4, ESendIPI=8, EWait=16 };
412 CHECK_PRECONDITIONS(MASK_NOT_ISR|MASK_INTERRUPTS_ENABLED,"TDfc::Cancel");
415 TUint action = EIdleUnlock;
418 NSchedulable* tied = 0;
422 TSubScheduler& ss0 = SubScheduler();
424 q = iDfcQ, t = q->iThread, t->AcqSLock();
425 TInt irq = NKern::DisableAllInterrupts();
426 TheScheduler.iIdleSpinLock.LockOnly();
428 // 0000->0000, XX00->ZZ00, xxYY->zzYY
429 TUint state = CancelInitialStateChange();
430 TUint stt = state >> 5;
433 // someone else cancelling at the same time - just wait for them to finish
434 action = EWait|EIdleUnlock;
437 if (state == 0) // DFC not active
440 // possible states here are 0001, 002g, 006m, 008m, 00Am, 00Cm, 00Em
441 ret = (stt!=6); // if running but not pending, Cancel() will not have prevented an execution
442 if (state == TUint(TheScheduler.iIdleGeneration | 0x20))
444 // was on idle queue, BeginTiedEvent() isn't called until QueueDfcs() runs
445 action = EDeque|EReset|EIdleUnlock;
450 // was on final queue, must be DFC not IDFC
451 q->Remove((TPriListLink*)this);
452 action = EReset|EIdleUnlock;
456 // possible states here are 002g (spilled), 006m, 008m, 00Am, 00Cm, 00Em
457 // i.e. either on IDFC queue, ExIDFC queue or running
458 // For IDFCs, tied thread/group is now in play.
459 cpu = state & 0x1f; // CPU it's on for states 006m, 008m, 00Am, 00Cm, 00Em
460 if (stt==3 || stt==6 || stt==7)
462 // It's actually running - must be IDFC. A re-queue may also be pending.
463 TheScheduler.iIdleSpinLock.UnlockOnly();
464 TSubScheduler* ss = TheSubSchedulers + cpu;
466 TBool done = __e32_atomic_cas_acq_ptr(&ss->iCurrentIDFC, &expect, 0);
469 // We cleared iCurrentIDFC so QueueDfcs() won't touch this again - we reset the state and finish up
470 // We must also release the tied thread/group
475 // QueueDfcs() got to iCurrentIDFC before we did, so we interlock with it
476 // and we can leave the EndTiedEvent to it as well
479 // XX00->0000, don't wait
480 TUint32 orig = CancelFinalStateChange() & 0xFF;
481 __NK_ASSERT_ALWAYS(orig==0 || orig==state);
482 action = orig ? EWait : 0;
486 // possible states here 002g (propagated), 008m, 00Am so it's either on the endogenous or exogenous IDFC queue
489 // it's on the exogenous IDFC queue
490 TheScheduler.iIdleSpinLock.UnlockOnly();
491 TSubScheduler* ss = TheSubSchedulers + cpu;
492 ss->iExIDfcLock.LockOnly();
495 // we got to it before QueueDfcs() on the other CPU so we can finish up here
496 // QueueDfcs() will never see it again so we must release tied thread/group
499 ss->iExIDfcLock.UnlockOnly();
503 // QueueDfcs() on other CPU has already dequeued it - we must now interlock with RunIDFCStateChange()
504 ss->iExIDfcLock.UnlockOnly();
507 // XX00->0000, don't wait
508 // QueueDfcs() will take care of tied thread/group
509 TUint32 orig = CancelFinalStateChange() & 0xFF;
510 __NK_ASSERT_ALWAYS(orig==0 || orig==state);
511 action = orig ? EWait : 0;
515 // possible states here 002g (propagated idle) or 008m (IDFC or DFC on endogenous DFC queue)
516 if (stt==1) // propagated idle
517 cpu = TheScheduler.iIdleSpillCpu;
519 // if it's on this CPU's IDFC queue we can just remove it and reset the state here
520 // otherwise we send a cancel IPI to the CPU it's on
521 // We are guaranteed to dequeue the DFC before it executes since the
522 // QueueDfcs() on the target CPU will notice that a cancel is in progress and
523 // so will not run the DFC even if it dequeues it.
524 // QueueDfcs() takes care of the tied thread/group if it sees the DFC/IDFC again, otherwise
525 // we must do it here.
526 if (TUint(cpu) == ss0.iCpuNum)
530 action = EDeque|EReset|EIdleUnlock;
533 action = EIdleUnlock|ESendIPI|EWait;
543 if (action & EIdleUnlock)
544 TheScheduler.iIdleSpinLock.UnlockOnly();
545 NKern::RestoreInterrupts(irq);
549 // on another CPU's IDFC queue so send IPI to remove it
550 if (action & ESendIPI)
554 ipi.WaitCompletion();
558 // wait for cancel to complete
561 TUint n = 0x01000000;
562 while ((iDfcState>>8) & ss0.iCpuMask)
570 // release tied thread/group if waiting for IDFC to complete
572 tied->EndTiedEvent();
578 /** Queues a DFC (not an IDFC) from a thread.
580 Does nothing if DFC is already queued.
582 NOTE: Although this can be called in an IDFC context, it is more efficient to call
583 DoEnque() in this case.
585 @pre Call either in a thread or an IDFC context.
586 @pre Do not call from an ISR.
587 @return TRUE if DFC was actually queued by this call
588 FALSE if DFC was already queued on entry so this call did nothing
590 EXPORT_C TBool TDfc::Enque()
592 CHECK_PRECONDITIONS(MASK_NOT_ISR,"TDfc::Enque()");
594 TBool ret = DoEnque();
600 /** Queue a DFC (not an IDFC) from a thread and also signals a fast mutex.
602 The DFC is unaffected if it is already queued.
604 The fast mutex is signalled before preemption is reenabled to avoid potential
607 @param aMutex = pointer to fast mutex to be signalled;
608 NULL means system lock mutex.
609 @return TRUE if DFC was actually queued by this call
610 FALSE if DFC was already queued on entry so this call did nothing
611 @pre Call in a thread context.
612 @pre Kernel must be unlocked.
613 @pre Do not call from an ISR.
614 @pre Do not call from an IDFC.
616 EXPORT_C TBool TDfc::Enque(NFastMutex* aMutex)
618 CHECK_PRECONDITIONS(MASK_KERNEL_UNLOCKED|MASK_NOT_ISR|MASK_NOT_IDFC,"TDfc::Enque(NFastMutex* aMutex)");
620 aMutex=&TheScheduler.iLock;
622 TBool ret = DoEnque();
629 /** Returns a pointer to the thread on which a DFC runs
631 @return If this is a DFC and the DFC queue has been set, a pointer to the
632 thread which will run the DFC.
633 NULL if this is an IDFC or the DFC queue has not been set.
635 EXPORT_C NThreadBase* TDfc::Thread()
639 return iDfcQ ? iDfcQ->iThread : 0;
643 /******************************************************************************
645 ******************************************************************************/
647 /** Register an IDFC or a DFC to be called when the system goes idle
649 This function does nothing if the IDFC/DFC is already queued.
651 @return TRUE if DFC was actually queued by this call
652 FALSE if DFC was already queued on entry so this call did nothing
654 EXPORT_C TBool TDfc::QueueOnIdle()
656 TInt irq = TheScheduler.iIdleSpinLock.LockIrqSave();
657 TUint32 orig = 0xFF00;
659 // Transition the state to 'on normal idle queue'
662 // All other states unchanged
663 // Return original state
664 if (IsValid()) // don't add if tied and tied thread/group is being/has been destroyed
665 orig = QueueOnIdleStateChange();
668 i8888.iHState0 = 0; // BeginTiedEvent() not done
669 TheScheduler.iIdleDfcs.Add(this);
672 TheScheduler.iIdleSpinLock.UnlockIrqRestore(irq);
673 return (orig==0 || (orig&0xFFE0)==0x00C0);
677 /******************************************************************************
678 * Scheduler IDFC/DFC Processing
679 ******************************************************************************/
681 void TSubScheduler::QueueDfcs()
683 // Enter with interrupts off and kernel locked
684 // Leave with interrupts off and kernel locked
686 // In state descriptions:
687 // XX=8 bits not all zero (bitmask representing cancelling CPUs)
688 // xx=8 bits (bitmask representing cancelling CPUs)
689 // YY=8 bits not all zero
690 // ZZ=XX with an additional bit set corresponding to the current CPU
691 // zz=xx with an additional bit set corresponding to the current CPU
692 // n = current CPU number
693 // m = another CPU number
694 // g = idle generation number
696 __KTRACE_OPT(KSCHED2,DEBUGPRINT("^"));
698 BTrace0(BTrace::ECpuUsage, BTrace::EIDFCStart);
700 NSchedulable* tied = 0;
703 NKern::DisableAllInterrupts();
704 // remove from pending queue with interrupts disabled
705 d = (TDfc*)iDfcs.GetFirst();
710 TUint32 st8 = DFC_STATE(d) & 0xFF;
711 if (st8 != TUint(0x80|iCpuNum) && st8 != TUint(0x21^TheScheduler.iIdleGeneration))
714 if (d->IsDFC()) // also true for mutating NTimer
716 NKern::EnableAllInterrupts();
717 TDfcQue* q = d->iDfcQ;
718 NThreadBase* t = q->iThread;
719 t->AcqSLock(); // also protects DFC queue
721 // transition to 'final queue' state
722 // 002g->0001, ok=TRUE
723 // 008n->0001, ok=TRUE
724 // XXYY->XX00, ok=FALSE
725 // XX00->0000, ok=FALSE
726 // other starting states invalid
727 TUint32 orig = d->MoveToFinalQStateChange() >> 5;
728 if (orig==1 || orig==4)
730 // wasn't being cancelled, now marked as on final queue, which means
731 // attempts to cancel will block on the thread spin lock
732 TUint present = q->iPresent[0];
733 q->Add((TPriListLink*)d);
735 t->iWaitState.UnBlockT(NThreadBase::EWaitDfc, q, KErrNone);
737 t->RelSLock(); // also protects DFC queue
740 // endogenous IDFC - could be tied in which case may need to be punted over to another CPU
741 // can't be mutating NTimer since that would have gone into IsDFC() path
743 if (tied && !d->i8888.iHState0) // if tied and BeginTiedEvent() not already done
745 d->i8888.iHState0 = 1; // flag that BeginTiedEvent() done
746 TInt cpu = tied->BeginTiedEvent();
747 if (TUint(cpu) != iCpuNum)
749 // punt over to other CPU
751 TSubScheduler* ss = TheSubSchedulers + cpu;
752 ss->iExIDfcLock.LockOnly();
753 // transition state here to handle cancel
754 // XXYY->XX00, ok=FALSE
755 // XX00->0000, ok=FALSE
756 // 008n->00Am, ok=TRUE
757 // 002g->00Am, ok=TRUE
758 // other starting states invalid
759 TUint32 orig = d->TransferIDFCStateChange(cpu) >> 5;
760 if (orig==1 || orig==4)
762 kick = !ss->iExIDfcPendingFlag;
763 ss->iExIDfcPendingFlag = TRUE;
766 ss->iExIDfcLock.UnlockOnly();
768 send_resched_ipi(cpu);
769 NKern::EnableAllInterrupts(); // let interrupts in
771 tied->EndTiedEvent(); // IDFC cancelled so release tied thread/group
778 if (!iExIDfcPendingFlag)
780 iExIDfcLock.LockOnly();
781 d = (TDfc*)iExIDfcs.GetFirst();
784 iExIDfcPendingFlag = 0;
785 iExIDfcLock.UnlockOnly();
790 __NK_ASSERT_ALWAYS(d->IsIDFC() && tied); // only tied IDFCs should get here
792 TUint32 st8 = DFC_STATE(d) & 0xFF;
793 if (st8 != (0xA0|iCpuNum))
796 iExIDfcLock.UnlockOnly();
799 // endogenous or exogenous IDFC
800 // if tied, we are on correct CPU
804 // If Cancel() finds the IDFC in the running state (00Cn or 00En) it will do the following
805 // atomic { if (iCurrentIDFC==d) iCurrentIDFC=0; }
806 // We must guarantee that the following access is observed before the state change in RunIDFCStateChange()
807 // We assume the latter has full barrier semantics to guarantee this.
810 // transition to running state
811 // 002g->00Cn, ok=TRUE
812 // 008n->00Cn, ok=TRUE
813 // 00An->00Cn, ok=TRUE
814 // XXYY->XX00, ok=FALSE
815 // XX00->0000, ok=FALSE
816 // other starting states invalid
817 TUint32 orig = d->RunIDFCStateChange() >> 5;
818 NKern::EnableAllInterrupts();
819 if (orig==1 || orig==4 || orig==5)
823 // transition to idle state or rerun if necessary
824 // first swap iCurrentIDFC with 0 - if original value != d, don't touch d again, return 0xFFFFFFFF
831 // other starting states invalid
832 // return original state
833 NKern::DisableAllInterrupts();
834 TUint32 orig = d->EndIDFCStateChange(this);
839 TUint32 st8 = DFC_STATE(d) & 0xFF;
840 if (st8 != (0x80|iCpuNum))
845 else if ((orig>>5)==3)
847 TheScheduler.iIdleSpinLock.LockOnly();
850 orig = d->EndIDFCStateChange2();
852 TheScheduler.iIdleDfcs.Add(d);
853 TheScheduler.iIdleSpinLock.UnlockOnly();
855 NKern::EnableAllInterrupts();
856 if (tied && orig<0x10000)
857 tied->EndTiedEvent(); // if we set iCurrentIDFC back to 0, we release the tied thread/group
863 tied->EndTiedEvent(); // IDFC cancelled so release tied thread/group
867 BTrace0(BTrace::ECpuUsage, BTrace::EIDFCEnd);
869 __KTRACE_OPT(KSCHED2,DEBUGPRINT("~"));
873 /******************************************************************************
874 * Kernel-side asynchronous request DFCs
875 ******************************************************************************/
877 EXPORT_C TAsyncRequest::TAsyncRequest(TDfcFn aFunction, TDfcQue* aDfcQ, TInt aPriority)
878 : TDfc(aFunction, this, aDfcQ, aPriority), iCompletionObject(0), iCancel(0), iResult(0)
883 EXPORT_C void TAsyncRequest::Send(TDfc* aCompletionDfc)
885 __NK_ASSERT_DEBUG(!iCompletionObject);
887 iCompletionObject = (TAny*)((TLinAddr)aCompletionDfc|1);
892 EXPORT_C void TAsyncRequest::Send(NFastSemaphore* aCompletionSemaphore)
894 __NK_ASSERT_DEBUG(!iCompletionObject);
896 iCompletionObject = aCompletionSemaphore;
901 EXPORT_C TInt TAsyncRequest::SendReceive()
903 NFastSemaphore signal;
904 NKern::FSSetOwner(&signal, 0);
906 NKern::FSWait(&signal);
911 EXPORT_C void TAsyncRequest::Cancel()
915 Complete(KErrCancel);
919 EXPORT_C void TAsyncRequest::Complete(TInt aResult)
921 TLinAddr signal = (TLinAddr)__e32_atomic_swp_ord_ptr(&iCompletionObject, 0);
926 ((TDfc*)(signal&~1))->Enque();
928 NKern::FSSignal((NFastSemaphore*)signal);