34 } |
34 } |
35 |
35 |
36 extern void __ltr(TInt /*aSelector*/); |
36 extern void __ltr(TInt /*aSelector*/); |
37 |
37 |
38 extern "C" TUint __tr(); |
38 extern "C" TUint __tr(); |
39 extern void InitTimestamp(TSubScheduler* aSS, SNThreadCreateInfo& aInfo); |
39 extern void InitAPTimestamp(SNThreadCreateInfo& aInfo); |
40 |
40 |
41 TInt NThread::Create(SNThreadCreateInfo& aInfo, TBool aInitial) |
41 TInt NThread::Create(SNThreadCreateInfo& aInfo, TBool aInitial) |
42 { |
42 { |
43 if (!aInfo.iStackBase || aInfo.iStackSize<0x100) |
43 if (!aInfo.iStackBase || aInfo.iStackSize<0x100) |
44 return KErrArgument; |
44 return KErrArgument; |
45 new (this) NThread; |
45 new (this) NThread; |
46 TInt cpu = -1; |
46 TInt cpu = -1; |
47 TSubScheduler* ss = 0; |
|
48 if (aInitial) |
47 if (aInitial) |
49 { |
48 { |
50 cpu = __e32_atomic_add_ord32(&TheScheduler.iNumCpus, 1); |
49 cpu = __e32_atomic_add_ord32(&TheScheduler.iNumCpus, 1); |
51 if (cpu==0) |
50 if (cpu==0) |
52 memset(SubSchedulerLookupTable, 0x9a, sizeof(SubSchedulerLookupTable)); |
51 memset(SubSchedulerLookupTable, 0x9a, sizeof(SubSchedulerLookupTable)); |
53 aInfo.iCpuAffinity = cpu; |
52 aInfo.iCpuAffinity = cpu; |
54 // OK since we can't migrate yet |
53 // OK since we can't migrate yet |
55 TUint32 apicid = *(volatile TUint32*)(X86_LOCAL_APIC_BASE + X86_LOCAL_APIC_OFFSET_ID) >> 24; |
54 TUint32 apicid = *(volatile TUint32*)(X86_LOCAL_APIC_BASE + X86_LOCAL_APIC_OFFSET_ID) >> 24; |
56 ss = &TheSubSchedulers[cpu]; |
55 TSubScheduler& ss = TheSubSchedulers[cpu]; |
57 ss->iSSX.iAPICID = apicid << 24; |
56 ss.i_APICID = (TAny*)(apicid<<24); |
58 ss->iCurrentThread = this; |
57 ss.iCurrentThread = this; |
59 ss->iDeferShutdown = 0; |
58 SubSchedulerLookupTable[apicid] = &ss; |
60 SubSchedulerLookupTable[apicid] = ss; |
59 ss.iLastTimestamp64 = NKern::Timestamp(); |
61 iRunCount.i64 = UI64LIT(1); |
60 iRunCount64 = UI64LIT(1); |
62 iActiveState = 1; |
61 __KTRACE_OPT(KBOOT,DEBUGPRINT("Init: cpu=%d APICID=%08x ss=%08x", cpu, apicid, &ss)); |
63 __KTRACE_OPT(KBOOT,DEBUGPRINT("Init: cpu=%d APICID=%08x ss=%08x", cpu, apicid, ss)); |
|
64 if (cpu) |
62 if (cpu) |
65 { |
63 { |
66 __ltr(TSS_SELECTOR(cpu)); |
64 __ltr(TSS_SELECTOR(cpu)); |
67 NIrq::HwInit2AP(); |
65 NIrq::HwInit2AP(); |
68 __e32_atomic_ior_ord32(&TheScheduler.iThreadAcceptCpus, 1<<cpu); |
66 __e32_atomic_ior_ord32(&TheScheduler.iActiveCpus1, 1<<cpu); |
69 __e32_atomic_ior_ord32(&TheScheduler.iIpiAcceptCpus, 1<<cpu); |
67 __e32_atomic_ior_ord32(&TheScheduler.iActiveCpus2, 1<<cpu); |
70 __e32_atomic_ior_ord32(&TheScheduler.iCpusNotIdle, 1<<cpu); |
68 __e32_atomic_ior_ord32(&TheScheduler.iCpusNotIdle, 1<<cpu); |
71 __e32_atomic_add_ord32(&TheScheduler.iCCRequestLevel, 1); |
|
72 __KTRACE_OPT(KBOOT,DEBUGPRINT("AP TR=%x",__tr())); |
69 __KTRACE_OPT(KBOOT,DEBUGPRINT("AP TR=%x",__tr())); |
73 } |
70 } |
74 } |
71 } |
75 TInt r=NThreadBase::Create(aInfo,aInitial); |
72 TInt r=NThreadBase::Create(aInfo,aInitial); |
76 if (r!=KErrNone) |
73 if (r!=KErrNone) |
151 } |
147 } |
152 TScheduler& s = TheScheduler; |
148 TScheduler& s = TheScheduler; |
153 TInt irq = NKern::DisableAllInterrupts(); |
149 TInt irq = NKern::DisableAllInterrupts(); |
154 TSubScheduler& ss = SubScheduler(); |
150 TSubScheduler& ss = SubScheduler(); |
155 NThreadBase* ct = ss.iCurrentThread; |
151 NThreadBase* ct = ss.iCurrentThread; |
156 TInt inc = TInt(ss.iSSX.iIrqNestCount); |
152 TInt inc = TInt(ss.i_IrqNestCount); |
157 TInt cpu = ss.iCpuNum; |
153 TInt cpu = ss.iCpuNum; |
158 NKern::RestoreInterrupts(irq); |
154 NKern::RestoreInterrupts(irq); |
159 DEBUGPRINT("Thread %T, CPU %d, KLCount=%08x, IrqNest=%d",ct,cpu,ss.iKernLockCount,inc); |
155 DEBUGPRINT("Thread %T, CPU %d, KLCount=%08x, IrqNest=%d",ct,cpu,ss.iKernLockCount,inc); |
160 } |
156 } |
161 |
157 |
281 void TGetContextIPI::Isr(TGenericIPI* aPtr) |
277 void TGetContextIPI::Isr(TGenericIPI* aPtr) |
282 { |
278 { |
283 TGetContextIPI& ipi = *(TGetContextIPI*)aPtr; |
279 TGetContextIPI& ipi = *(TGetContextIPI*)aPtr; |
284 TX86RegSet& a = *ipi.iContext; |
280 TX86RegSet& a = *ipi.iContext; |
285 TSubScheduler& ss = SubScheduler(); |
281 TSubScheduler& ss = SubScheduler(); |
286 TUint32* irqstack = (TUint32*)ss.iSSX.iIrqStackTop; |
282 TUint32* irqstack = (TUint32*)ss.i_IrqStackTop; |
287 SThreadExcStack* txs = (SThreadExcStack*)irqstack[-1]; // first word pushed on IRQ stack points to thread supervisor stack |
283 SThreadExcStack* txs = (SThreadExcStack*)irqstack[-1]; // first word pushed on IRQ stack points to thread supervisor stack |
288 GetContextAfterExc(a, txs, *ipi.iAvailRegsMask, TRUE); |
284 GetContextAfterExc(a, txs, *ipi.iAvailRegsMask, TRUE); |
289 } |
285 } |
290 |
286 |
291 void TGetContextIPI::Get(TInt aCpu, TX86RegSet& aContext, TUint32& aAvailRegsMask) |
287 void TGetContextIPI::Get(TInt aCpu, TX86RegSet& aContext, TUint32& aAvailRegsMask) |
569 aThread->SetUserContext(a, mask); |
565 aThread->SetUserContext(a, mask); |
570 NKern::Unlock(); |
566 NKern::Unlock(); |
571 } |
567 } |
572 |
568 |
573 |
569 |
|
570 /** Return the total CPU time so far used by the specified thread. |
|
571 |
|
572 @return The total CPU time in units of 1/NKern::CpuTimeMeasFreq(). |
|
573 */ |
|
574 EXPORT_C TUint64 NKern::ThreadCpuTime(NThread* aThread) |
|
575 { |
|
576 TSubScheduler* ss = 0; |
|
577 NKern::Lock(); |
|
578 aThread->AcqSLock(); |
|
579 if (aThread->i_NThread_Initial) |
|
580 ss = &TheSubSchedulers[aThread->iLastCpu]; |
|
581 else if (aThread->iReady && aThread->iParent->iReady) |
|
582 ss = &TheSubSchedulers[aThread->iParent->iReady & NSchedulable::EReadyCpuMask]; |
|
583 if (ss) |
|
584 ss->iReadyListLock.LockOnly(); |
|
585 TUint64 t = aThread->iTotalCpuTime64; |
|
586 if (aThread->iCurrent || (aThread->i_NThread_Initial && !ss->iCurrentThread)) |
|
587 t += (NKern::Timestamp() - ss->iLastTimestamp64); |
|
588 if (ss) |
|
589 ss->iReadyListLock.UnlockOnly(); |
|
590 aThread->RelSLock(); |
|
591 NKern::Unlock(); |
|
592 return t; |
|
593 } |
|
594 |
574 extern "C" void __fastcall add_dfc(TDfc* aDfc) |
595 extern "C" void __fastcall add_dfc(TDfc* aDfc) |
575 { |
596 { |
576 aDfc->Add(); |
597 aDfc->Add(); |
577 } |
598 } |
578 |
599 |
580 TInt NKern::QueueUserModeCallback(NThreadBase* aThread, TUserModeCallback* aCallback) |
601 TInt NKern::QueueUserModeCallback(NThreadBase* aThread, TUserModeCallback* aCallback) |
581 { |
602 { |
582 __e32_memory_barrier(); |
603 __e32_memory_barrier(); |
583 if (aCallback->iNext != KUserModeCallbackUnqueued) |
604 if (aCallback->iNext != KUserModeCallbackUnqueued) |
584 return KErrInUse; |
605 return KErrInUse; |
585 if (aThread->i_NThread_Initial) |
|
586 return KErrArgument; |
|
587 TInt result = KErrDied; |
606 TInt result = KErrDied; |
588 NKern::Lock(); |
607 NKern::Lock(); |
589 TUserModeCallback* listHead = aThread->iUserModeCallbacks; |
608 TUserModeCallback* listHead = aThread->iUserModeCallbacks; |
590 do { |
609 do { |
591 if (TLinAddr(listHead) & 3) |
610 if (TLinAddr(listHead) & 3) |