os/kernelhwsrv/kernel/eka/nkern/nkern.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     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".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // e32\nkern\nkern.cpp
    15 // 
    16 //
    17 
    18 // NThreadBase member data
    19 #define __INCLUDE_NTHREADBASE_DEFINES__
    20 
    21 #include "nk_priv.h"
    22 
    23 /******************************************************************************
    24  * Fast mutex
    25  ******************************************************************************/
    26 
    27 /** Checks if the current thread holds this fast mutex
    28 
    29 	@return TRUE if the current thread holds this fast mutex
    30 	@return FALSE if not
    31 */
    32 EXPORT_C TBool NFastMutex::HeldByCurrentThread()
    33 	{
    34 	return iHoldingThread == NCurrentThread();
    35 	}
    36 
    37 /** Find the fast mutex held by the current thread
    38 
    39 	@return a pointer to the fast mutex held by the current thread
    40 	@return NULL if the current thread does not hold a fast mutex
    41 */
    42 EXPORT_C NFastMutex* NKern::HeldFastMutex()
    43 	{
    44 	return TheScheduler.iCurrentThread->iHeldFastMutex;
    45 	}
    46 
    47 
    48 #ifndef __FAST_MUTEX_MACHINE_CODED__
    49 /** Acquires the fast mutex.
    50 
    51     This will block until the mutex is available, and causes
    52 	the thread to enter an implicit critical section until the mutex is released.
    53 
    54 	Generally threads would use NKern::FMWait() which manipulates the kernel lock
    55 	for you.
    56 	
    57 	@pre Kernel must be locked, with lock count 1.
    58 	@pre The calling thread holds no fast mutexes.
    59 	
    60 	@post Kernel is locked, with lock count 1.
    61 	@post The calling thread holds the mutex.
    62 	
    63 	@see NFastMutex::Signal()
    64 	@see NKern::FMWait()
    65 */
    66 EXPORT_C void NFastMutex::Wait()
    67 	{
    68 	__KTRACE_OPT(KNKERN,DEBUGPRINT("FMWait %M",this));
    69 	CHECK_PRECONDITIONS(MASK_KERNEL_LOCKED_ONCE|MASK_NO_FAST_MUTEX,"NFastMutex::Wait");			
    70 	NThreadBase* pC=TheScheduler.iCurrentThread;
    71 	if (iHoldingThread)
    72 		{
    73 		iWaiting=1;
    74 		pC->iWaitFastMutex=this;
    75 		__KTRACE_OPT(KNKERN,DEBUGPRINT("FMWait: YieldTo %T",iHoldingThread));
    76 		TheScheduler.YieldTo(iHoldingThread);	// returns with kernel unlocked, interrupts disabled
    77 		TheScheduler.iKernCSLocked = 1;	// relock kernel
    78 		NKern::EnableAllInterrupts();
    79 		pC->iWaitFastMutex=NULL;
    80 		}
    81 	pC->iHeldFastMutex=this;		// automatically puts thread into critical section
    82 #ifdef BTRACE_FAST_MUTEX
    83 	BTraceContext4(BTrace::EFastMutex,BTrace::EFastMutexWait,this);
    84 #endif
    85 	iHoldingThread=pC;
    86 	}
    87 
    88 
    89 /** Releases a previously acquired fast mutex.
    90 	
    91 	Generally, threads would use NKern::FMSignal() which manipulates the kernel lock
    92 	for you.
    93 	
    94 	@pre The calling thread holds the mutex.
    95 	@pre Kernel must be locked.
    96 	
    97 	@post Kernel is locked.
    98 	
    99 	@see NFastMutex::Wait()
   100 	@see NKern::FMSignal()
   101 */
   102 EXPORT_C void NFastMutex::Signal()
   103 	{
   104 	__KTRACE_OPT(KNKERN,DEBUGPRINT("FMSignal %M",this));
   105 	CHECK_PRECONDITIONS(MASK_KERNEL_LOCKED,"NFastMutex::Signal");			
   106 	NThreadBase* pC=TheScheduler.iCurrentThread;
   107 	__ASSERT_WITH_MESSAGE_DEBUG(pC->iHeldFastMutex==this,"The calling thread holds the mutex","NFastMutex::Signal");
   108 #ifdef BTRACE_FAST_MUTEX
   109 	BTraceContext4(BTrace::EFastMutex,BTrace::EFastMutexSignal,this);
   110 #endif
   111 	iHoldingThread=NULL;
   112 	pC->iHeldFastMutex=NULL;
   113 	TBool w=iWaiting;
   114 	iWaiting=0;
   115 	if (w)
   116 		{
   117 		RescheduleNeeded();
   118 		if (pC->iCsFunction && !pC->iCsCount)
   119 			pC->DoCsFunction();
   120 		}
   121 	}
   122 
   123 
   124 /** Acquires a fast mutex.
   125 
   126     This will block until the mutex is available, and causes
   127 	the thread to enter an implicit critical section until the mutex is released.
   128 
   129 	@param aMutex The fast mutex to acquire.
   130 	
   131 	@post The calling thread holds the mutex.
   132 	
   133 	@see NFastMutex::Wait()
   134 	@see NKern::FMSignal()
   135 
   136 	@pre No fast mutex can be held.
   137 	@pre Call in a thread context.
   138 	@pre Kernel must be unlocked
   139 	@pre interrupts enabled
   140 
   141 */
   142 EXPORT_C void NKern::FMWait(NFastMutex* aMutex)
   143 	{
   144 	CHECK_PRECONDITIONS(MASK_THREAD_STANDARD,"NKern::FMWait");
   145 	NKern::Lock();
   146 	aMutex->Wait();
   147 	NKern::Unlock();
   148 	}
   149 
   150 
   151 /** Releases a previously acquired fast mutex.
   152 	
   153 	@param aMutex The fast mutex to release.
   154 	
   155 	@pre The calling thread holds the mutex.
   156 	
   157 	@see NFastMutex::Signal()
   158 	@see NKern::FMWait()
   159 */
   160 EXPORT_C void NKern::FMSignal(NFastMutex* aMutex)
   161 	{
   162 	NKern::Lock();
   163 	aMutex->Signal();
   164 	NKern::Unlock();
   165 	}
   166 
   167 
   168 /** Acquires the System Lock.
   169 
   170     This will block until the mutex is available, and causes
   171 	the thread to enter an implicit critical section until the mutex is released.
   172 
   173 	@post System lock is held.
   174 
   175 	@see NKern::UnlockSystem()
   176 	@see NKern::FMWait()
   177 
   178 	@pre No fast mutex can be held.
   179 	@pre Call in a thread context.
   180 	@pre Kernel must be unlocked
   181 	@pre interrupts enabled
   182 */
   183 EXPORT_C void NKern::LockSystem()
   184 	{
   185 	CHECK_PRECONDITIONS(MASK_THREAD_STANDARD,"NKern::LockSystem");
   186 	NKern::Lock();
   187 	TheScheduler.iLock.Wait();
   188 	NKern::Unlock();
   189 	}
   190 
   191 
   192 /** Releases the System Lock.
   193 
   194 	@pre System lock must be held.
   195 
   196 	@see NKern::LockSystem()
   197 	@see NKern::FMSignal()
   198 */
   199 EXPORT_C void NKern::UnlockSystem()
   200 	{
   201 	NKern::Lock();
   202 	TheScheduler.iLock.Signal();
   203 	NKern::Unlock();
   204 	}
   205 
   206 
   207 /** Temporarily releases a fast mutex if there is contention.
   208 
   209     If there is another thread attempting to acquire the mutex, the calling
   210 	thread releases the mutex and then acquires it again.
   211 	
   212 	This is more efficient than the equivalent code:
   213 	
   214 	@code
   215 	NKern::FMSignal();
   216 	NKern::FMWait();
   217 	@endcode
   218 
   219 	@return	TRUE if the mutex was relinquished, FALSE if not.
   220 
   221 	@pre	The mutex must be held.
   222 
   223 	@post	The mutex is held.
   224 */
   225 EXPORT_C TBool NKern::FMFlash(NFastMutex* aM)
   226 	{
   227 	__ASSERT_WITH_MESSAGE_DEBUG(aM->HeldByCurrentThread(),"The calling thread holds the mutex","NKern::FMFlash");
   228 	TBool w = aM->iWaiting;
   229 	if (w)
   230 		{
   231 		NKern::Lock();
   232 		aM->Signal();
   233 		NKern::PreemptionPoint();
   234 		aM->Wait();
   235 		NKern::Unlock();
   236 		}
   237 #ifdef BTRACE_FAST_MUTEX
   238 	else
   239 		{
   240 		BTraceContext4(BTrace::EFastMutex,BTrace::EFastMutexFlash,aM);
   241 		}
   242 #endif
   243 	return w;
   244 	}
   245 
   246 
   247 /** Temporarily releases the System Lock if there is contention.
   248 
   249     If there
   250 	is another thread attempting to acquire the System lock, the calling
   251 	thread releases the mutex and then acquires it again.
   252 	
   253 	This is more efficient than the equivalent code:
   254 	
   255 	@code
   256 	NKern::UnlockSystem();
   257 	NKern::LockSystem();
   258 	@endcode
   259 
   260 	Note that this can only allow higher priority threads to use the System
   261 	lock as lower priority cannot cause contention on a fast mutex.
   262 
   263 	@return	TRUE if the system lock was relinquished, FALSE if not.
   264 
   265 	@pre	System lock must be held.
   266 
   267 	@post	System lock is held.
   268 
   269 	@see NKern::LockSystem()
   270 	@see NKern::UnlockSystem()
   271 */
   272 EXPORT_C TBool NKern::FlashSystem()
   273 	{
   274 	return NKern::FMFlash(&TheScheduler.iLock);
   275 	}
   276 #endif
   277 
   278 
   279 /******************************************************************************
   280  * Fast semaphore
   281  ******************************************************************************/
   282 
   283 /** Sets the owner of a fast semaphore.
   284 
   285 	@param aThread The thread to own this semaphore. If aThread==0, then the
   286 					owner is set to the current thread.
   287 
   288 	@pre Kernel must be locked.
   289 	@pre If changing ownership form one thread to another, the there must be no
   290 		 pending signals or waits.
   291 	@pre Call either in a thread or an IDFC context.
   292 	
   293 	@post Kernel is locked.
   294 */
   295 EXPORT_C void NFastSemaphore::SetOwner(NThreadBase* aThread)
   296 	{
   297 	CHECK_PRECONDITIONS(MASK_KERNEL_LOCKED|MASK_NOT_ISR,"NFastSemaphore::SetOwner");		
   298 	if(!aThread)
   299 		aThread = TheScheduler.iCurrentThread;
   300 	if(iOwningThread && iOwningThread!=aThread)
   301 		{
   302 		__NK_ASSERT_ALWAYS(!iCount);	// Can't change owner if iCount!=0
   303 		}
   304 	iOwningThread = aThread;
   305 	}
   306 
   307 
   308 #ifndef __FAST_SEM_MACHINE_CODED__
   309 /** Waits on a fast semaphore.
   310 
   311     Decrements the signal count for the semaphore and
   312 	removes the calling thread from the ready-list if the sempahore becomes
   313 	unsignalled. Only the thread that owns a fast semaphore can wait on it.
   314 	
   315 	Note that this function does not block, it merely updates the NThread state,
   316 	rescheduling will only occur when the kernel is unlocked. Generally threads
   317 	would use NKern::FSWait() which manipulates the kernel lock for you.
   318 
   319 	@pre The calling thread must own the semaphore.
   320 	@pre No fast mutex can be held.
   321 	@pre Kernel must be locked.
   322 	
   323 	@post Kernel is locked.
   324 	
   325 	@see NFastSemaphore::Signal()
   326 	@see NKern::FSWait()
   327 	@see NKern::Unlock()
   328  */
   329 EXPORT_C void NFastSemaphore::Wait()
   330 	{
   331 	CHECK_PRECONDITIONS(MASK_KERNEL_LOCKED|MASK_NO_FAST_MUTEX,"NFastSemaphore::Wait");		
   332 	NThreadBase* pC=TheScheduler.iCurrentThread;
   333 	__ASSERT_WITH_MESSAGE_ALWAYS(pC==iOwningThread,"The calling thread must own the semaphore","NFastSemaphore::Wait");
   334 	if (--iCount<0)
   335 		{
   336 		pC->iNState=NThread::EWaitFastSemaphore;
   337 		pC->iWaitObj=this;
   338 		TheScheduler.Remove(pC);
   339 		RescheduleNeeded();
   340 		}
   341 	}
   342 
   343 
   344 /** Signals a fast semaphore.
   345 
   346     Increments the signal count of a fast semaphore by
   347 	one and releases any waiting thread if the semphore becomes signalled.
   348 	
   349 	Note that a reschedule will not occur before this function returns, this will
   350 	only take place when the kernel is unlocked. Generally threads
   351 	would use NKern::FSSignal() which manipulates the kernel lock for you.
   352 	
   353 	@pre Kernel must be locked.
   354 	@pre Call either in a thread or an IDFC context.
   355 	
   356 	@post Kernel is locked.
   357 	
   358 	@see NFastSemaphore::Wait()
   359 	@see NKern::FSSignal()
   360 	@see NKern::Unlock()
   361  */
   362 EXPORT_C void NFastSemaphore::Signal()
   363 	{
   364 	CHECK_PRECONDITIONS(MASK_KERNEL_LOCKED|MASK_NOT_ISR,"NFastSemaphore::Signal");			
   365 	if (++iCount<=0)
   366 		{
   367 		iOwningThread->iWaitObj=NULL;
   368 		iOwningThread->CheckSuspendThenReady();
   369 		}
   370 	}
   371 
   372 
   373 /** Signals a fast semaphore multiple times.
   374 
   375 	@pre Kernel must be locked.
   376 	@pre Call either in a thread or an IDFC context.
   377 	
   378 	@post Kernel is locked.
   379 
   380 	@internalComponent	
   381  */
   382 EXPORT_C void NFastSemaphore::SignalN(TInt aCount)
   383 	{
   384 	CHECK_PRECONDITIONS(MASK_KERNEL_LOCKED|MASK_NOT_ISR,"NFastSemaphore::SignalN");			
   385 	__NK_ASSERT_DEBUG(aCount>=0);
   386 	if (aCount>0 && iCount<0)
   387 		{
   388 		iOwningThread->iWaitObj=NULL;
   389 		iOwningThread->CheckSuspendThenReady();
   390 		}
   391 	iCount+=aCount;
   392 	}
   393 
   394 
   395 /** Resets a fast semaphore.
   396 
   397 	@pre Kernel must be locked.
   398 	@pre Call either in a thread or an IDFC context.
   399 	
   400 	@post Kernel is locked.
   401 
   402 	@internalComponent	
   403  */
   404 EXPORT_C void NFastSemaphore::Reset()
   405 	{
   406 	CHECK_PRECONDITIONS(MASK_KERNEL_LOCKED|MASK_NOT_ISR,"NFastSemaphore::Reset");			
   407 	if (iCount<0)
   408 		{
   409 		iOwningThread->iWaitObj=NULL;
   410 		iOwningThread->CheckSuspendThenReady();
   411 		}
   412 	iCount=0;
   413 	}
   414 
   415 
   416 /** Cancels a wait on a fast semaphore.
   417 
   418 	@pre Kernel must be locked.
   419 	@pre Call either in a thread or an IDFC context.
   420 	
   421 	@post Kernel is locked.
   422 
   423 	@internalComponent	
   424  */
   425 void NFastSemaphore::WaitCancel()
   426 	{
   427 	CHECK_PRECONDITIONS(MASK_KERNEL_LOCKED|MASK_NOT_ISR,"NFastSemaphore::WaitCancel");			
   428 	iCount=0;
   429 	iOwningThread->iWaitObj=NULL;
   430 	iOwningThread->CheckSuspendThenReady();
   431 	}
   432 
   433 
   434 /** Waits for a signal on the current thread's I/O semaphore.
   435 
   436 	@pre No fast mutex can be held.
   437 	@pre Call in a thread context.
   438 	@pre Kernel must be unlocked
   439 	@pre interrupts enabled
   440  */
   441 EXPORT_C void NKern::WaitForAnyRequest()
   442 	{
   443 	CHECK_PRECONDITIONS(MASK_THREAD_STANDARD,"NKern::WaitForAnyRequest");
   444 	__KTRACE_OPT(KNKERN,DEBUGPRINT("WfAR"));
   445 	NThreadBase* pC=TheScheduler.iCurrentThread;
   446 	NKern::Lock();
   447 	pC->iRequestSemaphore.Wait();
   448 	NKern::Unlock();
   449 	}
   450 #endif
   451 
   452 
   453 /** Sets the owner of a fast semaphore.
   454 
   455 	@param aSem The semaphore to change ownership off.
   456 	@param aThread The thread to own this semaphore. If aThread==0, then the
   457 					owner is set to the current thread.
   458 
   459 	@pre If changing ownership form one thread to another, the there must be no
   460 		 pending signals or waits.
   461 */
   462 EXPORT_C void NKern::FSSetOwner(NFastSemaphore* aSem,NThreadBase* aThread)
   463 	{
   464 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NKern::FSSetOwner %m %T",aSem,aThread));
   465 	NKern::Lock();
   466 	aSem->SetOwner(aThread);
   467 	NKern::Unlock();
   468 	}
   469 
   470 /** Waits on a fast semaphore.
   471 
   472     Decrements the signal count for the semaphore
   473 	and waits for a signal if the sempahore becomes unsignalled. Only the
   474 	thread that owns a fast	semaphore can wait on it.
   475 
   476 	@param aSem The semaphore to wait on.
   477 	
   478 	@pre The calling thread must own the semaphore.
   479 	@pre No fast mutex can be held.
   480 	
   481 	@see NFastSemaphore::Wait()
   482 */
   483 EXPORT_C void NKern::FSWait(NFastSemaphore* aSem)
   484 	{
   485 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NKern::FSWait %m",aSem));
   486 	NKern::Lock();
   487 	aSem->Wait();
   488 	NKern::Unlock();
   489 	}
   490 
   491 
   492 /** Signals a fast semaphore.
   493 
   494     Increments the signal count of a fast semaphore
   495 	by one and releases any	waiting thread if the semphore becomes signalled.
   496 	
   497 	@param aSem The semaphore to signal.
   498 
   499 	@see NKern::FSWait()
   500 
   501 	@pre Interrupts must be enabled.
   502 	@pre Do not call from an ISR
   503  */
   504 EXPORT_C void NKern::FSSignal(NFastSemaphore* aSem)
   505 	{
   506 	CHECK_PRECONDITIONS(MASK_INTERRUPTS_ENABLED|MASK_NOT_ISR,"NKern::FSSignal(NFastSemaphore*)");
   507 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NKern::FSSignal %m",aSem));
   508 	NKern::Lock();
   509 	aSem->Signal();
   510 	NKern::Unlock();
   511 	}
   512 
   513 
   514 /** Atomically signals a fast semaphore and releases a fast mutex.
   515 
   516 	Rescheduling only occurs after both synchronisation operations are complete.
   517 	
   518 	@param aSem The semaphore to signal.
   519 	@param aMutex The mutex to release. If NULL, the System Lock is released
   520 
   521 	@pre The calling thread must hold the mutex.
   522 	
   523 	@see NKern::FMSignal()
   524  */
   525 EXPORT_C void NKern::FSSignal(NFastSemaphore* aSem, NFastMutex* aMutex)
   526 	{
   527 	if (!aMutex)
   528 		aMutex=&TheScheduler.iLock;
   529 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NKern::FSSignal %m +FM %M",aSem,aMutex));
   530 	NKern::Lock();
   531 	aSem->Signal();
   532 	aMutex->Signal();
   533 	NKern::Unlock();
   534 	}
   535 
   536 
   537 /** Signals a fast semaphore multiple times.
   538 
   539     Increments the signal count of a
   540 	fast semaphore by aCount and releases any waiting thread if the semphore
   541 	becomes signalled.
   542 	
   543 	@param aSem The semaphore to signal.
   544 	@param aCount The number of times to signal the semaphore.
   545 
   546 	@see NKern::FSWait()
   547 
   548 	@pre Interrupts must be enabled.
   549 	@pre Do not call from an ISR
   550  */
   551 EXPORT_C void NKern::FSSignalN(NFastSemaphore* aSem, TInt aCount)
   552 	{
   553 	CHECK_PRECONDITIONS(MASK_INTERRUPTS_ENABLED|MASK_NOT_ISR,"NKern::FSSignalN(NFastSemaphore*, TInt)");
   554 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NKern::FSSignalN %m %d",aSem,aCount));
   555 	NKern::Lock();
   556 	aSem->SignalN(aCount);
   557 	NKern::Unlock();
   558 	}
   559 
   560 
   561 /** Atomically signals a fast semaphore multiple times and releases a fast mutex.
   562 
   563 	Rescheduling only occurs after both synchronisation operations are complete.
   564 	
   565 	@param aSem The semaphore to signal.
   566 	@param aCount The number of times to signal the semaphore.
   567 	@param aMutex The mutex to release. If NULL, the System Lock is released.
   568 
   569 	@pre The calling thread must hold the mutex.
   570 	
   571 	@see NKern::FMSignal()
   572  */
   573 EXPORT_C void NKern::FSSignalN(NFastSemaphore* aSem, TInt aCount, NFastMutex* aMutex)
   574 	{
   575 	if (!aMutex)
   576 		aMutex=&TheScheduler.iLock;
   577 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NKern::FSSignalN %m %d + FM %M",aSem,aCount,aMutex));
   578 	NKern::Lock();
   579 	aSem->SignalN(aCount);
   580 	aMutex->Signal();
   581 	NKern::Unlock();
   582 	}
   583 
   584 
   585 /******************************************************************************
   586  * Thread
   587  ******************************************************************************/
   588 
   589 #ifndef __SCHEDULER_MACHINE_CODED__
   590 /** Makes a nanothread ready provided that it is not explicitly suspended.
   591 	
   592 	For use by RTOS personality layers.
   593 
   594 	@pre	Kernel must be locked.
   595 	@pre	Call either in a thread or an IDFC context.
   596 
   597 	@post	Kernel is locked.
   598  */
   599 EXPORT_C void NThreadBase::CheckSuspendThenReady()
   600 	{
   601 	CHECK_PRECONDITIONS(MASK_KERNEL_LOCKED|MASK_NOT_ISR,"NThreadBase::CheckSuspendThenReady");	
   602 	if (iSuspendCount==0)
   603 		Ready();
   604 	else
   605 		iNState=ESuspended;
   606 	}
   607 
   608 /** Makes a nanothread ready.
   609 	
   610 	For use by RTOS personality layers.
   611 
   612 	@pre	Kernel must be locked.
   613 	@pre	Call either in a thread or an IDFC context.
   614 	@pre	The thread being made ready must not be explicitly suspended
   615 	
   616 	@post	Kernel is locked.
   617  */
   618 EXPORT_C void NThreadBase::Ready()
   619 	{
   620 #ifdef _DEBUG
   621 	CHECK_PRECONDITIONS(MASK_KERNEL_LOCKED|MASK_NOT_ISR,"NThreadBase::Ready");	
   622 	__ASSERT_WITH_MESSAGE_DEBUG(iSuspendCount==0,"The thread being made ready must not be explicitly suspended","NThreadBase::Ready");
   623 
   624 	if (DEBUGNUM(KCRAZYSCHEDDELAY) && iPriority && TheTimerQ.iMsCount)
   625 		{
   626 		// Delay this thread, unless it's already on the delayed queue
   627 		if ((i_ThrdAttr & KThreadAttDelayed) == 0)
   628 			{
   629 			i_ThrdAttr |= KThreadAttDelayed;
   630 			TheScheduler.iDelayedQ.Add(this);
   631 			}
   632 		}
   633 	else
   634 		{
   635 		// Delayed scheduler off
   636 		// or idle thread, or the tick hasn't started yet
   637 		DoReady();
   638 		}
   639 #else
   640 	DoReady();
   641 #endif
   642 	}
   643 
   644 void NThreadBase::DoReady()
   645 	{
   646 	CHECK_PRECONDITIONS(MASK_KERNEL_LOCKED|MASK_NOT_ISR,"NThreadBase::DoReady");	
   647 	__ASSERT_WITH_MESSAGE_DEBUG(iSuspendCount==0,"The thread being made ready must not be explicitly suspended","NThreadBase::DoReady");
   648 
   649 	TScheduler& s=TheScheduler;
   650 	TInt p=iPriority;
   651 //	__KTRACE_OPT(KSCHED,Kern::Printf("Ready(%O), priority %d status %d",this,p,iStatus));
   652 	if (iNState==EDead)
   653 		return;
   654 	s.Add(this);
   655 	iNState=EReady;
   656 	if (!(s>p))	// s>p <=> highest ready priority > our priority so no preemption
   657 		{
   658 		// if no other thread at this priority or first thread at this priority has used its timeslice, reschedule
   659 		// note iNext points to first thread at this priority since we got added to the end
   660 		if (iNext==this || ((NThreadBase*)iNext)->iTime==0)
   661 			RescheduleNeeded();
   662 		}
   663 	}
   664 #endif
   665 
   666 void NThreadBase::DoCsFunction()
   667 	{
   668 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NThreadBase::DoCsFunction %T %d",this,iCsFunction));
   669 	TInt f=iCsFunction;
   670 	iCsFunction=0;
   671 	if (f>0)
   672 		{
   673 		// suspend this thread f times
   674 		Suspend(f);
   675 		return;
   676 		}
   677 	if (f==ECSExitPending)
   678 		{
   679 		// We need to exit now
   680 		Exit();	// this won't return
   681 		}
   682 	UnknownState(ELeaveCS,f);	// call into RTOS personality
   683 	}
   684 
   685 
   686 /** Suspends a nanothread the specified number of times.
   687 	
   688 	For use by RTOS personality layers.
   689 	Do not use this function directly on a Symbian OS thread.
   690 	Since the kernel is locked on entry, any reschedule will be deferred until
   691 	it is unlocked.
   692 	The suspension will be deferred if the target thread is currently in a
   693 	critical section; in this case the suspension will take effect when it exits
   694 	the critical section.
   695 	The thread's unknown state handler will be invoked with function ESuspend and
   696 	parameter aCount if the current NState is not recognised and it is not in a
   697 	critical section.
   698 
   699 	@param	aCount = the number of times to suspend.
   700 	@return	TRUE, if the suspension has taken immediate effect;
   701 			FALSE, if the thread is in a critical section or is already suspended.
   702 	
   703 	@pre	Kernel must be locked.
   704 	@pre	Call in a thread context.
   705 	
   706 	@post	Kernel is locked.
   707  */
   708 EXPORT_C TBool NThreadBase::Suspend(TInt aCount)
   709 	{
   710 	CHECK_PRECONDITIONS(MASK_KERNEL_LOCKED|MASK_NOT_ISR|MASK_NOT_IDFC,"NThreadBase::Suspend");		
   711 	// If thread is executing a critical section, we must defer the suspend
   712 	if (iNState==EDead)
   713 		return FALSE;		// already dead so suspension is a no-op
   714 	if (iCsCount || iHeldFastMutex)
   715 		{
   716 		__KTRACE_OPT(KNKERN,DEBUGPRINT("NThreadBase::Suspend %T (CSF %d) %d",this,iCsFunction,aCount));
   717 		if (iCsFunction>=0)			// -ve means thread is about to exit
   718 			{
   719 			iCsFunction+=aCount;	// so thread will suspend itself when it leaves the critical section
   720 			if (iHeldFastMutex && iCsCount==0)
   721 				iHeldFastMutex->iWaiting=1;
   722 			}
   723 		return FALSE;
   724 		}
   725 
   726 	// thread not in critical section, so suspend it
   727 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NThreadBase::Suspend %T (NState %d) %d",this,iNState,aCount));
   728 	switch (iNState)
   729 		{
   730 		case EReady:
   731 			TheScheduler.Remove(this);
   732 			RescheduleNeeded();
   733 			iNState=ESuspended;
   734 		case EWaitFastSemaphore:
   735 		case EWaitDfc:
   736 		case ESleep:
   737 		case EBlocked:
   738 		case ESuspended:
   739 			break;
   740 		default:
   741 			UnknownState(ESuspend,aCount);
   742 			break;
   743 		}
   744 	TInt old_suspend=iSuspendCount;
   745 	iSuspendCount-=aCount;
   746 	return (old_suspend==0);	// return TRUE if thread has changed from not-suspended to suspended.
   747 	}
   748 
   749 
   750 /** Resumes a nanothread, cancelling one suspension.
   751 	
   752 	For use by RTOS personality layers.
   753 	Do not use this function directly on a Symbian OS thread.
   754 	Since the kernel is locked on entry, any reschedule will be deferred until
   755 	it is unlocked.
   756 	If the target thread is currently in a critical section this will simply
   757 	cancel one deferred suspension.
   758 	The thread's unknown state handler will be invoked with function EResume if
   759 	the current NState is not recognised and it is not in a	critical section.
   760 
   761 	@return	TRUE, if the resumption has taken immediate effect;
   762 			FALSE, if the thread is in a critical section or is still suspended.
   763 	
   764 	@pre	Kernel must be locked.
   765 	@pre	Call either in a thread or an IDFC context.
   766 	
   767 	@post	Kernel must be locked.
   768  */
   769 EXPORT_C TBool NThreadBase::Resume()
   770 	{
   771 	CHECK_PRECONDITIONS(MASK_KERNEL_LOCKED|MASK_NOT_ISR|MASK_NOT_IDFC,"NThreadBase::Resume");		
   772 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NThreadBase::Resume %T, state %d CSC %d CSF %d",this,iNState,iCsCount,iCsFunction));
   773 	if (iNState==EDead)
   774 		return FALSE;
   775 
   776 	// If thread is in critical section, just cancel deferred suspends
   777 	if (iCsCount || iHeldFastMutex)
   778 		{
   779 		if (iCsFunction>0)
   780 			--iCsFunction;	// one less deferred suspension
   781 		return FALSE;
   782 		}
   783 	if (iSuspendCount<0 && ++iSuspendCount==0)
   784 		{
   785 		switch (iNState)
   786 			{
   787 			case ESuspended:
   788 				Ready();
   789 			case EReady:
   790 			case EWaitFastSemaphore:
   791 			case EWaitDfc:
   792 			case ESleep:
   793 			case EBlocked:
   794 				break;
   795 			default:
   796 				UnknownState(EResume,0);
   797 				break;
   798 			}
   799 		return TRUE;	// thread has changed from suspended to not-suspended
   800 		}
   801 	return FALSE;	// still suspended or not initially suspended so no higher level action required
   802 	}
   803 
   804 
   805 /** Resumes a nanothread, cancelling all outstanding suspensions.
   806 	
   807 	For use by RTOS personality layers.
   808 	Do not use this function directly on a Symbian OS thread.
   809 	Since the kernel is locked on entry, any reschedule will be deferred until
   810 	it is unlocked.
   811 	If the target thread is currently in a critical section this will simply
   812 	cancel all deferred suspensions.
   813 	The thread's unknown state handler will be invoked with function EForceResume
   814 	if the current NState is not recognised and it is not in a	critical section.
   815 
   816 	@return	TRUE, if the resumption has taken immediate effect;
   817 			FALSE, if the thread is in a critical section.
   818 
   819 	@pre	Kernel must be locked.
   820 	@pre	Call either in a thread or an IDFC context.
   821 
   822 	@post	Kernel is locked.
   823  */
   824 EXPORT_C TBool NThreadBase::ForceResume()
   825 	{
   826 	CHECK_PRECONDITIONS(MASK_KERNEL_LOCKED|MASK_NOT_ISR,"NThreadBase::ForceResume");		
   827 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NThreadBase::ForceResume %T, state %d CSC %d CSF %d",this,iNState,iCsCount,iCsFunction));
   828 	if (iNState==EDead)
   829 		return FALSE;
   830 
   831 	// If thread is in critical section, just cancel deferred suspends
   832 	if (iCsCount || iHeldFastMutex)
   833 		{
   834 		if (iCsFunction>0)
   835 			iCsFunction=0;	// cancel all deferred suspensions
   836 		return FALSE;
   837 		}
   838 	if (iSuspendCount<0)
   839 		{
   840 		iSuspendCount=0;
   841 		switch (iNState)
   842 			{
   843 			case ESuspended:
   844 				Ready();
   845 			case EReady:
   846 			case EWaitFastSemaphore:
   847 			case EWaitDfc:
   848 			case ESleep:
   849 			case EBlocked:
   850 			case EDead:
   851 				break;
   852 			default:
   853 				UnknownState(EForceResume,0);
   854 				break;
   855 			}
   856 		}
   857 	return TRUE;
   858 	}
   859 
   860 
   861 /** Releases a waiting nanokernel thread.
   862 
   863 	For use by RTOS personality layers.
   864 	Do not use this function directly on a Symbian OS thread.
   865 	This function should make the thread ready (provided it is not explicitly
   866 	suspended) and cancel any wait timeout. It should also remove it from any
   867 	wait queues.
   868 	If aReturnCode is nonnegative it indicates normal completion of the wait.
   869 	If aReturnCode is negative it indicates early/abnormal completion of the
   870 	wait and so any wait object should be reverted as if the wait had never
   871 	occurred (eg semaphore count should be incremented as this thread has not
   872 	actually acquired the semaphore).
   873 	The thread's unknown state handler will be invoked with function ERelease
   874 	and parameter aReturnCode if the current NState is not recognised.
   875 	
   876 	@param aReturnCode	The reason code for release.
   877 
   878 	@pre	Kernel must be locked.
   879 	@pre	Call either in a thread or an IDFC context.
   880 	
   881 	@post	Kernel is locked.
   882  */
   883 EXPORT_C void NThreadBase::Release(TInt aReturnCode)
   884 	{
   885 	CHECK_PRECONDITIONS(MASK_KERNEL_LOCKED|MASK_NOT_ISR,"NThreadBase::Release");		
   886 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NThreadBase::Release %T, state %d retcode %d",this,iNState,aReturnCode));
   887 	switch(iNState)
   888 		{
   889 		case EDead:
   890 			return;
   891 		case EReady:
   892 		case ESuspended:
   893 			// don't release explicit suspensions
   894 			break;
   895 		case EWaitFastSemaphore:
   896 			if (aReturnCode<0 && iWaitObj)
   897 				((NFastSemaphore*)iWaitObj)->WaitCancel();
   898 			break;
   899 		case ESleep:
   900 		case EBlocked:
   901 		case EWaitDfc:
   902 			CheckSuspendThenReady();
   903 			break;
   904 		default:
   905 			UnknownState(ERelease,aReturnCode);
   906 			break;
   907 		}
   908 	if (iTimer.iUserFlags)
   909 		{
   910 		if (iTimer.iState == NTimer::EIdle)
   911 			{
   912 			// Potential race condition - timer must have completed but expiry
   913 			// handler has not yet run. Signal to the handler that it should do
   914 			// nothing by flipping the bottom bit of iTimer.iPtr
   915 			// This condition cannot possibly recur until the expiry handler has
   916 			// run since all expiry handlers run in DfcThread1.
   917 			TLinAddr& x = *(TLinAddr*)&iTimer.iPtr;
   918 			x ^= 1;
   919 			}
   920 		iTimer.Cancel();
   921 		iTimer.iUserFlags = FALSE;
   922 		}
   923 	iWaitObj=NULL;
   924 	iReturnValue=aReturnCode;
   925 	}
   926 
   927 
   928 /** Signals a nanokernel thread's request semaphore.
   929 
   930 	This can also be used on Symbian OS threads.
   931 	
   932 	@pre	Kernel must be locked.
   933 	@pre	Call either in a thread or an IDFC context.
   934 	
   935 	@post	Kernel is locked.
   936  */
   937 EXPORT_C void NThreadBase::RequestSignal()
   938 	{
   939 	CHECK_PRECONDITIONS(MASK_KERNEL_LOCKED|MASK_NOT_ISR,"NThreadBase::RequestSignal");		
   940 	iRequestSemaphore.Signal();
   941 	}
   942 
   943 void NThreadBase::TimerExpired(TAny* aPtr)
   944 	{
   945 	TLinAddr cookie = (TLinAddr)aPtr;
   946 	NThread* pT = (NThread*)(cookie &~ 3);
   947 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NThreadBase::TimerExpired %T, state %d",pT,pT->iNState));
   948 	NThreadTimeoutHandler th = pT->iHandlers->iTimeoutHandler;
   949 	NKern::Lock();
   950 	if (pT->iNState<ENumNStates && pT->iNState!=EBlocked)
   951 		th = NULL;
   952 	if (th)
   953 		{
   954 		// Use higher level timeout handler
   955 		NKern::Unlock();
   956 		(*th)(pT, ETimeoutPreamble);
   957 		TInt param = ETimeoutPostamble;
   958 		NKern::Lock();
   959 		TLinAddr current_cookie = (TLinAddr)pT->iTimer.iPtr;
   960 		if ((cookie ^ current_cookie) & 1)
   961 			{
   962 			// The timer was cancelled just after expiring but before this function
   963 			// managed to call NKern::Lock(), so it's spurious
   964 			param = ETimeoutSpurious;
   965 			}
   966 		else
   967 			pT->iTimer.iUserFlags = FALSE;
   968 		NKern::Unlock();
   969 		(*th)(pT, param);
   970 		return;
   971 		}
   972 	TLinAddr current_cookie = (TLinAddr)pT->iTimer.iPtr;
   973 	if ((cookie ^ current_cookie) & 1)
   974 		{
   975 		// The timer was cancelled just after expiring but before this function
   976 		// managed to call NKern::Lock(), so just return without doing anything.
   977 		NKern::Unlock();
   978 		return;
   979 		}
   980 	pT->iTimer.iUserFlags = FALSE;
   981 	switch(pT->iNState)
   982 		{
   983 		case EDead:
   984 		case EReady:
   985 		case ESuspended:
   986 			NKern::Unlock();
   987 			return;
   988 		case EWaitFastSemaphore:
   989 			((NFastSemaphore*)pT->iWaitObj)->WaitCancel();
   990 			break;
   991 		case EBlocked:
   992 		case ESleep:
   993 		case EWaitDfc:
   994 			pT->CheckSuspendThenReady();
   995 			break;
   996 		default:
   997 			pT->UnknownState(ETimeout,0);
   998 			break;
   999 		}
  1000 	pT->iWaitObj=NULL;
  1001 	pT->iReturnValue=KErrTimedOut;
  1002 	NKern::Unlock();
  1003 	}
  1004 
  1005 
  1006 /** Changes the priority of a nanokernel thread.
  1007 
  1008 	For use by RTOS personality layers.
  1009 	Do not use this function directly on a Symbian OS thread.
  1010 
  1011 	The thread's unknown state handler will be invoked with function EChangePriority
  1012 	and parameter newp if the current NState is not recognised and the new priority
  1013 	is not equal to the original priority.
  1014 	
  1015 	@param	newp  The new nanokernel priority (0 <= newp < KNumPriorities).
  1016 
  1017 	@pre	Kernel must be locked.
  1018 	@pre	Call in a thread context.
  1019 	
  1020 	@post	Kernel is locked.
  1021  */
  1022 EXPORT_C void NThreadBase::SetPriority(TInt newp)
  1023 	{
  1024 	CHECK_PRECONDITIONS(MASK_KERNEL_LOCKED|MASK_NOT_IDFC|MASK_NOT_ISR,"NThreadBase::SetPriority");		
  1025 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NThreadBase::SetPriority %T %d->%d, state %d",this,iPriority,newp,iNState));
  1026 #ifdef _DEBUG
  1027 	// When the crazy scheduler is active, refuse to set any priority higher than 1
  1028 	if (KCrazySchedulerEnabled() && newp>1)
  1029 		newp=1;
  1030 #endif
  1031 	if (newp==iPriority)
  1032 		return;
  1033 #ifdef BTRACE_THREAD_PRIORITY
  1034 	BTrace8(BTrace::EThreadPriority,BTrace::ENThreadPriority,this,newp);
  1035 #endif
  1036 	switch(iNState)
  1037 		{
  1038 		case EReady:
  1039 			{
  1040 			TInt oldp=iPriority;
  1041 			TheScheduler.ChangePriority(this,newp);
  1042 			NThreadBase* pC=TheScheduler.iCurrentThread;
  1043 			if (this==pC)
  1044 				{
  1045 				if (newp<oldp && (TheScheduler>newp || !TPriListLink::Alone()))	// can't have scheduler<newp
  1046 					RescheduleNeeded();
  1047 				}
  1048 			else if (newp>oldp)
  1049 				{
  1050 				TInt cp=pC->iPriority;
  1051 				if (newp>cp)
  1052 					RescheduleNeeded();
  1053 				else if (newp==cp && pC->iTime==0)
  1054 					{
  1055 					if (pC->iHeldFastMutex)
  1056 						pC->iHeldFastMutex->iWaiting=1;	// don't round-robin now, wait until fast mutex released
  1057 					else
  1058 						RescheduleNeeded();
  1059 					}
  1060 				}
  1061 			break;
  1062 			}
  1063 		case ESuspended:
  1064 		case EWaitFastSemaphore:
  1065 		case EWaitDfc:
  1066 		case ESleep:
  1067 		case EBlocked:
  1068 		case EDead:
  1069 			iPriority=TUint8(newp);
  1070 			break;
  1071 		default:
  1072 			UnknownState(EChangePriority,newp);
  1073 			break;
  1074 		}
  1075 	}
  1076 
  1077 void NThreadBase::Exit()
  1078 	{
  1079 	// The current thread is exiting
  1080 	// Enter with kernel locked, don't return
  1081 	__NK_ASSERT_DEBUG(this==TheScheduler.iCurrentThread);
  1082 
  1083 	OnExit();
  1084 
  1085 	TInt threadCS=iCsCount;
  1086 	TInt kernCS=TheScheduler.iKernCSLocked;
  1087 	iCsCount=1;
  1088 	iCsFunction=ECSExitInProgress;
  1089 	NKern::Unlock();
  1090 	__KTRACE_OPT(KSCHED,DEBUGPRINT("Exit %T %u",this,NTickCount()));
  1091 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NThreadBase::Exit %T, CSC %d HeldFM %M KernCS %d",this,threadCS,iHeldFastMutex,kernCS));
  1092 	if (kernCS!=1)
  1093 		FAULT();
  1094 	if (iHeldFastMutex)
  1095 		FAULT();
  1096 	if (threadCS)
  1097 		FAULT();
  1098 	TDfc* pD=NULL;
  1099 	NThreadExitHandler xh = iHandlers->iExitHandler;
  1100 	if (xh)
  1101 		pD=(*xh)((NThread*)this);		// call exit handler
  1102 	NKern::Lock();
  1103 	if (pD)
  1104 		pD->DoEnque();
  1105 	iNState=EDead;
  1106 	TheScheduler.Remove(this);
  1107 	RescheduleNeeded();
  1108 #ifdef BTRACE_THREAD_IDENTIFICATION
  1109 	BTrace4(BTrace::EThreadIdentification,BTrace::ENanoThreadDestroy,this);
  1110 #endif
  1111 	__NK_ASSERT_ALWAYS(iCsFunction == ECSExitInProgress);
  1112 	TScheduler::Reschedule();	// this won't return
  1113 	FAULT();
  1114 	}
  1115 
  1116 
  1117 /** Kills a nanokernel thread.
  1118 
  1119 	For use by RTOS personality layers.
  1120 	Do not use this function directly on a Symbian OS thread.
  1121 
  1122 	When acting on the calling thread, causes the calling thread to exit.
  1123 
  1124 	When acting on another thread, causes that thread to exit unless it is
  1125 	currently in a critical section. In this case the thread is marked as
  1126 	"exit pending" and will exit as soon as it leaves the critical section.
  1127 
  1128 	In either case the exiting thread first invokes its exit handler (if it
  1129 	exists). The handler runs with preemption enabled and with the thread in a
  1130 	critical section so that it may not be suspended or killed again. The
  1131 	handler may return a pointer to a TDfc, which will be enqueued just before
  1132 	the thread finally terminates (after the kernel has been relocked). This DFC
  1133 	will therefore execute once the NThread has been safely removed from the
  1134 	scheduler and is intended to be used to cleanup the NThread object and any
  1135 	associated personality layer resources.
  1136 	
  1137 	@pre	Kernel must be locked.
  1138 	@pre	Call in a thread context.
  1139 	@pre	If acting on calling thread, calling thread must not be in a
  1140 			critical section; if it is the kernel will fault. Also, the kernel
  1141 			must be locked exactly once (iKernCSLocked = 1).
  1142 	
  1143 	@post	Kernel is locked, if not acting on calling thread.
  1144 	@post	Does not return if it acts on the calling thread.
  1145  */
  1146 EXPORT_C void NThreadBase::Kill()
  1147 	{
  1148 	// Kill a thread
  1149 	// Enter with kernel locked
  1150 	// Exit with kernel locked if not current thread, otherwise does not return
  1151 	CHECK_PRECONDITIONS(MASK_KERNEL_LOCKED_ONCE|MASK_NOT_IDFC|MASK_NOT_ISR,"NThreadBase::Kill");
  1152 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NThreadBase::Kill %T, state %d CSC %d HeldFM %M",this,iNState,iCsCount,iHeldFastMutex));
  1153 	OnKill(); // platform-specific hook
  1154 	NThreadBase* pC=TheScheduler.iCurrentThread;
  1155 	if (this==pC)
  1156 		{
  1157 		if (iCsFunction==ECSExitInProgress)
  1158 			FAULT();
  1159 		Exit();				// this will not return
  1160 		}
  1161 	if (iCsCount || iHeldFastMutex)
  1162 		{
  1163 		__KTRACE_OPT(KNKERN,DEBUGPRINT("NThreadBase::Kill %T deferred",this));
  1164 		if (iCsFunction<0)
  1165 			return;			// thread is already exiting
  1166 		iCsFunction=ECSExitPending;		// zap any suspensions pending
  1167 		if (iHeldFastMutex && iCsCount==0)
  1168 			iHeldFastMutex->iWaiting=1;
  1169 		return;
  1170 		}
  1171 
  1172 	// thread is not in critical section
  1173 	// make the thread divert to Exit() when it next runs
  1174 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NThreadBase::Kill diverting %T",this));
  1175 	Release(KErrDied);		// cancel any waits on semaphores etc.
  1176 	ForceResume();			// release any suspensions
  1177 	iWaitFastMutex=NULL;	// if thread was waiting for a fast mutex it needn't bother
  1178 	iCsCount=1;				// stop anyone suspending the thread
  1179 	iCsFunction=ECSExitPending;
  1180 	ForceExit();			// get thread to call Exit when it is next scheduled
  1181 	}
  1182 
  1183 
  1184 /** Suspends the execution of a thread.
  1185 
  1186 	This function is intended to be used by the EPOC layer and personality layers.
  1187 	Do not use this function directly on a Symbian OS thread - use Kern::ThreadSuspend().
  1188 
  1189     If the thread is in a critical section or holds a fast mutex, the suspension will
  1190     be deferred until the thread leaves the critical section or signals the fast mutex.
  1191     Otherwise the thread will be suspended with immediate effect. If the thread it's
  1192     running, the execution of the thread will be suspended and a reschedule will occur.
  1193 
  1194     @param aThread Thread to be suspended.
  1195     @param aCount  Number of times to suspend this thread.
  1196     
  1197     @return TRUE, if the thread had changed the state from non-suspended to suspended;
  1198 	        FALSE, otherwise.
  1199 	     
  1200 	@see Kern::ThreadSuspend()
  1201 */
  1202 EXPORT_C TBool NKern::ThreadSuspend(NThread* aThread, TInt aCount)
  1203 	{	
  1204 	NKern::Lock();
  1205 	TBool r=aThread->Suspend(aCount);
  1206 	NKern::Unlock();
  1207 	return r;
  1208 	}
  1209 
  1210 
  1211 /** Resumes the execution of a thread.
  1212 
  1213 	This function is intended to be used by the EPOC layer and personality layers.
  1214 	Do not use this function directly on a Symbian OS thread - use Kern::ThreadResume().
  1215 
  1216     This function resumes the thread once. If the thread was suspended more than once
  1217     the thread will remain suspended.
  1218     If the thread is in a critical section, this function will decrease the number of
  1219     deferred suspensions.
  1220 
  1221     @param aThread Thread to be resumed.
  1222     
  1223     @return TRUE, if the thread had changed the state from suspended to non-suspended;
  1224             FALSE, otherwise.
  1225             
  1226 	@see Kern::ThreadResume()
  1227 */
  1228 EXPORT_C TBool NKern::ThreadResume(NThread* aThread)
  1229 	{	
  1230 	NKern::Lock();
  1231 	TBool r=aThread->Resume();
  1232 	NKern::Unlock();
  1233 	return r;
  1234 	}
  1235 
  1236 
  1237 /** Resumes the execution of a thread and signals a mutex.
  1238 
  1239 	This function is intended to be used by the EPOC layer and personality layers.
  1240 	Do not use this function directly on a Symbian OS thread - use Kern::ThreadResume().
  1241 
  1242     This function resumes the thread once. If the thread was suspended more than once
  1243     the thread will remain suspended.
  1244     If the thread is in a critical section, this function will decrease the number of
  1245     deferred suspensions.
  1246 
  1247     @param aThread Thread to be resumed.
  1248     @param aMutex Mutex to be signalled. If NULL, the scheduler's mutex will be signalled.
  1249 
  1250     @return TRUE, if the thread had changed the state from suspended to non-suspended;
  1251             FALSE, otherwise.
  1252            
  1253 	@see Kern::ThreadResume()
  1254 */
  1255 EXPORT_C TBool NKern::ThreadResume(NThread* aThread, NFastMutex* aMutex)
  1256 	{
  1257 	if (!aMutex)
  1258 		aMutex=&TheScheduler.iLock;
  1259 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NKern::ThreadResume %T + FM %M",aThread,aMutex));
  1260 	NKern::Lock();
  1261 	TBool r=aThread->Resume();
  1262 	aMutex->Signal();
  1263 	NKern::Unlock();
  1264 	return r;
  1265 	}
  1266 
  1267 
  1268 /** Forces the execution of a thread to be resumed.
  1269 
  1270 	This function is intended to be used by the EPOC layer and personality layers.
  1271 	Do not use this function directly on a Symbian OS thread - use Kern::ThreadResume().
  1272 
  1273     This function cancels all suspensions on a thread.
  1274 
  1275     @param aThread Thread to be resumed.
  1276     
  1277     @return TRUE, if the thread had changed the state from suspended to non-suspended;
  1278             FALSE, otherwise.
  1279             
  1280 	@see Kern::ThreadResume()
  1281 */
  1282 EXPORT_C TBool NKern::ThreadForceResume(NThread* aThread)
  1283 	{	
  1284 	NKern::Lock();
  1285 	TBool r=aThread->ForceResume();
  1286 	NKern::Unlock();
  1287 	return r;
  1288 	}
  1289 
  1290 
  1291 /** Forces the execution of a thread to be resumed and signals a mutex.
  1292 
  1293 	This function is intended to be used by the EPOC layer and personality layers.
  1294 	Do not use this function directly on a Symbian OS thread - use Kern::ThreadResume().
  1295 
  1296     This function cancels all suspensions on a thread.
  1297 
  1298     @param aThread Thread to be resumed.
  1299     @param aMutex Mutex to be signalled. If NULL, the scheduler's mutex will be signalled.
  1300     
  1301     @return TRUE, if the thread had changed the state from suspended to non-suspended;
  1302             FALSE, otherwise.
  1303             
  1304     @see Kern::ThreadResume()
  1305 */
  1306 EXPORT_C TBool NKern::ThreadForceResume(NThread* aThread, NFastMutex* aMutex)
  1307 	{
  1308 	if (!aMutex)
  1309 		aMutex=&TheScheduler.iLock;
  1310 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NKern::ThreadForceResume %T + FM %M",aThread,aMutex));
  1311 	NKern::Lock();
  1312 	TBool r=aThread->ForceResume();
  1313 	aMutex->Signal();
  1314 	NKern::Unlock();
  1315 	return r;
  1316 	}
  1317 
  1318 
  1319 /** Awakens a nanothread.
  1320 
  1321 	This function is used to implement synchronisation primitives in the EPOC
  1322 	kernel (e.g. DMutex and DSemaphore) and in personality layers.  It is not
  1323 	intended to be used directly by device drivers.
  1324 
  1325 	If the nanothread is waiting on a fast semaphore, waiting for a DFC, or is
  1326 	blocked in a call to NKern::Block, it is awakened and put back on the ready
  1327 	list.  Otherwise, the thread state is unchanged.  In particular, nothing
  1328 	happens if the nanothread has been explicitly suspended.
  1329 
  1330 	@param aThread Thread to release.
  1331 	@param aReturnValue Value returned by NKern::Block if the thread was blocked.
  1332 
  1333 	@see NKern::Block()
  1334 
  1335 	@pre Interrupts must be enabled.
  1336 	@pre Do not call from an ISR
  1337  */
  1338 EXPORT_C void NKern::ThreadRelease(NThread* aThread, TInt aReturnValue)
  1339 	{
  1340 	CHECK_PRECONDITIONS(MASK_INTERRUPTS_ENABLED|MASK_NOT_ISR,"NKern::ThreadRelease(NThread*, TInt)");
  1341 	NKern::Lock();
  1342 	aThread->Release(aReturnValue);
  1343 	NKern::Unlock();
  1344 	}
  1345 
  1346 
  1347 /** Atomically awakens a nanothread and signals a fast mutex.
  1348 
  1349 	This function is used to implement synchronisation primitives in the EPOC
  1350 	kernel (e.g. DMutex and DSemaphore) and in personality layers.  It is not
  1351 	intended to be used directly by device drivers.
  1352 
  1353 	@param aThread Thread to release.
  1354 	@param aReturnValue Value returned by NKern::Block if the thread was blocked.
  1355 	@param aMutex Fast mutex to signal. If NULL, the system lock is signalled.
  1356 
  1357 	@see NKern::ThreadRelease(NThread*, TInt)
  1358 	@see NKern::Block()
  1359 
  1360 	@pre	Call in a thread context.
  1361 	@pre	Interrupts must be enabled.
  1362 	@pre	Kernel must be unlocked.
  1363 	@pre	Specified mutex must be held
  1364  */
  1365 EXPORT_C void NKern::ThreadRelease(NThread* aThread, TInt aReturnValue, NFastMutex* aMutex)
  1366 	{
  1367 	CHECK_PRECONDITIONS(MASK_KERNEL_UNLOCKED|MASK_INTERRUPTS_ENABLED|MASK_NOT_ISR|MASK_NOT_IDFC,"NKern::ThreadRelease(NThread*,TInt,NFastMutex*)");
  1368 	if (!aMutex)
  1369 		aMutex=&TheScheduler.iLock;
  1370 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NKern::ThreadRelease %T ret %d + FM %M",aThread,aReturnValue,aMutex));
  1371 	NKern::Lock();
  1372 	aThread->Release(aReturnValue);
  1373 	aMutex->Signal();
  1374 	NKern::Unlock();
  1375 	}
  1376 
  1377 
  1378 /** Changes the priority of a thread.
  1379 
  1380 	This function is intended to be used by the EPOC layer and personality layers.
  1381 	Do not use this function directly on a Symbian OS thread - use Kern::ThreadSetPriority().
  1382 
  1383     @param aThread Thread to receive the new priority.
  1384     @param aPriority New priority for aThread.
  1385     
  1386 	@see Kern::SetThreadPriority()
  1387 */
  1388 EXPORT_C void NKern::ThreadSetPriority(NThread* aThread, TInt aPriority)
  1389 	{
  1390 	NKern::Lock();
  1391 	aThread->SetPriority(aPriority);
  1392 	NKern::Unlock();
  1393 	}
  1394 
  1395 
  1396 /** Changes the priority of a thread and signals a mutex.
  1397 
  1398 	This function is intended to be used by the EPOC layer and personality layers.
  1399 	Do not use this function directly on a Symbian OS thread - use Kern::ThreadSetPriority().
  1400 
  1401     @param aThread Thread to receive the new priority.
  1402     @param aPriority New priority for aThread.
  1403     @param aMutex Mutex to be signalled. If NULL, the scheduler's mutex will be signalled.
  1404         
  1405 	@see Kern::SetThreadPriority()
  1406 */
  1407 EXPORT_C void NKern::ThreadSetPriority(NThread* aThread, TInt aPriority, NFastMutex* aMutex)
  1408 	{	
  1409 	if (!aMutex)
  1410 		aMutex=&TheScheduler.iLock;
  1411 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NKern::ThreadSetPriority %T->%d + FM %M",aThread,aPriority,aMutex));
  1412 	NKern::Lock();
  1413 	aThread->SetPriority(aPriority);
  1414 	aMutex->Signal();
  1415 	NKern::Unlock();
  1416 	}
  1417 
  1418 #ifndef __SCHEDULER_MACHINE_CODED__
  1419 
  1420 /** Signals the request semaphore of a nanothread.
  1421 
  1422 	This function is intended to be used by the EPOC layer and personality
  1423 	layers.  Device drivers should use Kern::RequestComplete instead.
  1424 
  1425 	@param aThread Nanothread to signal. Must be non NULL.
  1426 
  1427 	@see Kern::RequestComplete()
  1428 
  1429 	@pre Interrupts must be enabled.
  1430 	@pre Do not call from an ISR
  1431  */
  1432 EXPORT_C void NKern::ThreadRequestSignal(NThread* aThread)
  1433 	{
  1434 	CHECK_PRECONDITIONS(MASK_INTERRUPTS_ENABLED|MASK_NOT_ISR,"NKern::ThreadRequestSignal(NThread*)");
  1435 	NKern::Lock();
  1436 	aThread->iRequestSemaphore.Signal();
  1437 	NKern::Unlock();
  1438 	}
  1439 
  1440 
  1441 /** Atomically signals the request semaphore of a nanothread and a fast mutex.
  1442 
  1443 	This function is intended to be used by the EPOC layer and personality
  1444 	layers.  Device drivers should use Kern::RequestComplete instead.
  1445 
  1446 	@param aThread Nanothread to signal.  Must be non NULL.
  1447 	@param aMutex Fast mutex to signal.  If NULL, the system lock is signaled.
  1448 
  1449 	@see Kern::RequestComplete()
  1450 
  1451 	@pre	Call in a thread context.
  1452 	@pre	Interrupts must be enabled.
  1453 	@pre	Kernel must be unlocked.
  1454 	@pre	Specified mutex must be held
  1455  */
  1456 EXPORT_C void NKern::ThreadRequestSignal(NThread* aThread, NFastMutex* aMutex)
  1457 	{
  1458 	CHECK_PRECONDITIONS(MASK_KERNEL_UNLOCKED|MASK_INTERRUPTS_ENABLED|MASK_NOT_ISR|MASK_NOT_IDFC,"NKern::ThreadRequestSignal(NThread*,NFastMutex*)");
  1459 	if (!aMutex)
  1460 		aMutex=&TheScheduler.iLock;
  1461 	NKern::Lock();
  1462 	aThread->iRequestSemaphore.Signal();
  1463 	aMutex->Signal();
  1464 	NKern::Unlock();
  1465 	}
  1466 #endif
  1467 
  1468 
  1469 /** Signals the request semaphore of a nanothread several times.
  1470 
  1471 	This function is intended to be used by the EPOC layer and personality
  1472 	layers.  Device drivers should use Kern::RequestComplete instead.
  1473 
  1474 	@param aThread Nanothread to signal.  If NULL, the current thread is signaled.
  1475 	@param aCount Number of times the request semaphore must be signaled.
  1476 	
  1477 	@pre aCount >= 0
  1478 
  1479 	@see Kern::RequestComplete()
  1480  */
  1481 EXPORT_C void NKern::ThreadRequestSignal(NThread* aThread, TInt aCount)
  1482 	{
  1483 	__ASSERT_WITH_MESSAGE_DEBUG(aCount >= 0,"aCount >= 0","NKern::ThreadRequestSignal");
  1484 	if (!aThread)
  1485 		aThread=(NThread*)TheScheduler.iCurrentThread;
  1486 	NKern::Lock();
  1487 	aThread->iRequestSemaphore.SignalN(aCount);
  1488 	NKern::Unlock();
  1489 	}
  1490 
  1491 
  1492 /**	Kills a nanothread.
  1493 
  1494 	This function is intended to be used by the EPOC layer and personality layers.
  1495 	Do not use this function directly on a Symbian OS thread - use Kern::ThreadKill().
  1496 
  1497 	This function does not return if the current thread is killed.  
  1498 	This function is asynchronous (i.e. the thread to kill may still be alive when the call returns).
  1499 
  1500 	@param aThread Thread to kill.  Must be non NULL.
  1501 
  1502 	@pre If acting on calling thread, calling thread must not be in a
  1503 			critical section
  1504 	@pre Thread must not already be exiting.
  1505 
  1506 	@see Kern::ThreadKill()
  1507  */
  1508 EXPORT_C void NKern::ThreadKill(NThread* aThread)
  1509 	{
  1510 	NKern::Lock();
  1511 	aThread->Kill();
  1512 	NKern::Unlock();
  1513 	}
  1514 
  1515 
  1516 /**	Atomically kills a nanothread and signals a fast mutex.
  1517 
  1518 	This function is intended to be used by the EPOC layer and personality layers.
  1519 	Do not use this function directly on a Symbian OS thread - use Kern::ThreadKill().
  1520 
  1521 	@param aThread Thread to kill.  Must be non NULL.
  1522 	@param aMutex Fast mutex to signal.  If NULL, the system lock is signalled.
  1523 
  1524 	@pre	If acting on calling thread, calling thread must not be in a
  1525 			critical section
  1526 	@pre Thread must not already be exiting.
  1527 
  1528 	@see NKern::ThreadKill(NThread*)
  1529  */
  1530 EXPORT_C void NKern::ThreadKill(NThread* aThread, NFastMutex* aMutex)
  1531 	{
  1532 	if (!aMutex)
  1533 		aMutex=&TheScheduler.iLock;
  1534 	NThreadBase* pC=TheScheduler.iCurrentThread;
  1535 	NKern::Lock();
  1536 	if (aThread==pC)
  1537 		{
  1538 		__NK_ASSERT_DEBUG(pC->iCsCount==0);	// Make sure thread isn't in critical section
  1539 		aThread->iCsFunction=NThreadBase::ECSExitPending;
  1540 		aMutex->iWaiting=1;
  1541 		aMutex->Signal();	// this will make us exit
  1542 		FAULT();			// should never get here
  1543 		}
  1544 	else
  1545 		{
  1546 		aThread->Kill();
  1547 		aMutex->Signal();
  1548 		}
  1549 	NKern::Unlock();
  1550 	}
  1551 
  1552 
  1553 /** Enters thread critical section.
  1554 
  1555 	This function can safely be used in device drivers.
  1556 
  1557     The current thread will enter its critical section. While in critical section
  1558     the thread cannot be suspended or killed. Any suspension or kill will be deferred
  1559     until the thread leaves the critical section.
  1560     Some API explicitly require threads to be in critical section before calling that
  1561     API.
  1562     Only User threads need to call this function as the concept of thread critical
  1563     section applies to User threads only.
  1564 
  1565 	@pre	Call in a thread context.
  1566 	@pre	Kernel must be unlocked.
  1567 */
  1568 EXPORT_C void NKern::ThreadEnterCS()
  1569 	{
  1570 	CHECK_PRECONDITIONS(MASK_KERNEL_UNLOCKED|MASK_NOT_ISR|MASK_NOT_IDFC,"NKern::ThreadEnterCS");
  1571 	NThreadBase* pC=TheScheduler.iCurrentThread;
  1572 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NKern::ThreadEnterCS %T",pC));
  1573 	__NK_ASSERT_DEBUG(pC->iCsCount>=0);
  1574 	++pC->iCsCount;
  1575 	}
  1576 
  1577 
  1578 NThread* NKern::_ThreadEnterCS()
  1579 	{
  1580 	NThread* pC = (NThread*)TheScheduler.iCurrentThread;
  1581 	__NK_ASSERT_DEBUG(pC->iCsCount>=0);
  1582 	++pC->iCsCount;
  1583 	return pC;
  1584 	}
  1585 
  1586 
  1587 /** Leaves thread critical section.
  1588 
  1589 	This function can safely be used in device drivers.
  1590 
  1591     The current thread will leave its critical section. If the thread was suspended/killed
  1592     while in critical section, the thread will be suspended/killed after leaving the
  1593     critical section by calling this function.
  1594     Only User threads need to call this function as the concept of thread critical
  1595     section applies to User threads only.
  1596 
  1597 	@pre	Call in a thread context.
  1598 	@pre	Kernel must be unlocked.
  1599 */
  1600 
  1601 EXPORT_C void NKern::ThreadLeaveCS()
  1602 	{
  1603 	CHECK_PRECONDITIONS(MASK_KERNEL_UNLOCKED|MASK_NOT_ISR|MASK_NOT_IDFC,"NKern::ThreadLeaveCS");
  1604 	NThreadBase* pC=TheScheduler.iCurrentThread;
  1605 	NKern::Lock();
  1606 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NKern::ThreadLeaveCS %T",pC));
  1607 	__NK_ASSERT_DEBUG(pC->iCsCount>0);
  1608 	if (--pC->iCsCount==0 && pC->iCsFunction!=0)
  1609 		{
  1610 		if (pC->iHeldFastMutex)
  1611 			pC->iHeldFastMutex->iWaiting=1;
  1612 		else
  1613 			pC->DoCsFunction();
  1614 		}
  1615 	NKern::Unlock();
  1616 	}
  1617 
  1618 void NKern::_ThreadLeaveCS()
  1619 	{
  1620 	NThreadBase* pC=TheScheduler.iCurrentThread;
  1621 	NKern::Lock();
  1622 	__NK_ASSERT_DEBUG(pC->iCsCount>0);
  1623 	if (--pC->iCsCount==0 && pC->iCsFunction!=0)
  1624 		{
  1625 		if (pC->iHeldFastMutex)
  1626 			pC->iHeldFastMutex->iWaiting=1;
  1627 		else
  1628 			pC->DoCsFunction();
  1629 		}
  1630 	NKern::Unlock();
  1631 	}
  1632 
  1633 /** Freeze the CPU of the current thread
  1634 
  1635 	After this the current thread will not migrate to another processor
  1636 
  1637 	On uniprocessor builds does nothing and returns 0
  1638 
  1639 	@return	A cookie to be passed to NKern::EndFreezeCpu() to allow nesting
  1640 */
  1641 EXPORT_C TInt NKern::FreezeCpu()
  1642 	{
  1643 	CHECK_PRECONDITIONS(MASK_KERNEL_UNLOCKED|MASK_NOT_ISR|MASK_NOT_IDFC,"NKern::FreezeCpu");
  1644 	return 0;
  1645 	}
  1646 
  1647 
  1648 /** Unfreeze the current thread's CPU
  1649 
  1650 	After this the current thread will again be eligible to migrate to another processor
  1651 
  1652 	On uniprocessor builds does nothing
  1653 
  1654 	@param	aCookie the value returned by NKern::FreezeCpu()
  1655 */
  1656 EXPORT_C void NKern::EndFreezeCpu(TInt /*aCookie*/)
  1657 	{
  1658 	CHECK_PRECONDITIONS(MASK_KERNEL_UNLOCKED|MASK_NOT_ISR|MASK_NOT_IDFC,"NKern::EndFreezeCpu");
  1659 	}
  1660 
  1661 
  1662 /** Change the CPU affinity of a thread
  1663 
  1664 	On uniprocessor builds does nothing
  1665 
  1666 	@pre	Call in a thread context.
  1667 
  1668 	@param	The new CPU affinity mask
  1669 	@return The old affinity mask
  1670  */
  1671 EXPORT_C TUint32 NKern::ThreadSetCpuAffinity(NThread*, TUint32)
  1672 	{
  1673 	return 0;	// lock to processor 0
  1674 	}
  1675 
  1676 
  1677 /** Modify a thread's timeslice
  1678 
  1679 	@pre	Call in a thread context.
  1680 
  1681 	@param	aTimeslice	The new timeslice value
  1682  */
  1683 EXPORT_C void NKern::ThreadSetTimeslice(NThread* aThread, TInt aTimeslice)
  1684 	{
  1685 	NKern::Lock();
  1686 	if (aThread->iTimeslice == aThread->iTime || aTimeslice<0)
  1687 		aThread->iTime = aTimeslice;
  1688 	aThread->iTimeslice = aTimeslice;
  1689 	NKern::Unlock();
  1690 	}
  1691 
  1692 
  1693 /** Blocks current nanothread.
  1694 
  1695 	This function is used to implement synchronisation primitives in the EPOC
  1696 	layer and in personality layers.  It is not intended to be used directly by
  1697 	device drivers.  
  1698 
  1699 	@param aTimeout If greater than 0, the nanothread will be blocked for at most
  1700 					aTimeout microseconds.
  1701 	@param aMode	Bitmask whose possible values are documented in TBlockMode.  
  1702 	@param aMutex	Fast mutex to operate on.  If NULL, the system lock is used.
  1703 
  1704 	@see NKern::ThreadRelease()
  1705 	@see TBlockMode
  1706 
  1707 	@pre	Call in a thread context.
  1708 	@pre	Interrupts must be enabled.
  1709 	@pre	Kernel must be unlocked.
  1710 	@pre	Specified mutex must be held
  1711  */
  1712 EXPORT_C TInt NKern::Block(TUint32 aTimeout, TUint aMode, NFastMutex* aMutex)
  1713 	{
  1714 	CHECK_PRECONDITIONS(MASK_KERNEL_UNLOCKED|MASK_INTERRUPTS_ENABLED|MASK_NOT_ISR|MASK_NOT_IDFC,"NKern::Block(TUint32,TUint,NFastMutex*)");
  1715 	if (!aMutex)
  1716 		aMutex=&TheScheduler.iLock;
  1717 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NKern::Block time %d mode %d FM %M",aTimeout,aMode,aMutex));
  1718 	NThreadBase* pC=TheScheduler.iCurrentThread;
  1719 	pC->iReturnValue=0;
  1720 	NKern::Lock();
  1721 	if (aMode & EEnterCS)
  1722 		++pC->iCsCount;
  1723 	if (aMode & ERelease)
  1724 		{
  1725 #ifdef BTRACE_FAST_MUTEX
  1726 		BTraceContext4(BTrace::EFastMutex,BTrace::EFastMutexSignal,aMutex);
  1727 #endif
  1728 		aMutex->iHoldingThread=NULL;
  1729 		TBool w=aMutex->iWaiting;
  1730 		aMutex->iWaiting=0;
  1731 		pC->iHeldFastMutex=NULL;
  1732 		if (w && !pC->iCsCount && pC->iCsFunction)
  1733 			pC->DoCsFunction();
  1734 		}
  1735 	RescheduleNeeded();
  1736 	if (aTimeout)
  1737 		{
  1738 		pC->iTimer.iUserFlags = TRUE;
  1739 		pC->iTimer.OneShot(aTimeout,TRUE);
  1740 		}
  1741 	if (pC->iNState==NThread::EReady)
  1742 		TheScheduler.Remove(pC);
  1743 	pC->iNState=NThread::EBlocked;
  1744 	NKern::Unlock();
  1745 	if (aMode & EClaim)
  1746 		FMWait(aMutex);
  1747 	return pC->iReturnValue;
  1748 	}
  1749 
  1750 /**
  1751 @pre	Call in a thread context.
  1752 @pre	Interrupts must be enabled.
  1753 @pre	Kernel must be unlocked.
  1754 @pre	No fast mutex can be held
  1755 */
  1756 /** @see NKern::Block(TUint32, TUint, NFastMutex*) */
  1757 EXPORT_C TInt NKern::Block(TUint32 aTimeout, TUint aMode)
  1758 	{
  1759 	CHECK_PRECONDITIONS(MASK_THREAD_STANDARD,"NKern::Block(TUint32,TUint)");
  1760 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NKern::Block time %d mode %d",aTimeout,aMode));
  1761 	NThreadBase* pC=TheScheduler.iCurrentThread;
  1762 	pC->iReturnValue=0;
  1763 	NKern::Lock();
  1764 	if (aMode & EEnterCS)
  1765 		++pC->iCsCount;
  1766 	RescheduleNeeded();
  1767 	if (aTimeout)
  1768 		{
  1769 		pC->iTimer.iUserFlags = TRUE;
  1770 		pC->iTimer.OneShot(aTimeout,TRUE);
  1771 		}
  1772 	pC->iNState=NThread::EBlocked;
  1773 	TheScheduler.Remove(pC);
  1774 	NKern::Unlock();
  1775 	return pC->iReturnValue;
  1776 	}
  1777 
  1778 
  1779 
  1780 
  1781 EXPORT_C void NKern::NanoBlock(TUint32 aTimeout, TUint aState, TAny* aWaitObj)
  1782 /**
  1783 Places the current nanothread into a wait state on an externally
  1784 defined wait object.
  1785 	
  1786 For use by RTOS personality layers.
  1787 Do not use this function directly on a Symbian OS thread.
  1788 
  1789 Since the kernel is locked on entry, any reschedule will be deferred until
  1790 it is unlocked. The thread should be added to any necessary wait queue after
  1791 a call to this function, since this function removes it from the ready list.
  1792 The thread's wait timer is started if aTimeout is nonzero.
  1793 The thread's NState and wait object are updated.
  1794 
  1795 Call NThreadBase::Release() when the wait condition is resolved.
  1796 
  1797 @param aTimeout The maximum time for which the thread should block, in nanokernel timer ticks.
  1798                 A zero value means wait forever.
  1799                 If the thread is still blocked when the timeout expires,
  1800                 then the timeout state handler will be called.
  1801 @param aState   The nanokernel thread state (N-State) value to be set.
  1802                 This state corresponds to the externally defined wait object.
  1803                 This value will be written into the member NThreadBase::iNState.
  1804 @param aWaitObj A pointer to an externally defined wait object.
  1805                 This value will be written into the member NThreadBase::iWaitObj.
  1806 
  1807 @pre	Kernel must be locked.
  1808 @pre	Call in a thread context.
  1809 
  1810 @post	Kernel is locked.
  1811 
  1812 @see	NThreadBase::Release()
  1813 */
  1814 	{
  1815 	CHECK_PRECONDITIONS(MASK_KERNEL_LOCKED|MASK_NOT_ISR|MASK_NOT_IDFC,"NKern::NanoBlock");		
  1816 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NKern::NanoBlock time %d state %d obj %08x", aTimeout, aState, aWaitObj));
  1817 	NThreadBase* pC=TheScheduler.iCurrentThread;
  1818 	if (aTimeout)
  1819 		{
  1820 		pC->iTimer.iUserFlags = TRUE;
  1821 		pC->iTimer.OneShot(aTimeout,TRUE);
  1822 		}
  1823 	pC->iNState = (TUint8)aState;
  1824 	pC->iWaitObj = aWaitObj;
  1825 	pC->iReturnValue = 0;
  1826 	TheScheduler.Remove(pC);
  1827 	RescheduleNeeded();
  1828 	}
  1829 
  1830 
  1831 
  1832 
  1833 EXPORT_C void NKern::Sleep(TUint32 aTime)
  1834 /**
  1835 Puts the current nanothread to sleep for the specified duration.
  1836 
  1837 It can be called from Symbian OS threads.
  1838 
  1839 @param	aTime sleep time in nanokernel timer ticks.
  1840 
  1841 @pre    No fast mutex can be held.
  1842 @pre    Kernel must be unlocked.
  1843 @pre	Call in a thread context.
  1844 @pre	Interrupts must be enabled.
  1845 */
  1846 	{
  1847 	CHECK_PRECONDITIONS(MASK_THREAD_STANDARD,"NKern::Sleep");		
  1848 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NKern::Sleep %d",aTime));
  1849 	NThreadBase* pC=TheScheduler.iCurrentThread;
  1850 	NKern::Lock();
  1851 	pC->iTimer.iUserFlags = TRUE;
  1852 	pC->iTimer.OneShot(aTime,TRUE);
  1853 	pC->iNState=NThread::ESleep;
  1854 	TheScheduler.Remove(pC);
  1855 	RescheduleNeeded();
  1856 	NKern::Unlock();
  1857 	}
  1858 
  1859 
  1860 /**	Terminates the current nanothread.
  1861 
  1862 	Calls to this function never return.
  1863 
  1864 	For use by RTOS personality layers.
  1865 	Do not use this function directly on a Symbian OS thread.
  1866 
  1867 	@pre	Call in a thread context.
  1868 	@pre	Interrupts must be enabled.
  1869 	@pre	Kernel must be unlocked.	
  1870  */
  1871 EXPORT_C void NKern::Exit()
  1872 	{
  1873 	CHECK_PRECONDITIONS(MASK_KERNEL_UNLOCKED|MASK_INTERRUPTS_ENABLED|MASK_NOT_ISR|MASK_NOT_IDFC,"NKern::Exit");
  1874 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NKern::Exit"));
  1875 	NThreadBase* pC=TheScheduler.iCurrentThread;
  1876 	NKern::Lock();
  1877 	pC->Exit();			// this won't return
  1878 	FAULT();
  1879 	}
  1880 
  1881 
  1882 /**	Terminates the current nanothread at the next possible point.
  1883 
  1884 	If the calling thread is not currently in a critical section and does not
  1885 	currently hold a fast mutex, it exits immediately and this function does
  1886 	not return. On the other hand if the thread is in a critical section or
  1887 	holds a fast mutex the thread continues executing but it will exit as soon
  1888 	as it leaves the critical section and/or releases the fast mutex.
  1889 
  1890 	@pre	Call in a thread context.
  1891 	@pre	Interrupts must be enabled.
  1892 	@pre	Kernel must be unlocked.	
  1893  */
  1894 EXPORT_C void NKern::DeferredExit()
  1895 	{
  1896 	CHECK_PRECONDITIONS(MASK_KERNEL_UNLOCKED|MASK_INTERRUPTS_ENABLED|MASK_NOT_ISR|MASK_NOT_IDFC,"NKern::DeferredExit");
  1897 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NDefExit"));
  1898 	NFastMutex* m = HeldFastMutex();
  1899 	NThreadBase* pC = NKern::LockC();
  1900 	if (!m && !pC->iCsCount)
  1901 		pC->Exit();			// this won't return
  1902 	if (pC->iCsFunction >= 0)	// don't touch it if we are already exiting
  1903 		pC->iCsFunction = NThreadBase::ECSExitPending;
  1904 	if (m && !pC->iCsCount)
  1905 		m->iWaiting = TRUE;
  1906 	NKern::Unlock();
  1907 	}
  1908 
  1909 
  1910 /** Prematurely terminates the current thread's timeslice
  1911 
  1912 	@pre	Kernel must be unlocked.
  1913 	@pre	Call in a thread context.
  1914 	
  1915 	@post	Kernel is unlocked.
  1916  */
  1917 EXPORT_C void NKern::YieldTimeslice()
  1918 	{
  1919 	CHECK_PRECONDITIONS(MASK_KERNEL_UNLOCKED|MASK_NOT_ISR|MASK_NOT_IDFC,"NKern::YieldTimeslice");
  1920 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NKern::YieldTimeslice"));
  1921 	NThreadBase* t = NKern::LockC();
  1922 	t->iTime = 0;
  1923 	if (t->iNext != t)
  1924 		RescheduleNeeded();
  1925 	NKern::Unlock();
  1926 	}
  1927 
  1928 
  1929 /** Rotates the ready list for threads at the specified priority.
  1930 	
  1931 	For use by RTOS personality layers to allow external control of round-robin
  1932 	scheduling. Not intended for direct use by device drivers.
  1933 
  1934 	@param	aPriority = priority at which threads should be rotated.
  1935 						-1 means use calling thread's priority.
  1936 	
  1937 	@pre	Kernel must be unlocked.
  1938 	@pre	Call in a thread context.
  1939 	
  1940 	@post	Kernel is unlocked.
  1941  */
  1942 EXPORT_C void NKern::RotateReadyList(TInt aPriority)
  1943 	{
  1944 	CHECK_PRECONDITIONS(MASK_KERNEL_UNLOCKED|MASK_NOT_ISR|MASK_NOT_IDFC,"NKern::RotateReadyList");		
  1945 	__KTRACE_OPT(KNKERN,DEBUGPRINT("NKern::RotateReadyList %d",aPriority));
  1946 	if (aPriority<0 || aPriority>=KNumPriorities)
  1947 		aPriority=TheScheduler.iCurrentThread->iPriority;
  1948 	NKern::Lock();
  1949 	TheScheduler.RotateReadyList(aPriority);
  1950 	NKern::Unlock();
  1951 	}
  1952 
  1953 /** Rotates the ready list for threads at the specified priority.
  1954 	
  1955 	For use by RTOS personality layers to allow external control of round-robin
  1956 	scheduling. Not intended for direct use by device drivers.
  1957 
  1958 	@param	aPriority = priority at which threads should be rotated.
  1959 						-1 means use calling thread's priority.
  1960 	@param	aCpu = which CPU's ready list should be rotated
  1961 					ignored on UP systems.
  1962 	
  1963 	@pre	Kernel must be unlocked.
  1964 	@pre	Call in a thread context.
  1965 	
  1966 	@post	Kernel is unlocked.
  1967  */
  1968 EXPORT_C void NKern::RotateReadyList(TInt aPriority, TInt /*aCpu*/)
  1969 	{
  1970 	RotateReadyList(aPriority);
  1971 	}
  1972 
  1973 
  1974 /** Returns the NThread control block for the currently scheduled thread.
  1975 
  1976     Note that this is the calling thread if called from a thread context, or the
  1977 	interrupted thread if called from an interrupt context.
  1978 	
  1979 	@return A pointer to the NThread for the currently scheduled thread.
  1980 	
  1981 	@pre Call in any context.
  1982 */
  1983 EXPORT_C NThread* NKern::CurrentThread()
  1984 	{
  1985 	return (NThread*)TheScheduler.iCurrentThread;
  1986 	}
  1987 
  1988 
  1989 /** Returns the CPU number of the calling CPU.
  1990 
  1991 	@return the CPU number of the calling CPU.
  1992 	
  1993 	@pre Call in any context.
  1994 */
  1995 EXPORT_C TInt NKern::CurrentCpu()
  1996 	{
  1997 	return 0;
  1998 	}
  1999 
  2000 
  2001 /** Returns the number of CPUs available to Symbian OS
  2002 
  2003 	@return the number of CPUs
  2004 	
  2005 	@pre Call in any context.
  2006 */
  2007 EXPORT_C TInt NKern::NumberOfCpus()
  2008 	{
  2009 	return 1;
  2010 	}
  2011 
  2012 
  2013 /** Check if the kernel is locked the specified number of times.
  2014 
  2015 	@param aCount	The number of times the kernel should be locked
  2016 					If zero, tests if it is locked at all
  2017 	@return TRUE if the tested condition is true.
  2018 
  2019 	@internalTechnology
  2020 */
  2021 EXPORT_C TBool NKern::KernelLocked(TInt aCount)
  2022 	{
  2023 	if (aCount)
  2024 		return TheScheduler.iKernCSLocked == aCount;
  2025 	return TheScheduler.iKernCSLocked!=0;
  2026 	}
  2027 
  2028 
  2029 /******************************************************************************
  2030  * Priority lists
  2031  ******************************************************************************/
  2032 
  2033 #ifndef __PRI_LIST_MACHINE_CODED__
  2034 /** Returns the priority of the highest priority item present on a priority list.
  2035 
  2036 	@return	The highest priority present or -1 if the list is empty.
  2037  */
  2038 EXPORT_C TInt TPriListBase::HighestPriority()
  2039 	{
  2040 //	TUint64 present = MAKE_TUINT64(iPresent[1], iPresent[0]);
  2041 //	return __e32_find_ms1_64(present);
  2042 	return __e32_find_ms1_64(iPresent64);
  2043 	}
  2044 
  2045 
  2046 /** Finds the highest priority item present on a priority list.
  2047 
  2048 	If multiple items at the same priority are present, return the first to be
  2049 	added in chronological order.
  2050 
  2051 	@return	A pointer to the item or NULL if the list is empty.
  2052  */
  2053 EXPORT_C TPriListLink* TPriListBase::First()
  2054 	{
  2055 	TInt p = HighestPriority();
  2056 	return p >=0 ? static_cast<TPriListLink*>(iQueue[p]) : NULL;
  2057 	}
  2058 
  2059 
  2060 /** Adds an item to a priority list.
  2061 
  2062 	@param aLink A pointer to the item - must not be NULL.
  2063  */
  2064 EXPORT_C void TPriListBase::Add(TPriListLink* aLink)
  2065 	{
  2066 	TInt p = aLink->iPriority;
  2067 	SDblQueLink* head = iQueue[p];
  2068 	if (head)
  2069 		{
  2070 		// already some at this priority
  2071 		aLink->InsertBefore(head);
  2072 		}
  2073 	else
  2074 		{
  2075 		// 'create' new list
  2076 		iQueue[p] = aLink;
  2077 		aLink->iNext = aLink->iPrev = aLink;
  2078 		iPresent[p>>5] |= 1u << (p & 0x1f);
  2079 		}
  2080 	}
  2081 
  2082 
  2083 /** Removes an item from a priority list.
  2084 
  2085 	@param aLink A pointer to the item - must not be NULL.
  2086  */
  2087 EXPORT_C void TPriListBase::Remove(TPriListLink* aLink)
  2088 	{
  2089 	if (!aLink->Alone())
  2090 		{
  2091 		// not the last on this list
  2092 		TInt p = aLink->iPriority;
  2093 		if (iQueue[p] == aLink)
  2094 			iQueue[p] = aLink->iNext;
  2095 		aLink->Deque();
  2096 		}
  2097 	else
  2098 		{
  2099 		TInt p = aLink->iPriority;
  2100 		iQueue[p] = 0;
  2101 		iPresent[p>>5] &= ~(1u << (p & 0x1f));
  2102 		KILL_LINK(aLink);
  2103 		}
  2104 	}
  2105 
  2106 
  2107 /** Changes the priority of an item on a priority list.
  2108 
  2109 	@param	aLink A pointer to the item to act on - must not be NULL.
  2110 	@param	aNewPriority A new priority for the item.
  2111  */
  2112 EXPORT_C void TPriListBase::ChangePriority(TPriListLink* aLink, TInt aNewPriority)
  2113 	{
  2114 	if (aLink->iPriority!=aNewPriority)
  2115 		{
  2116 		Remove(aLink);
  2117 		aLink->iPriority=TUint8(aNewPriority);
  2118 		Add(aLink);
  2119 		}
  2120 	}
  2121 #endif
  2122 
  2123 /** Adds an item to a priority list at the head of the queue for its priority.
  2124 
  2125 	@param aLink A pointer to the item - must not be NULL.
  2126  */
  2127 EXPORT_C void TPriListBase::AddHead(TPriListLink* aLink)
  2128 	{
  2129 	TInt p = aLink->iPriority;
  2130 	SDblQueLink* head = iQueue[p];
  2131 	iQueue[p] = aLink;
  2132 	if (head)
  2133 		{
  2134 		// already some at this priority
  2135 		aLink->InsertBefore(head);
  2136 		}
  2137 	else
  2138 		{
  2139 		// 'create' new list
  2140 		aLink->iNext = aLink->iPrev = aLink;
  2141 		iPresent[p>>5] |= 1u << (p & 0x1f);
  2142 		}
  2143 	}
  2144 
  2145