kernel/eka/nkernsmp/nkerns.cpp
changeset 0 a41df078684a
child 90 947f0dc9f7a8
child 256 c1f20ce4abcf
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 2005-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".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // e32\nkernsmp\nkerns.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 // NThreadBase member data
       
    19 #define __INCLUDE_NTHREADBASE_DEFINES__
       
    20 
       
    21 #include <e32cmn.h>
       
    22 #include <e32cmn_private.h>
       
    23 #include "nk_priv.h"
       
    24 
       
    25 extern "C" void ExcFault(TAny*);
       
    26 
       
    27 /******************************************************************************
       
    28  * Fast mutex
       
    29  ******************************************************************************/
       
    30 /** Create a fast mutex
       
    31 
       
    32 	@publishedPartner
       
    33 	@released
       
    34 */
       
    35 EXPORT_C NFastMutex::NFastMutex()
       
    36 	: iHoldingThread(0), iMutexLock(TSpinLock::EOrderFastMutex)
       
    37 	{
       
    38 	}
       
    39 
       
    40 /******************************************************************************
       
    41  * NSchedulable
       
    42  ******************************************************************************/
       
    43 NSchedulable::NSchedulable()
       
    44 	:	iSSpinLock(TSpinLock::EOrderThread)
       
    45 	{
       
    46 	iPriority = 0;
       
    47 	iReady = 0;
       
    48 	iCurrent = 0;
       
    49 	iLastCpu = 0;
       
    50 	iNSchedulableSpare1 = 0;
       
    51 	iPauseCount = 0;
       
    52 	iSuspended = 0;
       
    53 	iNSchedulableSpare2 = 0;
       
    54 	iCpuChange = 0;
       
    55 	iStopping = 0;
       
    56 	iFreezeCpu = 0;
       
    57 	iParent = (NSchedulable*)0xdeadbeef;
       
    58 	iCpuAffinity = 0;
       
    59 	new (i_IDfcMem) TDfc(&DeferredReadyIDfcFn, this);
       
    60 	iEventState = 0;
       
    61 	iTotalCpuTime64 = 0;
       
    62 	}
       
    63 
       
    64 /******************************************************************************
       
    65  * NThreadGroup
       
    66  ******************************************************************************/
       
    67 NThreadGroup::NThreadGroup()
       
    68 	{
       
    69 	iParent = 0;
       
    70 	iThreadCount = 0;
       
    71 	new (&iSSpinLock) TSpinLock(TSpinLock::EOrderThreadGroup);
       
    72 	}
       
    73 
       
    74 /** Create a thread group
       
    75 
       
    76 	@publishedPartner
       
    77 	@prototype
       
    78 */
       
    79 EXPORT_C TInt NKern::GroupCreate(NThreadGroup* aGroup, SNThreadGroupCreateInfo& aInfo)
       
    80 	{
       
    81 	new (aGroup) NThreadGroup();
       
    82 	aGroup->iCpuAffinity = aInfo.iCpuAffinity;
       
    83 	return KErrNone;
       
    84 	}
       
    85 
       
    86 
       
    87 /** Destroy a thread group
       
    88 
       
    89 	@pre Call in thread context, interrupts enabled, preemption enabled
       
    90 	@pre No fast mutex held
       
    91 	@pre Calling thread in critical section
       
    92 	@pre All threads have left the group
       
    93 
       
    94 	@publishedPartner
       
    95 	@prototype
       
    96 */
       
    97 EXPORT_C void NKern::GroupDestroy(NThreadGroup* aGroup)
       
    98 	{
       
    99 	NKern::ThreadEnterCS();
       
   100 	aGroup->DetachTiedEvents();
       
   101 	NKern::ThreadLeaveCS();
       
   102 	}
       
   103 
       
   104 
       
   105 /******************************************************************************
       
   106  * Thread
       
   107  ******************************************************************************/
       
   108 void InvalidExec()
       
   109 	{
       
   110 	FAULT();
       
   111 	}
       
   112 
       
   113 static const SFastExecTable DefaultFastExecTable={0,{0}};
       
   114 static const SSlowExecTable DefaultSlowExecTable={0,(TLinAddr)InvalidExec,0,{{0,0}}};
       
   115 
       
   116 const SNThreadHandlers NThread_Default_Handlers =
       
   117 	{
       
   118 	NTHREAD_DEFAULT_EXIT_HANDLER,
       
   119 	NTHREAD_DEFAULT_STATE_HANDLER,
       
   120 	NTHREAD_DEFAULT_EXCEPTION_HANDLER,
       
   121 	NTHREAD_DEFAULT_TIMEOUT_HANDLER
       
   122 	};
       
   123 
       
   124 NThreadWaitState::NThreadWaitState()
       
   125 	:	iTimer(&TimerExpired, this)
       
   126 	{
       
   127 	iWtSt64 = 0;
       
   128 	iTimer.iTriggerTime = 0;
       
   129 	iTimer.iNTimerSpare1 = 0;
       
   130 	}
       
   131 
       
   132 NThreadBase::NThreadBase()
       
   133 	:	iRequestSemaphore(), iWaitState()
       
   134 	{
       
   135 	iParent = this;
       
   136 	iWaitLink.iPriority = 0;
       
   137 	iBasePri = 0;
       
   138 	iMutexPri = 0;
       
   139 	i_NThread_Initial = 0;
       
   140 	iLinkedObjType = EWaitNone;
       
   141 	i_ThrdAttr = 0;
       
   142 	iNThreadBaseSpare10 = 0;
       
   143 	iFastMutexDefer = 0;
       
   144 	iRequestSemaphore.iOwningThread = (NThreadBase*)this;
       
   145 	iTime = 0;
       
   146 	iTimeslice = 0;
       
   147 	iSavedSP = 0;
       
   148 	iAddressSpace = 0;
       
   149 	iHeldFastMutex = 0;
       
   150 	iUserModeCallbacks = 0;
       
   151 	iLinkedObj = 0;
       
   152 	iNewParent = 0;
       
   153 	iFastExecTable = 0;
       
   154 	iSlowExecTable = 0;
       
   155 	iCsCount = 0;
       
   156 	iCsFunction = 0;
       
   157 	iHandlers = 0;
       
   158 	iSuspendCount = 0;
       
   159 	iStackBase = 0;
       
   160 	iStackSize = 0;
       
   161 	iExtraContext = 0;
       
   162 	iExtraContextSize = 0;
       
   163 	iNThreadBaseSpare6 = 0;
       
   164 	iNThreadBaseSpare7 = 0;
       
   165 	iNThreadBaseSpare8 = 0;
       
   166 	iNThreadBaseSpare9 = 0;
       
   167 
       
   168 	// KILL
       
   169 	iTag = 0;
       
   170 	iVemsData = 0;
       
   171 	}
       
   172 
       
   173 TInt NThreadBase::Create(SNThreadCreateInfo& aInfo, TBool aInitial)
       
   174 	{
       
   175 	__KTRACE_OPT(KNKERN,DEBUGPRINT(">NThreadBase::Create %08x(%08x,%d)", this, &aInfo, aInitial));
       
   176 	if (aInfo.iPriority<0 || aInfo.iPriority>63)
       
   177 		return KErrArgument;
       
   178 	if (aInfo.iPriority==0 && !aInitial)
       
   179 		return KErrArgument;
       
   180 //	if (aInfo.iCpu!=KCpuAny && aInfo.iCpu>=TheScheduler.iNumCpus)
       
   181 //		return KErrArgument;
       
   182 	iStackBase=(TLinAddr)aInfo.iStackBase;
       
   183 	iStackSize=aInfo.iStackSize;
       
   184 	iTimeslice=(aInfo.iTimeslice>0)?aInfo.iTimeslice:-1;
       
   185 	iTime=iTimeslice;
       
   186 	iPriority=TUint8(aInfo.iPriority);
       
   187 	iBasePri=TUint8(aInfo.iPriority);
       
   188 	iCpuAffinity = aInfo.iCpuAffinity;
       
   189 	iHandlers = aInfo.iHandlers ? aInfo.iHandlers : &NThread_Default_Handlers;
       
   190 	iFastExecTable=aInfo.iFastExecTable?aInfo.iFastExecTable:&DefaultFastExecTable;
       
   191 	iSlowExecTable=(aInfo.iSlowExecTable?aInfo.iSlowExecTable:&DefaultSlowExecTable)->iEntries;
       
   192 	i_ThrdAttr=(TUint8)aInfo.iAttributes;
       
   193 	if (aInitial)
       
   194 		{
       
   195 		TSubScheduler& ss = SubScheduler();
       
   196 		iLastCpu = (TUint8)ss.iCpuNum;
       
   197 		iReady = (TUint8)(iLastCpu | EReadyOffset);
       
   198 		iCurrent = iReady;
       
   199 		iCpuAffinity = iLastCpu;
       
   200 		iEventState = (iLastCpu<<EEventCpuShift) | (iLastCpu<<EThreadCpuShift);
       
   201 		ss.Add(this);
       
   202 		i_NThread_Initial = TRUE;
       
   203 		ss.iInitialThread = (NThread*)this;
       
   204 		NKern::Unlock();		// now that current thread is defined
       
   205 		}
       
   206 	else
       
   207 		{
       
   208 		iSuspendCount = 1;
       
   209 		iSuspended = 1;
       
   210 		TInt ecpu;
       
   211 		if (iCpuAffinity & NTHREADBASE_CPU_AFFINITY_MASK)
       
   212 			{
       
   213 			ecpu = __e32_find_ls1_32(iCpuAffinity);
       
   214 			if (ecpu >= TheScheduler.iNumCpus)
       
   215 				ecpu = 0;	// FIXME: Inactive CPU?
       
   216 			}
       
   217 		else
       
   218 			ecpu = iCpuAffinity;
       
   219 		iEventState = (ecpu<<EEventCpuShift) | (ecpu<<EThreadCpuShift);
       
   220 		if (aInfo.iGroup)
       
   221 			{
       
   222 			NKern::Lock();
       
   223 			AcqSLock();
       
   224 			aInfo.iGroup->AcqSLock();
       
   225 			iParent = (NSchedulable*)aInfo.iGroup;
       
   226 			++aInfo.iGroup->iThreadCount;
       
   227 			iEventState |= EEventParent;
       
   228 			RelSLock();
       
   229 			NKern::Unlock();
       
   230 			}
       
   231 		}
       
   232 	__KTRACE_OPT(KNKERN,DEBUGPRINT("<NThreadBase::Create OK"));
       
   233 	return KErrNone;
       
   234 	}
       
   235 
       
   236 void NThread_Default_State_Handler(NThread* __DEBUG_ONLY(aThread), TInt __DEBUG_ONLY(aOperation), TInt __DEBUG_ONLY(aParameter))
       
   237 	{
       
   238 //	__KTRACE_OPT(KPANIC,DEBUGPRINT("Unknown NState %d: thread %T op %08x par %08x",aThread,aThread->iNState,aOperation,aParameter));
       
   239 #ifdef _DEBUG
       
   240 	DEBUGPRINT("UnknownState: thread %T op %08x par %08x",aThread,aOperation,aParameter);
       
   241 #endif
       
   242 	FAULT();
       
   243 	}
       
   244 
       
   245 void NThread_Default_Exception_Handler(TAny* aContext, NThread*)
       
   246 	{
       
   247 	ExcFault(aContext);
       
   248 	}
       
   249 
       
   250 
       
   251 /** Create a nanothread.
       
   252 
       
   253 	This function is intended to be used by the EPOC kernel and by personality
       
   254 	layers. A nanothread may not use most of the functions available to normal
       
   255 	Symbian OS threads. Use Kern::ThreadCreate() to create a Symbian OS thread.
       
   256 
       
   257 	@param aThread Pointer to control block for thread to create.
       
   258 	@param aInfo Information needed for creating the thread.
       
   259 
       
   260 	@see SNThreadCreateInfo
       
   261 	@see Kern::ThreadCreate
       
   262 
       
   263 	@pre	Call in a thread context.
       
   264 	@pre	Interrupts must be enabled.
       
   265 	@pre	Kernel must be unlocked.
       
   266  */
       
   267 EXPORT_C TInt NKern::ThreadCreate(NThread* aThread, SNThreadCreateInfo& aInfo)
       
   268 	{
       
   269 	CHECK_PRECONDITIONS(MASK_KERNEL_UNLOCKED|MASK_INTERRUPTS_ENABLED|MASK_NOT_ISR|MASK_NOT_IDFC,"NKern::ThreadCreate");
       
   270 	return aThread->Create(aInfo,FALSE);
       
   271 	}
       
   272 
       
   273 // User-mode callbacks
       
   274 
       
   275 TUserModeCallback::TUserModeCallback(TUserModeCallbackFunc aFunc)
       
   276 	:	iNext(KUserModeCallbackUnqueued),
       
   277 		iFunc(aFunc)
       
   278 	{
       
   279 	}
       
   280 
       
   281 TUserModeCallback::~TUserModeCallback()
       
   282 	{
       
   283 	__NK_ASSERT_DEBUG(iNext == KUserModeCallbackUnqueued);
       
   284 	}
       
   285 
       
   286 void NKern::CancelUserModeCallbacks()
       
   287 	{
       
   288 	// Call any queued callbacks with the EUserModeCallbackCancel reason code, in the current
       
   289 	// thread.
       
   290 
       
   291 	TUserModeCallback* listHead =
       
   292 		(TUserModeCallback*)__e32_atomic_swp_ord_ptr(&NCurrentThread()->iUserModeCallbacks, NULL);
       
   293 	while (listHead)
       
   294 		{
       
   295 		TUserModeCallback* callback = listHead;
       
   296 		listHead = listHead->iNext;
       
   297 		callback->iNext = KUserModeCallbackUnqueued;
       
   298 		__e32_memory_barrier();
       
   299 		callback->iFunc(callback, EUserModeCallbackCancel);
       
   300 		}
       
   301 	}
       
   302 
       
   303 void NKern::MoveUserModeCallbacks(NThreadBase* aDestThread, NThreadBase* aSrcThread)
       
   304 	{
       
   305 	// Move all queued user-mode callbacks from the source thread to the destination thread, and
       
   306 	// prevent any more from being queued.  Used by the kernel thread code so that callbacks get
       
   307 	// cancelled in another thread if the thread they were originally queued on dies.
       
   308 
       
   309 	// Atomically remove list of callbacks and set pointer to 1
       
   310 	// The latter ensures any subsequent attempts to add callbacks fail
       
   311 	TUserModeCallback* sourceListStart =
       
   312 		(TUserModeCallback*)__e32_atomic_swp_ord_ptr(&aSrcThread->iUserModeCallbacks, (TAny*)1);
       
   313 	__NK_ASSERT_DEBUG(((TUint)sourceListStart & 3) == 0);  // check this only gets called once per thread
       
   314 
       
   315 	if (sourceListStart == NULL)
       
   316 		return;
       
   317 	
       
   318 	TUserModeCallback* sourceListEnd = sourceListStart;
       
   319 	while (sourceListEnd->iNext != NULL)
       
   320 		sourceListEnd = sourceListEnd->iNext;
       
   321 	
       
   322 	NKern::Lock();
       
   323 	TUserModeCallback* destListStart = aDestThread->iUserModeCallbacks;
       
   324 	do
       
   325 		{
       
   326 		__NK_ASSERT_DEBUG(((TUint)destListStart & 3) == 0);  // dest thread must not die
       
   327 		sourceListEnd->iNext = destListStart;
       
   328 		} while (!__e32_atomic_cas_ord_ptr(&aDestThread->iUserModeCallbacks, &destListStart, sourceListStart));
       
   329 	NKern::Unlock();
       
   330 	}
       
   331 
       
   332 /** Initialise the null thread
       
   333 	@internalComponent
       
   334 */
       
   335 void NKern::Init(NThread* aThread, SNThreadCreateInfo& aInfo)
       
   336 	{
       
   337 	aInfo.iFunction=NULL;			// irrelevant
       
   338 	aInfo.iPriority=0;				// null thread has lowest priority
       
   339 	aInfo.iTimeslice=0;				// null thread not timesliced
       
   340 	aInfo.iAttributes=0;			// null thread does not require implicit locks
       
   341 	aThread->Create(aInfo,TRUE);	// create the null thread
       
   342 	}
       
   343 
       
   344 /** @internalTechnology */
       
   345 EXPORT_C void NKern::RecordIntLatency(TInt /*aLatency*/, TInt /*aIntMask*/)
       
   346 	{
       
   347 	}
       
   348 
       
   349 
       
   350 /** @internalTechnology */
       
   351 EXPORT_C void NKern::RecordThreadLatency(TInt /*aLatency*/)
       
   352 	{
       
   353 	}
       
   354 
       
   355 /********************************************
       
   356  * Deterministic Priority List Implementation
       
   357  ********************************************/
       
   358 
       
   359 
       
   360 /** Construct a priority list with the specified number of priorities
       
   361 
       
   362 	@param aNumPriorities The number of priorities (must be 1-64).
       
   363  */
       
   364 EXPORT_C TPriListBase::TPriListBase(TInt aNumPriorities)
       
   365 	{
       
   366 	memclr(this, sizeof(TPriListBase)+(aNumPriorities-1)*sizeof(SDblQueLink*) );
       
   367 	}
       
   368 
       
   369 
       
   370 /********************************************
       
   371  * Miscellaneous
       
   372  ********************************************/
       
   373 
       
   374 /** Get the current value of the high performance counter.
       
   375 
       
   376     If a high performance counter is not available, this uses the millisecond
       
   377     tick count instead.
       
   378 */
       
   379 EXPORT_C TUint32 NKern::FastCounter()
       
   380 	{
       
   381 	return (TUint32)Timestamp();
       
   382 	}
       
   383 
       
   384 
       
   385 /** Get the frequency of counter queried by NKern::FastCounter().
       
   386 */
       
   387 EXPORT_C TInt NKern::FastCounterFrequency()
       
   388 	{
       
   389 	return (TInt)TimestampFrequency();
       
   390 	}
       
   391 
       
   392 
       
   393 extern "C" {
       
   394 TUint32 CrashState;
       
   395 }
       
   396 
       
   397 EXPORT_C TBool NKern::Crashed()
       
   398 	{
       
   399 	return CrashState!=0;
       
   400 	}
       
   401 
       
   402 
       
   403 /**	Returns number of nanokernel timer ticks since system started.
       
   404 	@return tick count
       
   405 	@pre any context
       
   406  */
       
   407 EXPORT_C TUint32 NKern::TickCount()
       
   408 	{
       
   409 	return NTickCount();
       
   410 	}
       
   411 
       
   412 
       
   413 TUint32 BTrace::BigTraceId = 0;
       
   414 
       
   415 TBool BTrace::DoOutBig(TUint32 a0, TUint32 a1, const TAny* aData, TInt aDataSize, TUint32 aContext, TUint32 aPc)
       
   416 	{
       
   417 	SBTraceData& traceData = BTraceData;
       
   418 
       
   419 	// see if trace is small enough to fit in single record...
       
   420 	if(TUint(aDataSize)<=TUint(KMaxBTraceDataArray+4))
       
   421 		{
       
   422 		a0 += aDataSize;
       
   423 		TUint32 a2 = 0;
       
   424 		TUint32 a3 = 0;
       
   425 		if(aDataSize)
       
   426 			{
       
   427 			a2 = *((TUint32*&)aData)++; // first 4 bytes into a2
       
   428 			if(aDataSize>=4 && aDataSize<=8)
       
   429 				a3 = *(TUint32*)aData; // only 4 more bytes, so pass by value, not pointer
       
   430 			else
       
   431 				a3 = (TUint32)aData;
       
   432 			}
       
   433 		__ACQUIRE_BTRACE_LOCK();
       
   434 		TBool r = traceData.iHandler(a0,0,aContext,a1,a2,a3,0,aPc);
       
   435 		__RELEASE_BTRACE_LOCK();
       
   436 		return r;
       
   437 		}
       
   438 
       
   439 	// adjust for header2, extra, and size word...
       
   440 	a0 |= BTrace::EHeader2Present<<(BTrace::EFlagsIndex*8)|BTrace::EExtraPresent<<(BTrace::EFlagsIndex*8);
       
   441 	a0 += 12;
       
   442 
       
   443 	TUint32 traceId = __e32_atomic_add_ord32(&BigTraceId, 1);
       
   444 	TUint32 header2 = BTrace::EMultipartFirst;
       
   445 	TInt offset = 0;
       
   446 	do
       
   447 		{
       
   448 		TUint32 size = aDataSize-offset;
       
   449 		if(size>KMaxBTraceDataArray)
       
   450 			size = KMaxBTraceDataArray;
       
   451 		else
       
   452 			header2 = BTrace::EMultipartLast;
       
   453 		if(size<=4)
       
   454 			*(TUint32*)&aData = *(TUint32*)aData; // 4 bytes or less are passed by value, not pointer
       
   455 
       
   456 		__ACQUIRE_BTRACE_LOCK();
       
   457 		TBool result = traceData.iHandler(a0+size,header2,aContext,aDataSize,a1,(TUint32)aData,traceId,aPc);
       
   458 		__RELEASE_BTRACE_LOCK();
       
   459 		if (!result)
       
   460 			return result;
       
   461 
       
   462 		offset += size;
       
   463 		*(TUint8**)&aData += size;
       
   464 
       
   465 		header2 = BTrace::EMultipartMiddle;
       
   466 		a1 = offset;
       
   467 		}
       
   468 	while(offset<aDataSize);
       
   469 
       
   470 	return TRUE;
       
   471 	}
       
   472 
       
   473 EXPORT_C TSpinLock* BTrace::LockPtr()
       
   474 	{
       
   475 #ifdef __USE_BTRACE_LOCK__
       
   476 	return &BTraceLock;
       
   477 #else
       
   478 	return 0;
       
   479 #endif
       
   480 	}