kernel/eka/nkernsmp/x86/ncthrd.cpp
changeset 90 947f0dc9f7a8
parent 0 a41df078684a
child 257 3e88ff8f41d5
equal deleted inserted replaced
52:2d65c2f76d7b 90:947f0dc9f7a8
    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 InitAPTimestamp(SNThreadCreateInfo& aInfo);
    39 extern void InitTimestamp(TSubScheduler* aSS, 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;
    47 	if (aInitial)
    48 	if (aInitial)
    48 		{
    49 		{
    49 		cpu = __e32_atomic_add_ord32(&TheScheduler.iNumCpus, 1);
    50 		cpu = __e32_atomic_add_ord32(&TheScheduler.iNumCpus, 1);
    50 		if (cpu==0)
    51 		if (cpu==0)
    51 			memset(SubSchedulerLookupTable, 0x9a, sizeof(SubSchedulerLookupTable));
    52 			memset(SubSchedulerLookupTable, 0x9a, sizeof(SubSchedulerLookupTable));
    52 		aInfo.iCpuAffinity = cpu;
    53 		aInfo.iCpuAffinity = cpu;
    53 		// OK since we can't migrate yet
    54 		// OK since we can't migrate yet
    54 		TUint32 apicid = *(volatile TUint32*)(X86_LOCAL_APIC_BASE + X86_LOCAL_APIC_OFFSET_ID) >> 24;
    55 		TUint32 apicid = *(volatile TUint32*)(X86_LOCAL_APIC_BASE + X86_LOCAL_APIC_OFFSET_ID) >> 24;
    55 		TSubScheduler& ss = TheSubSchedulers[cpu];
    56 		ss = &TheSubSchedulers[cpu];
    56 		ss.i_APICID = (TAny*)(apicid<<24);
    57 		ss->iSSX.iAPICID = apicid << 24;
    57 		ss.iCurrentThread = this;
    58 		ss->iCurrentThread = this;
    58 		SubSchedulerLookupTable[apicid] = &ss;
    59 		ss->iDeferShutdown = 0;
    59 		ss.iLastTimestamp64 = NKern::Timestamp();
    60 		SubSchedulerLookupTable[apicid] = ss;
    60 		iRunCount64 = UI64LIT(1);
    61 		iRunCount.i64 = UI64LIT(1);
    61 		__KTRACE_OPT(KBOOT,DEBUGPRINT("Init: cpu=%d APICID=%08x ss=%08x", cpu, apicid, &ss));
    62 		iActiveState = 1;
       
    63 		__KTRACE_OPT(KBOOT,DEBUGPRINT("Init: cpu=%d APICID=%08x ss=%08x", cpu, apicid, ss));
    62 		if (cpu)
    64 		if (cpu)
    63 			{
    65 			{
    64 			__ltr(TSS_SELECTOR(cpu));
    66 			__ltr(TSS_SELECTOR(cpu));
    65 			NIrq::HwInit2AP();
    67 			NIrq::HwInit2AP();
    66 			__e32_atomic_ior_ord32(&TheScheduler.iActiveCpus1, 1<<cpu);
    68 			__e32_atomic_ior_ord32(&TheScheduler.iThreadAcceptCpus, 1<<cpu);
    67 			__e32_atomic_ior_ord32(&TheScheduler.iActiveCpus2, 1<<cpu);
    69 			__e32_atomic_ior_ord32(&TheScheduler.iIpiAcceptCpus, 1<<cpu);
    68 			__e32_atomic_ior_ord32(&TheScheduler.iCpusNotIdle, 1<<cpu);
    70 			__e32_atomic_ior_ord32(&TheScheduler.iCpusNotIdle, 1<<cpu);
       
    71 			__e32_atomic_add_ord32(&TheScheduler.iCCRequestLevel, 1);
    69 			__KTRACE_OPT(KBOOT,DEBUGPRINT("AP TR=%x",__tr()));
    72 			__KTRACE_OPT(KBOOT,DEBUGPRINT("AP TR=%x",__tr()));
    70 			}
    73 			}
    71 		}
    74 		}
    72 	TInt r=NThreadBase::Create(aInfo,aInitial);
    75 	TInt r=NThreadBase::Create(aInfo,aInitial);
    73 	if (r!=KErrNone)
    76 	if (r!=KErrNone)
   122 		}
   125 		}
   123 	else
   126 	else
   124 		{
   127 		{
   125 		NKern::EnableAllInterrupts();
   128 		NKern::EnableAllInterrupts();
   126 
   129 
   127 		// synchronize AP's timestamp with BP's
   130 		// Initialise timestamp
   128 		if (cpu>0)
   131 		InitTimestamp(ss, aInfo);
   129 			InitAPTimestamp(aInfo);
   132 		}
   130 		}
   133 	AddToEnumerateList();
       
   134 	InitLbInfo();
   131 #ifdef BTRACE_THREAD_IDENTIFICATION
   135 #ifdef BTRACE_THREAD_IDENTIFICATION
   132 	BTrace4(BTrace::EThreadIdentification,BTrace::ENanoThreadCreate,this);
   136 	BTrace4(BTrace::EThreadIdentification,BTrace::ENanoThreadCreate,this);
   133 #endif
   137 #endif
   134 	return KErrNone;
   138 	return KErrNone;
   135 	}
   139 	}
   147 		}
   151 		}
   148 	TScheduler& s = TheScheduler;
   152 	TScheduler& s = TheScheduler;
   149 	TInt irq = NKern::DisableAllInterrupts();
   153 	TInt irq = NKern::DisableAllInterrupts();
   150 	TSubScheduler& ss = SubScheduler();
   154 	TSubScheduler& ss = SubScheduler();
   151 	NThreadBase* ct = ss.iCurrentThread;
   155 	NThreadBase* ct = ss.iCurrentThread;
   152 	TInt inc = TInt(ss.i_IrqNestCount);
   156 	TInt inc = TInt(ss.iSSX.iIrqNestCount);
   153 	TInt cpu = ss.iCpuNum;
   157 	TInt cpu = ss.iCpuNum;
   154 	NKern::RestoreInterrupts(irq);
   158 	NKern::RestoreInterrupts(irq);
   155 	DEBUGPRINT("Thread %T, CPU %d, KLCount=%08x, IrqNest=%d",ct,cpu,ss.iKernLockCount,inc);
   159 	DEBUGPRINT("Thread %T, CPU %d, KLCount=%08x, IrqNest=%d",ct,cpu,ss.iKernLockCount,inc);
   156 	}
   160 	}
   157 
   161 
   226 	NThread* pC = NCurrentThreadL();
   230 	NThread* pC = NCurrentThreadL();
   227 	TSubScheduler* ss = 0;
   231 	TSubScheduler* ss = 0;
   228 	if (pC != this)
   232 	if (pC != this)
   229 		{
   233 		{
   230 		AcqSLock();
   234 		AcqSLock();
   231 		if (iWaitState.ThreadIsDead())
   235 		if (iWaitState.ThreadIsDead() || i_NThread_Initial)
   232 			{
   236 			{
   233 			RelSLock();
   237 			RelSLock();
   234 			aAvailRegistersMask = 0;
   238 			aAvailRegistersMask = 0;
   235 			return;
   239 			return;
   236 			}
   240 			}
   277 void TGetContextIPI::Isr(TGenericIPI* aPtr)
   281 void TGetContextIPI::Isr(TGenericIPI* aPtr)
   278 	{
   282 	{
   279 	TGetContextIPI& ipi = *(TGetContextIPI*)aPtr;
   283 	TGetContextIPI& ipi = *(TGetContextIPI*)aPtr;
   280 	TX86RegSet& a = *ipi.iContext;
   284 	TX86RegSet& a = *ipi.iContext;
   281 	TSubScheduler& ss = SubScheduler();
   285 	TSubScheduler& ss = SubScheduler();
   282 	TUint32* irqstack = (TUint32*)ss.i_IrqStackTop;
   286 	TUint32* irqstack = (TUint32*)ss.iSSX.iIrqStackTop;
   283 	SThreadExcStack* txs = (SThreadExcStack*)irqstack[-1];	// first word pushed on IRQ stack points to thread supervisor stack
   287 	SThreadExcStack* txs = (SThreadExcStack*)irqstack[-1];	// first word pushed on IRQ stack points to thread supervisor stack
   284 	GetContextAfterExc(a, txs, *ipi.iAvailRegsMask, TRUE);
   288 	GetContextAfterExc(a, txs, *ipi.iAvailRegsMask, TRUE);
   285 	}
   289 	}
   286 
   290 
   287 void TGetContextIPI::Get(TInt aCpu, TX86RegSet& aContext, TUint32& aAvailRegsMask)
   291 void TGetContextIPI::Get(TInt aCpu, TX86RegSet& aContext, TUint32& aAvailRegsMask)
   388 	NThread* pC = NCurrentThreadL();
   392 	NThread* pC = NCurrentThreadL();
   389 	TSubScheduler* ss = 0;
   393 	TSubScheduler* ss = 0;
   390 	if (pC != this)
   394 	if (pC != this)
   391 		{
   395 		{
   392 		AcqSLock();
   396 		AcqSLock();
   393 		if (iWaitState.ThreadIsDead())
   397 		if (iWaitState.ThreadIsDead() || i_NThread_Initial)
   394 			{
   398 			{
   395 			RelSLock();
   399 			RelSLock();
   396 			aRegMask = 0;
   400 			aRegMask = 0;
   397 			return;
   401 			return;
   398 			}
   402 			}
   565 	aThread->SetUserContext(a, mask);
   569 	aThread->SetUserContext(a, mask);
   566 	NKern::Unlock();
   570 	NKern::Unlock();
   567 	}
   571 	}
   568 
   572 
   569 
   573 
   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 
       
   595 extern "C" void __fastcall add_dfc(TDfc* aDfc)
   574 extern "C" void __fastcall add_dfc(TDfc* aDfc)
   596 	{
   575 	{
   597 	aDfc->Add();
   576 	aDfc->Add();
   598 	}
   577 	}
   599 
   578 
   601 TInt NKern::QueueUserModeCallback(NThreadBase* aThread, TUserModeCallback* aCallback)
   580 TInt NKern::QueueUserModeCallback(NThreadBase* aThread, TUserModeCallback* aCallback)
   602 	{
   581 	{
   603 	__e32_memory_barrier();
   582 	__e32_memory_barrier();
   604 	if (aCallback->iNext != KUserModeCallbackUnqueued)
   583 	if (aCallback->iNext != KUserModeCallbackUnqueued)
   605 		return KErrInUse;
   584 		return KErrInUse;
       
   585 	if (aThread->i_NThread_Initial)
       
   586 		return KErrArgument;
   606 	TInt result = KErrDied;
   587 	TInt result = KErrDied;
   607 	NKern::Lock();
   588 	NKern::Lock();
   608 	TUserModeCallback* listHead = aThread->iUserModeCallbacks;
   589 	TUserModeCallback* listHead = aThread->iUserModeCallbacks;
   609 	do	{
   590 	do	{
   610 		if (TLinAddr(listHead) & 3)
   591 		if (TLinAddr(listHead) & 3)