kernel/eka/nkern/win32/ncthrd.cpp
changeset 273 6a75fa55495f
parent 0 a41df078684a
child 279 957c583b417b
equal deleted inserted replaced
271:dc268b18d709 273:6a75fa55495f
     1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
     1 // Copyright (c) 1998-2010 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
    10 //
    10 //
    11 // Contributors:
    11 // Contributors:
    12 //
    12 //
    13 // Description:
    13 // Description:
    14 // e32\nkern\win32\ncthrd.cpp
    14 // e32\nkern\win32\ncthrd.cpp
    15 // 
    15 //
    16 //
    16 //
    17 
    17 
    18 // NThreadBase member data
    18 // NThreadBase member data
    19 #define __INCLUDE_NTHREADBASE_DEFINES__
    19 #define __INCLUDE_NTHREADBASE_DEFINES__
    20 
    20 
    21 #include "nk_priv.h"
    21 #include "nk_priv.h"
    22 #include <emulator.h>
    22 #include <emulator.h>
       
    23 
       
    24 #if		defined(__CW32__) && defined(__MWERKS__) && (__MWERKS__ < 0x3200)
       
    25 // Early versions didn't support try/except :(
       
    26 #error	"This compiler is no longer supported, because it doesn't provide C++ exception generation and handling"
       
    27 #endif
    23 
    28 
    24 extern "C" void ExcFault(TAny*);
    29 extern "C" void ExcFault(TAny*);
    25 
    30 
    26 // initial Win32 thread stack size
    31 // initial Win32 thread stack size
    27 const TInt KInitialStackSize = 0x1000;
    32 const TInt KInitialStackSize = 0x1000;
    34 	{
    39 	{
    35 	const SNThreadCreateInfo* iInfo;
    40 	const SNThreadCreateInfo* iInfo;
    36 	NFastMutex iHandoff;
    41 	NFastMutex iHandoff;
    37 	};
    42 	};
    38 
    43 
    39 /**
       
    40  * Set the Win32 thread priority based on the thread type.
       
    41  * Interrupt/Event threads must be able to preempt normal nKern threads,
       
    42  * so they get a higher priority.
       
    43  */
       
    44 static void SetPriority(HANDLE aThread, TEmulThreadType aType)
       
    45 	{
       
    46 	TInt p;
       
    47 	switch (aType)
       
    48 		{
       
    49 	default:
       
    50 		FAULT();
       
    51 	case EThreadEvent:
       
    52 		p = THREAD_PRIORITY_ABOVE_NORMAL;
       
    53 		break;
       
    54 	case EThreadNKern:
       
    55 		p = THREAD_PRIORITY_NORMAL;
       
    56 		break;
       
    57 		}
       
    58 
       
    59 	__NK_ASSERT_ALWAYS(SetThreadPriority(aThread, p));
       
    60 	SetThreadPriorityBoost(aThread, TRUE);		// disable priority boost (for NT)
       
    61 	}
       
    62 
       
    63 
       
    64 /**	Create a Win32 thread for use in the emulator.
       
    65 
       
    66 	@param	aType Type of thread (Event or NKern) - determines Win32 priority
       
    67 	@param	aThreadFunc Entry point of thread
       
    68 	@param	aPtr Argument passed to entry point
       
    69 	@param	aRun TRUE if thread should be resumed immediately
       
    70 	@return	The Win32 handle to the thread, 0 if an error occurred
       
    71 
       
    72 	@pre    Call either in thread context.
       
    73 	@pre	Do not call from bare Win32 threads.
       
    74 
       
    75 	@see TEmulThreadType
       
    76  */
       
    77 EXPORT_C HANDLE CreateWin32Thread(TEmulThreadType aType, LPTHREAD_START_ROUTINE aThreadFunc, LPVOID aPtr, TBool aRun)
       
    78 	{
       
    79 	__NK_ASSERT_DEBUG(!TheScheduler.iCurrentThread || NKern::CurrentContext() == NKern::EThread);
       
    80 
       
    81 	__LOCK_HOST;
       
    82 	
       
    83 	DWORD id;
       
    84 	HANDLE handle = CreateThread(NULL , KInitialStackSize, aThreadFunc, aPtr, CREATE_SUSPENDED, &id);
       
    85 	if (handle)
       
    86 		{
       
    87 		SetPriority(handle, aType);
       
    88 		if (aRun)
       
    89 			ResumeThread(handle);
       
    90 		}
       
    91 	return handle;
       
    92 	}
       
    93 
       
    94 
    44 
    95 /** Set some global properties of the emulator
    45 /** Set some global properties of the emulator
    96 	Called by the Win32 base port during boot.
    46 	Called by the Win32 base port during boot.
    97 
    47 
    98 	@param	aTrace TRUE means trace Win32 thread ID for every thread created
    48 	@param	aTrace TRUE means trace Win32 thread ID for every thread created
   104 	{
    54 	{
   105 	Win32TraceThreadId = aTrace;
    55 	Win32TraceThreadId = aTrace;
   106 	Win32SingleCpu = aSingleCpu;
    56 	Win32SingleCpu = aSingleCpu;
   107 	}
    57 	}
   108 
    58 
   109 #if defined(__CW32__) && __MWERKS__ < 0x3200
    59 
   110 DWORD NThread__ExceptionHandler(EXCEPTION_RECORD* aException, TAny* /*aRegistrationRecord*/, CONTEXT* aContext)
    60 
   111 //
    61 void NThread__HandleException(TWin32ExcInfo aExc)
   112 // Hook into exception handling for old version of CW
    62 //
   113 //
    63 // Final stage NKern exception handler.
   114 	{
    64 //
   115 	return NThread::ExceptionHandler(aException, aContext);
    65 // The first stage of exception processing (in ExceptionHandler()) entered the
   116 	}
    66 // kernel and locked it, so we have to undo those two operations before returning.
   117 #endif // old __CW32__
    67 // However, if the kernel was already locked when the exception occurred, it is
   118 
    68 // a fatal condition and the system will be faulted.
   119 DWORD WINAPI NThread::StartThread(LPVOID aParam)
    69 //
   120 //
    70 // Note that the parameter struct is passed by value, this allows for direct
   121 // Win32 thread function for nKern threads.
    71 // access to the exception context created on the call stack by NThread::Exception().
   122 //
    72 //
   123 // The thread first enters this function after the nScheduler has resumed
    73 	{
   124 // it, following the context switch induced by the hand-off mutex.
       
   125 //
       
   126 // The parameter block for this thread needs to be copied into its
       
   127 // own context, before releasing the mutex and handing control back to
       
   128 // the creating thread.
       
   129 //
       
   130 	{
       
   131 	SCreateThread* init = static_cast<SCreateThread*>(aParam);
       
   132 	NThread& me=*static_cast<NThread*>(init->iHandoff.iHoldingThread);
       
   133 	me.iWinThreadId = GetCurrentThreadId();
       
   134 	SchedulerRegister(me);
       
   135 #ifdef BTRACE_FAST_MUTEX
       
   136 	BTraceContext4(BTrace::EFastMutex,BTrace::EFastMutexWait,&init->iHandoff);
       
   137 #endif
       
   138 	NKern::Unlock();
    74 	NKern::Unlock();
   139 
       
   140 #if defined(__CW32__) && __MWERKS__ < 0x3200
       
   141 	// intercept the win32 exception mechanism manually
       
   142     asm {
       
   143     	push	ebp
       
   144     	mov		eax, -1
       
   145     	push	eax
       
   146     	push	eax
       
   147     	push	offset NThread__ExceptionHandler
       
   148     	push	fs:[0]
       
   149     	mov		fs:[0], esp
       
   150 
       
   151 		// realign the stack
       
   152     	sub		esp, 0x20
       
   153     	and		esp, ~0x1f
       
   154 		}
       
   155 #else // ! old __CW32__
       
   156 	// intercept win32 exceptions in a debuggabble way
       
   157 __try {
       
   158 #endif // old __CW32__
       
   159 
       
   160 	// save the thread entry point and parameter block
       
   161 	const SNThreadCreateInfo& info = *init->iInfo;
       
   162 	TUint8 parameterBlock[KMaxParameterBlock];
       
   163 	TAny* parameter=(TAny*)info.iParameterBlock;
       
   164 	if (info.iParameterBlockSize)
       
   165 		{
       
   166 		__NK_ASSERT_DEBUG(TUint(info.iParameterBlockSize)<=TUint(KMaxParameterBlock));
       
   167 		parameter=parameterBlock;
       
   168 		memcpy(parameterBlock,info.iParameterBlock,info.iParameterBlockSize);
       
   169 		}
       
   170 	NThreadFunction threadFunction=info.iFunction;
       
   171 
       
   172 	// Calculate stack base
       
   173 	me.iUserStackBase = (((TLinAddr)&parameterBlock)+0xfff)&~0xfff; // base address of stack
       
   174 
       
   175 	// some useful diagnostics for debugging
       
   176 	if (Win32TraceThreadId)
       
   177 		KPrintf("Thread %T created @ 0x%x - Win32 Thread ID 0x%x",init->iHandoff.iHoldingThread,init->iHandoff.iHoldingThread,GetCurrentThreadId());
       
   178 
       
   179 #ifdef MONITOR_THREAD_CPU_TIME
       
   180 	me.iLastStartTime = 0;  // Don't count NThread setup in cpu time
       
   181 #endif
       
   182  
       
   183 	// start-up complete, release the handoff mutex, which will re-suspend us
       
   184 	NKern::FMSignal(&init->iHandoff);
       
   185 
       
   186 	// thread has been resumed: invoke the thread function
       
   187 	threadFunction(parameter);
       
   188 
       
   189 #if !defined(__CW32__) || __MWERKS__ >= 0x3200
       
   190 	// handle win32 exceptions
       
   191 } __except (ExceptionFilter(GetExceptionInformation())) {
       
   192 	// Do nothing - filter does all the work and hooks
       
   193 	// into EPOC h/w exception mechanism if necessary
       
   194 	// by thread diversion
       
   195 }
       
   196 #endif // !old __CW32__
       
   197 
       
   198 	NKern::Exit();
       
   199 
       
   200 	return 0;
       
   201 	}
       
   202 
       
   203 static HANDLE InitThread()
       
   204 //
       
   205 // Set up the initial thread and return the thread handle
       
   206 //
       
   207 	{
       
   208 	HANDLE p = GetCurrentProcess();
       
   209 	HANDLE me;
       
   210 	__NK_ASSERT_ALWAYS(DuplicateHandle(p, GetCurrentThread(), p, &me, 0, FALSE, DUPLICATE_SAME_ACCESS));
       
   211 	SetPriority(me, EThreadNKern);
       
   212 	return me;
       
   213 	}
       
   214 
       
   215 TInt NThread::Create(SNThreadCreateInfo& aInfo, TBool aInitial)
       
   216 	{
       
   217 	iWinThread = NULL;
       
   218 	iWinThreadId = 0;
       
   219 	iScheduleLock = NULL;
       
   220 	iInKernel = 1;
       
   221 	iDivert = NULL;
       
   222 	iWakeup = aInitial ? ERelease : EResumeLocked;	// mark new threads as created (=> win32 suspend)
       
   223 
       
   224 	TInt r=NThreadBase::Create(aInfo,aInitial);
       
   225 	if (r!=KErrNone)
       
   226 		return r;
       
   227 
       
   228 	// the rest has to be all or nothing, we must complete it
       
   229 	iScheduleLock = CreateEventA(NULL, FALSE, FALSE, NULL);
       
   230 	if (iScheduleLock == NULL)
       
   231 		return Emulator::LastError();
       
   232 
       
   233 	if (aInitial)
       
   234 		{
       
   235 		iWinThread = InitThread();
       
   236 		FastCounterInit();
       
   237 #ifdef MONITOR_THREAD_CPU_TIME
       
   238 		iLastStartTime = NKern::FastCounter();
       
   239 #endif
       
   240 		iUserStackBase = (((TLinAddr)&r)+0xfff)&~0xfff; // base address of stack
       
   241 		SchedulerInit(*this);
       
   242 		return KErrNone;
       
   243 		}
       
   244 
       
   245 	// create the thread proper
       
   246 	//
       
   247 	SCreateThread start;
       
   248 	start.iInfo = &aInfo;
       
   249 
       
   250 	iWinThread = CreateWin32Thread(EThreadNKern, &StartThread, &start, FALSE);
       
   251 	if (iWinThread == NULL)
       
   252 		{
       
   253 		r = Emulator::LastError();
       
   254 		CloseHandle(iScheduleLock);
       
   255 		return r;
       
   256 		}
       
   257 
       
   258 #ifdef BTRACE_THREAD_IDENTIFICATION
       
   259 	BTrace4(BTrace::EThreadIdentification,BTrace::ENanoThreadCreate,this);
       
   260 #endif
       
   261 	// switch to the new thread to hand over the parameter block
       
   262 	NKern::Lock();
       
   263 	ForceResume();	// mark the thread as ready
       
   264 	// give the thread ownership of the handoff mutex
       
   265 	start.iHandoff.iHoldingThread = this;
       
   266 	iHeldFastMutex = &start.iHandoff;
       
   267 	Suspend(1);		// will defer as holding a fast mutex (implicit critical section)
       
   268 	// do the hand-over
       
   269 	start.iHandoff.Wait();
       
   270 	start.iHandoff.Signal();
       
   271 	NKern::Unlock();
       
   272 
       
   273 	return KErrNone;
       
   274 	}
       
   275 
       
   276 void NThread__HandleException(TWin32ExcInfo aExc)
       
   277 //
       
   278 // Final stage NKern exception handler.
       
   279 //
       
   280 // Check for a fatal exception when the kernel is locked
       
   281 //
       
   282 // Note that the parameter struct is passed by value, this allows for
       
   283 // direct access to the exception context created on the call stack by
       
   284 // NThread::Exception().
       
   285 //
       
   286 	{
       
   287 	if (TheScheduler.iKernCSLocked)
    75 	if (TheScheduler.iKernCSLocked)
   288 		ExcFault(&aExc);
    76 		ExcFault(&aExc);
   289 
    77 
   290 	// Complete the exception data. Note that the call to EnterKernel() in
    78 	// Complete the exception data. Note that the call to EnterKernel() in
   291 	// ExceptionFilter() will have incremented iInKernel after the exception
    79 	// ExceptionHandler() will have incremented iInKernel after the exception
   292 	// occurred.
    80 	// occurred.
   293 	NThread* me = static_cast<NThread*>(TheScheduler.iCurrentThread);
    81 	NThread* me = static_cast<NThread*>(TheScheduler.iCurrentThread);
   294 	__NK_ASSERT_DEBUG(me->iInKernel);
    82 	__NK_ASSERT_DEBUG(me->iInKernel);
   295 	aExc.iFlags = me->iInKernel == 1 ? 0 : TWin32ExcInfo::EExcInKernel;
    83 	aExc.iFlags = me->iInKernel == 1 ? 0 : TWin32ExcInfo::EExcInKernel;
   296 	aExc.iHandler = NULL;
    84 	aExc.iHandler = NULL;
   302 	// If a 'user' handler is set by the kernel handler, run it
    90 	// If a 'user' handler is set by the kernel handler, run it
   303 	if (aExc.iHandler)
    91 	if (aExc.iHandler)
   304 		aExc.iHandler(aExc.iParam[0], aExc.iParam[1]);
    92 		aExc.iHandler(aExc.iParam[0], aExc.iParam[1]);
   305 	}
    93 	}
   306 
    94 
   307 void NKern__Unlock()
       
   308 //
       
   309 // CW asm ICE workaround
       
   310 //
       
   311 	{
       
   312 	NKern::Unlock();
       
   313 	}
       
   314 
       
   315 __NAKED__ void NThread::Exception()
    95 __NAKED__ void NThread::Exception()
   316 //
    96 //
   317 // Trampoline to nKern exception handler
    97 // Trampoline to nKern exception handler
   318 // must preserve all registers in the structure defined by TWin32Exc
    98 // Must preserve all registers in the structure defined by TWin32Exc
       
    99 //
       
   100 // This is an intermediate layer, to which control has been diverted by
       
   101 // NThread::ExceptionHandler(). It constructs a TWin32Exc structure on
       
   102 // the stack and passes it NThread__ExceptionHandler().
       
   103 //
       
   104 // At this point we are no longer in Win32 exception context.
   319 //
   105 //
   320 	{
   106 	{
   321 	// this is the TWin32Exc structure
   107 	// this is the TWin32Exc structure
   322 	__asm push Win32ExcAddress			// save return address followed by EBP first to help debugger
   108 	__asm push Win32ExcAddress			// save return address followed by EBP first to help debugger
   323 	__asm push ebp
   109 	__asm push ebp
   330 	__asm push ds
   116 	__asm push ds
   331 	__asm push ss
   117 	__asm push ss
   332 	__asm push edi
   118 	__asm push edi
   333 	__asm push esi
   119 	__asm push esi
   334 	__asm lea esi, [ebp+8]
   120 	__asm lea esi, [ebp+8]
   335 	__asm push esi		// original esp
   121 	__asm push esi						// original esp
   336 	__asm push ebx
   122 	__asm push ebx
   337 	__asm push edx
   123 	__asm push edx
   338 	__asm push ecx
   124 	__asm push ecx
   339 	__asm push eax
   125 	__asm push eax
   340 	__asm push Win32ExcDataAddress
   126 	__asm push Win32ExcDataAddress
   341 	__asm push Win32ExcCode
   127 	__asm push Win32ExcCode
   342 	__asm sub esp, 20	// struct init completed by NThread__HandleException()
   128 	__asm sub esp, 20					// struct init completed by NThread__HandleException()
   343 
       
   344 	__asm call NKern__Unlock
       
   345 
   129 
   346 	__asm call NThread__HandleException
   130 	__asm call NThread__HandleException
   347 
   131 
   348 	__asm add esp, 28
   132 	__asm add esp, 28
   349 	__asm pop eax
   133 	__asm pop eax
   350 	__asm pop ecx
   134 	__asm pop ecx
   351 	__asm pop edx
   135 	__asm pop edx
   352 	__asm pop ebx
   136 	__asm pop ebx
   353 	__asm pop esi		// original ESP - ignore
   137 	__asm pop esi						// original ESP - ignore
   354 	__asm pop esi
   138 	__asm pop esi
   355 	__asm pop edi
   139 	__asm pop edi
   356 	__asm pop ebp		// original SS - ignore
   140 	__asm pop ebp						// original SS - ignore
   357 	__asm pop ds
   141 	__asm pop ds
   358 	__asm pop es
   142 	__asm pop es
   359 	__asm pop fs
   143 	__asm pop fs
   360 	__asm pop gs
   144 	__asm pop gs
   361 	__asm popfd
   145 	__asm popfd
   362 	__asm pop ebp		// original CS - ignore
   146 	__asm pop ebp						// original CS - ignore
   363 	__asm pop ebp
   147 	__asm pop ebp
   364 	__asm ret
   148 	__asm ret
   365 	}
   149 	}
   366 
   150 
   367 LONG WINAPI NThread::ExceptionFilter(EXCEPTION_POINTERS* aExc)
       
   368 //
       
   369 // Filter wrapper for main Win32 exception handler
       
   370 //
       
   371 	{
       
   372 	LONG ret = EXCEPTION_CONTINUE_SEARCH;
       
   373 
       
   374 	switch (ExceptionHandler(aExc->ExceptionRecord, aExc->ContextRecord))
       
   375 		{
       
   376 		case ExceptionContinueExecution:
       
   377 			{
       
   378 			ret = EXCEPTION_CONTINUE_EXECUTION;
       
   379 			}
       
   380 			break;
       
   381 		case ExceptionContinueSearch:
       
   382 		default:
       
   383 			{
       
   384 			}
       
   385 			break;
       
   386 		}
       
   387 
       
   388 	return ret;
       
   389 	}
       
   390 
       
   391 // From e32/commmon/win32/seh.cpp
   151 // From e32/commmon/win32/seh.cpp
   392 extern DWORD CallFinalSEHHandler(EXCEPTION_RECORD* aException, CONTEXT* aContext);
   152 extern DWORD CallFinalSEHHandler(EXCEPTION_RECORD* aException, CONTEXT* aContext);
   393 
   153 
   394 extern void DivertHook();
   154 extern void DivertHook();
   395 
   155 
   396 DWORD NThread::ExceptionHandler(EXCEPTION_RECORD* aException, CONTEXT* aContext)
   156 DWORD NThread::ExceptionHandler(EXCEPTION_RECORD* aException, CONTEXT* aContext)
   397 //
   157 //
   398 // Win32 exception handler for EPOC threads
   158 // Win32 exception handler for EPOC threads
       
   159 //
       
   160 // This is the outermost wrapper, called from ExceptionFilter() of via manual
       
   161 // interception of the Win32 exception mechanism if using a really old compiler
   399 //
   162 //
   400 	{
   163 	{
   401 	if (aException->ExceptionCode == EXCEPTION_BREAKPOINT)
   164 	if (aException->ExceptionCode == EXCEPTION_BREAKPOINT)
   402 		{
   165 		{
   403 		// Hardcoded breakpoint
   166 		// Hardcoded breakpoint
   413 		}
   176 		}
   414 
   177 
   415 	// deal with conflict between preemption and diversion
   178 	// deal with conflict between preemption and diversion
   416 	// the diversion will have been applied to the pre-exception context, not
   179 	// the diversion will have been applied to the pre-exception context, not
   417 	// the current context, and thus will get 'lost'. Wake-up of a pre-empted
   180 	// the current context, and thus will get 'lost'. Wake-up of a pre-empted
   418 	// thread with a diversion will not unlock the kernel, so need to deal with
   181 	// thread with a diversion will not unlock the kernel, so we need to deal
   419 	// the possibility that the kernel may be locked if a diversion exists
   182 	// with the possibility that the kernel may be locked if a diversion exists
   420 
       
   421 	NThread& me = *static_cast<NThread*>(TheScheduler.iCurrentThread);
   183 	NThread& me = *static_cast<NThread*>(TheScheduler.iCurrentThread);
   422 	if (me.iDiverted && me.iDivert)
   184 	if (me.iDiverting && me.iDivertFn)
   423 		{
   185 		{
   424 		// The thread is being forced to exit - run the diversion outside of Win32 exception handler
   186 		// The thread is being forced to exit - run the diversion outside of Win32 exception handler
   425 		__NK_ASSERT_ALWAYS(TheScheduler.iKernCSLocked == 1);
   187 		__NK_ASSERT_ALWAYS(TheScheduler.iKernCSLocked == 1);
   426 		aContext->Eip = (TUint32)&DivertHook;
   188 		aContext->Eip = (TUint32)&DivertHook;
   427 		}
   189 		}
   428 	else
   190 	else
   429 		{
   191 		{
   430 		if (me.iDiverted)
   192 		if (me.iDiverting)
   431 			{
   193 			{
   432 			// The thread is being prodded to pick up its callbacks.  This will happen when the
   194 			// The thread is being prodded to pick up its callbacks.  This will happen when the
   433 			// exception handler calls LeaveKernel(), so we can remove the diversion
   195 			// exception handler calls LeaveKernel(), so we can remove the diversion
   434 			__NK_ASSERT_ALWAYS(TheScheduler.iKernCSLocked == 1);
   196 			__NK_ASSERT_ALWAYS(TheScheduler.iKernCSLocked == 1);
   435 			if (aException->ExceptionAddress == &DivertHook)
   197 			if (aException->ExceptionAddress == &DivertHook)
   436 				aException->ExceptionAddress = me.iDivertReturn;
   198 				aException->ExceptionAddress = me.iDivertReturn;
   437 			me.iDiverted = EFalse;
       
   438 			me.iDivertReturn = NULL;
   199 			me.iDivertReturn = NULL;
   439 			EnterKernel(FALSE);
   200 			me.iDiverting = EFalse;
       
   201 			EnterKernel(TRUE);
   440 			}
   202 			}
   441 		else
   203 		else
   442 			{
   204 			{
   443 			EnterKernel();
   205 			EnterKernel();
   444 			TheScheduler.iKernCSLocked = 1;	// prevent pre-emption
   206 			TheScheduler.iKernCSLocked = 1;	// prevent pre-emption
   445 			}
   207 			}
   446 		
   208 
   447 		// If the kernel was already locked, this will be detected in the next stage handler
   209 		// If the kernel was already locked, this will be detected in the next stage handler
   448 		// run 2nd stage handler outside of Win32 exception context
   210 		// (NThread::Exception()), which we arrange to run outside the Win32 exception context
   449 		Win32ExcAddress = aException->ExceptionAddress;
   211 		Win32ExcAddress = aException->ExceptionAddress;
   450 		Win32ExcDataAddress = (TAny*)aException->ExceptionInformation[1];
   212 		Win32ExcDataAddress = (TAny*)aException->ExceptionInformation[1];
   451 		Win32ExcCode = aException->ExceptionCode;
   213 		Win32ExcCode = aException->ExceptionCode;
   452 		aContext->Eip = (TUint32)&Exception;
   214 		aContext->Eip = (TUint32)&Exception;
   453 		}
   215 		}
       
   216 
   454 	return ExceptionContinueExecution;
   217 	return ExceptionContinueExecution;
   455 	}
   218 	}
   456 
   219 
       
   220 LONG WINAPI NThread::ExceptionFilter(EXCEPTION_POINTERS* aExc)
       
   221 //
       
   222 // Filter wrapper for main Win32 exception handler
       
   223 //
       
   224 	{
       
   225 	LONG ret = EXCEPTION_CONTINUE_SEARCH;
       
   226 
       
   227 	switch (ExceptionHandler(aExc->ExceptionRecord, aExc->ContextRecord))
       
   228 		{
       
   229 	case ExceptionContinueExecution:
       
   230 		ret = EXCEPTION_CONTINUE_EXECUTION;
       
   231 		break;
       
   232 		
       
   233 	case ExceptionContinueSearch:
       
   234 	default:
       
   235 		break;
       
   236 		}
       
   237 
       
   238 	return ret;
       
   239 	}
       
   240 
       
   241 
       
   242 DWORD WINAPI NThread::StartThread(LPVOID aParam)
       
   243 //
       
   244 // Win32 thread function for nKern threads.
       
   245 //
       
   246 // The thread first enters this function after the nScheduler has resumed
       
   247 // it, following the context switch induced by the hand-off mutex.
       
   248 //
       
   249 // The parameter block for this thread needs to be copied into its
       
   250 // own context, before releasing the mutex and handing control back to
       
   251 // the creating thread.
       
   252 //
       
   253 	{
       
   254 	SCreateThread* init = static_cast<SCreateThread*>(aParam);
       
   255 	NThread& me = *static_cast<NThread*>(init->iHandoff.iHoldingThread);
       
   256 	me.iWinThreadId = GetCurrentThreadId();
       
   257 	SchedulerRegister(me);
       
   258 #ifdef BTRACE_FAST_MUTEX
       
   259 	BTraceContext4(BTrace::EFastMutex, BTrace::EFastMutexWait, &init->iHandoff);
       
   260 #endif
       
   261 	NKern::Unlock();
       
   262 
       
   263 	// intercept win32 exceptions in a debuggabble way
       
   264 	__try
       
   265 		{
       
   266 		// save the thread entry point and parameter block
       
   267 		const SNThreadCreateInfo& info = *init->iInfo;
       
   268 		NThreadFunction threadFunction = info.iFunction;
       
   269 		TUint8 parameterBlock[KMaxParameterBlock];
       
   270 		TAny* parameter = (TAny*)info.iParameterBlock;
       
   271 
       
   272 		if (info.iParameterBlockSize)
       
   273 			{
       
   274 			__NK_ASSERT_DEBUG(TUint(info.iParameterBlockSize) <= TUint(KMaxParameterBlock));
       
   275 			memcpy(parameterBlock, info.iParameterBlock, info.iParameterBlockSize);
       
   276 			parameter = parameterBlock;
       
   277 			}
       
   278 
       
   279 
       
   280 		// Calculate stack base
       
   281 		me.iUserStackBase = (((TLinAddr)&parameterBlock) + 0xfff) & ~0xfff;
       
   282 
       
   283 		// some useful diagnostics for debugging
       
   284 		if (Win32TraceThreadId)
       
   285 			KPrintf("Thread %T created @ 0x%x - Win32 Thread ID 0x%x", init->iHandoff.iHoldingThread, init->iHandoff.iHoldingThread, GetCurrentThreadId());
       
   286 
       
   287 #ifdef MONITOR_THREAD_CPU_TIME
       
   288 		me.iLastStartTime = 0;  // Don't count NThread setup in cpu time
       
   289 #endif
       
   290 
       
   291 		// start-up complete, release the handoff mutex, which will re-suspend us
       
   292 		NKern::FMSignal(&init->iHandoff);
       
   293 
       
   294 		// thread has been resumed: invoke the thread function
       
   295 		threadFunction(parameter);
       
   296 		}
       
   297 	__except (ExceptionFilter(GetExceptionInformation()))
       
   298 		{
       
   299 		// Do nothing - filter does all the work and hooks into EPOC
       
   300 		// h/w exception mechanism if necessary by thread diversion
       
   301 		}
       
   302 
       
   303 	NKern::Exit();
       
   304 	return 0;
       
   305 	}
       
   306 
       
   307 
       
   308 
       
   309 /**
       
   310  * Set the Win32 thread priority based on the thread type.
       
   311  * Interrupt/Event threads must be able to preempt normal
       
   312  * nKern threads, so they get a higher (Win32) priority.
       
   313  */
       
   314 static void SetPriority(HANDLE aThread, TEmulThreadType aType)
       
   315 	{
       
   316 	TInt p;
       
   317 
       
   318 	switch (aType)
       
   319 		{
       
   320 	default:
       
   321 		FAULT();
       
   322 
       
   323 	case EThreadEvent:
       
   324 		p = THREAD_PRIORITY_ABOVE_NORMAL;
       
   325 		break;
       
   326 
       
   327 	case EThreadNKern:
       
   328 		p = THREAD_PRIORITY_NORMAL;
       
   329 		break;
       
   330 		}
       
   331 
       
   332 	CheckedSetThreadPriority(aThread, p);
       
   333 	SetThreadPriorityBoost(aThread, TRUE);		// disable priority boost (for NT)
       
   334 	}
       
   335 
       
   336 /**	Create a Win32 thread for use in the emulator.
       
   337 
       
   338 	@param	aType Type of thread (Event or NKern) - determines Win32 priority
       
   339 	@param	aThreadFunc Entry point of thread
       
   340 	@param	aPtr Argument passed to entry point
       
   341 	@param	aRun TRUE if thread should be resumed immediately
       
   342 	@return	The Win32 handle to the thread, 0 if an error occurred
       
   343 
       
   344 	@pre    Call either in thread context.
       
   345 	@pre	Do not call from bare Win32 threads.
       
   346 
       
   347 	@see TEmulThreadType
       
   348  */
       
   349 EXPORT_C HANDLE CreateWin32Thread(TEmulThreadType aType, LPTHREAD_START_ROUTINE aThreadFunc, LPVOID aPtr, TBool aRun)
       
   350 	{
       
   351 	__NK_ASSERT_DEBUG(!TheScheduler.iCurrentThread || NKern::CurrentContext() == NKern::EThread);
       
   352 
       
   353 	__LOCK_HOST;
       
   354 	
       
   355 	DWORD id;
       
   356 	HANDLE handle = CreateThread(NULL , KInitialStackSize, aThreadFunc, aPtr, CREATE_SUSPENDED, &id);
       
   357 	if (handle)
       
   358 		{
       
   359 		SetPriority(handle, aType);
       
   360 		if (aRun)
       
   361 			ResumeThread(handle);
       
   362 		}
       
   363 	return handle;
       
   364 	}
       
   365 
       
   366 static HANDLE InitThread()
       
   367 //
       
   368 // Set up the initial thread and return the thread handle
       
   369 //
       
   370 	{
       
   371 	HANDLE p = GetCurrentProcess();
       
   372 	HANDLE me;
       
   373 	DWORD r = DuplicateHandle(p, GetCurrentThread(), p, &me, 0, FALSE, DUPLICATE_SAME_ACCESS);
       
   374 	__NK_ASSERT_ALWAYS(r != 0);						// r is zero on error
       
   375 	SetPriority(me, EThreadNKern);
       
   376 	return me;
       
   377 	}
       
   378 
       
   379 TInt NThread::Create(SNThreadCreateInfo& aInfo, TBool aInitial)
       
   380 	{
       
   381 	iWinThread = NULL;
       
   382 	iWinThreadId = 0;
       
   383 	iScheduleLock = NULL;
       
   384 	iInKernel = 1;
       
   385 	iDivertFn = NULL;
       
   386 	iWakeup = aInitial ? ERelease : EResumeLocked;	// mark new threads as created (=> win32 suspend)
       
   387 
       
   388 	TInt r = NThreadBase::Create(aInfo, aInitial);
       
   389 	if (r != KErrNone)
       
   390 		return r;
       
   391 
       
   392 	// the rest has to be all or nothing, we must complete it
       
   393 	iScheduleLock = CreateEventA(NULL, FALSE, FALSE, NULL);
       
   394 	if (iScheduleLock == NULL)
       
   395 		return Emulator::LastError();
       
   396 
       
   397 	if (aInitial)
       
   398 		{
       
   399 		iWinThread = InitThread();
       
   400 		FastCounterInit();
       
   401 #ifdef MONITOR_THREAD_CPU_TIME
       
   402 		iLastStartTime = NKern::FastCounter();
       
   403 #endif
       
   404 		iUserStackBase = (((TLinAddr)&r) + 0xfff) & ~0xfff; // base address of stack
       
   405 		SchedulerInit(*this);
       
   406 		return KErrNone;
       
   407 		}
       
   408 
       
   409 	// create the thread proper
       
   410 	//
       
   411 	SCreateThread start;
       
   412 	start.iInfo = &aInfo;
       
   413 	iWinThread = CreateWin32Thread(EThreadNKern, &StartThread, &start, FALSE);
       
   414 	if (iWinThread == NULL)
       
   415 		{
       
   416 		r = Emulator::LastError();
       
   417 		CloseHandle(iScheduleLock);
       
   418 		return r;
       
   419 		}
       
   420 
       
   421 #ifdef BTRACE_THREAD_IDENTIFICATION
       
   422 	BTrace4(BTrace::EThreadIdentification, BTrace::ENanoThreadCreate, this);
       
   423 #endif
       
   424 	// switch to the new thread to hand over the parameter block
       
   425 	NKern::Lock();
       
   426 	ForceResume();	// mark the thread as ready
       
   427 	// give the thread ownership of the handoff mutex
       
   428 	start.iHandoff.iHoldingThread = this;
       
   429 	iHeldFastMutex = &start.iHandoff;
       
   430 	Suspend(1);		// will defer as holding a fast mutex (implicit critical section)
       
   431 	// do the hand-over
       
   432 	start.iHandoff.Wait();
       
   433 	start.iHandoff.Signal();
       
   434 	NKern::Unlock();
       
   435 
       
   436 	return KErrNone;
       
   437 	}
       
   438 
       
   439 
       
   440 
   457 void NThread::Diverted()
   441 void NThread::Diverted()
   458 //
   442 //
   459 // Forced diversion go through here, in order to 'enter' the kernel
   443 // This function is called in the context of a thread that is being diverted.
       
   444 // This can be for either of two reasons: if iDivertFn has been set, that
       
   445 // function will be called and is not expected to return i.e.  it should force
       
   446 // the thread to exit. Otherwise, the thread will make a null trip through the
       
   447 // kernel, causing it to run pending user-mode callbacks on the way out.
       
   448 //
       
   449 // On entry, the kernel is locked and interrupts enabled
   460 //
   450 //
   461 	{
   451 	{
   462 	NThread& me = *static_cast<NThread*>(TheScheduler.iCurrentThread);
   452 	NThread& me = *static_cast<NThread*>(TheScheduler.iCurrentThread);
   463 	__NK_ASSERT_ALWAYS(TheScheduler.iKernCSLocked == 1);
   453 	__NK_ASSERT_ALWAYS(TheScheduler.iKernCSLocked == 1);
   464 	__NK_ASSERT_ALWAYS(me.iDiverted);
   454 	__NK_ASSERT_ALWAYS(me.iInKernel == 0);
   465 	NThread::TDivert divert = me.iDivert;
   455 	__NK_ASSERT_ALWAYS(me.iDiverting);
   466 	me.iDiverted = EFalse;
   456 	NThread::TDivert divertFn = me.iDivertFn;
   467 	me.iDivert = NULL;
   457 	me.iDivertFn = NULL;
   468 	me.iDivertReturn = NULL;
   458 	me.iDivertReturn = NULL;
   469 	EnterKernel(FALSE);
   459 	me.iDiverting = EFalse;
   470 	if (divert)
   460 
   471 		divert();	// does not return
   461 	EnterKernel(TRUE);
       
   462 
       
   463 	if (divertFn)
       
   464 		divertFn();					// does not return
       
   465 
   472 	NKern::Unlock();
   466 	NKern::Unlock();
   473 	LeaveKernel();
   467 	LeaveKernel();
   474 	}
   468 	}
   475 
   469 
   476 void NThread__Diverted()
   470 void NThread__Diverted()
   486 	//		| frame pointer  |
   480 	//		| frame pointer  |
   487 	//		| flags			 |
   481 	//		| flags			 |
   488 	//		| saved eax		 |
   482 	//		| saved eax		 |
   489 	//		| saved ecx		 |
   483 	//		| saved ecx		 |
   490 	//      | saved edx		 |
   484 	//      | saved edx		 |
   491 	//		
   485 	//
   492 	__asm push eax					// reserve word for return address
   486 	__asm push eax					// reserve word for return address
   493 	__asm push ebp
   487 	__asm push ebp
   494 	__asm mov ebp, esp 
   488 	__asm mov ebp, esp
   495 	__asm pushfd
   489 	__asm pushfd
   496 	__asm push eax
   490 	__asm push eax
   497 	__asm push ecx
   491 	__asm push ecx
   498 	__asm push edx
   492 	__asm push edx
   499 	__asm mov eax, [TheScheduler.iCurrentThread]
   493 	__asm mov eax, [TheScheduler.iCurrentThread]
   508 	__asm ret
   502 	__asm ret
   509 	}
   503 	}
   510 
   504 
   511 
   505 
   512 void NThread::ApplyDiversion()
   506 void NThread::ApplyDiversion()
       
   507 //
       
   508 // Arrange that the thread will be diverted when next it runs.
       
   509 // This can be for either of two reasons: if iDivertFn has been set,
       
   510 // that function will be called and is not expected to return i.e.
       
   511 // it should force the thread to exit. Otherwise, the thread will
       
   512 // make a null trip through the kernel, causing it to run pending
       
   513 // user-mode callbacks on the way out.
       
   514 //
       
   515 // This uses the Win32 CONTEXT functions to change the thread's PC
       
   516 // so that execution restarts at DivertHook ...
       
   517 //
   513 	{
   518 	{
   514 	// Called with interrupts disabled and kernel locked
   519 	// Called with interrupts disabled and kernel locked
   515 	__NK_ASSERT_ALWAYS(TheScheduler.iKernCSLocked == 1);
   520 	__NK_ASSERT_ALWAYS(TheScheduler.iKernCSLocked == 1);
   516 	if (iDiverted)
   521 	__NK_ASSERT_ALWAYS(iDivertReturn == NULL || iDiverting);
       
   522 
       
   523 	if (iDiverting)
   517 		return;
   524 		return;
       
   525 
   518 	CONTEXT c;
   526 	CONTEXT c;
   519 	c.ContextFlags=CONTEXT_FULL;
   527 	c.ContextFlags = CONTEXT_CONTROL;
   520 	GetThreadContext(iWinThread, &c);
   528 	CheckedGetThreadContext(iWinThread, &c);
   521 	__NK_ASSERT_ALWAYS(iDivertReturn == NULL);
       
   522 	iDivertReturn = (TAny*)c.Eip;
   529 	iDivertReturn = (TAny*)c.Eip;
   523 	c.Eip=(TUint32)&DivertHook;
   530 	c.Eip = (TUint32)&DivertHook;
   524 	SetThreadContext(iWinThread, &c);
   531 	c.ContextFlags = CONTEXT_CONTROL;
   525 	iDiverted = ETrue;
   532 	CheckedSetThreadContext(iWinThread, &c);
   526 	}
   533 	iDiverting = ETrue;
   527 
   534 	}
   528 void NThread::Divert(TDivert aDivert)
   535 
   529 //
   536 void NThread::Divert(TDivert aDivertFn)
   530 // Divert the thread from its current path
   537 //
   531 // The diversion function is called with the kernel locked and interrupts enabled
   538 // Arrange that the thread will exit by calling aDivertFn when next
   532 //
   539 // it runs.  The diversion function will be called with the kernel
   533 	{
   540 // locked and interrupts enabled.  It is not expected to return.
   534 	iDivert = aDivert;
   541 //
       
   542 	{
       
   543 	iDivertFn = aDivertFn;
   535 	if (iWakeup == EResume)
   544 	if (iWakeup == EResume)
   536 		iWakeup = EResumeDiverted;
   545 		iWakeup = EResumeDiverted;
   537 	else
   546 	else
   538 		__NK_ASSERT_ALWAYS(iWakeup == ERelease);
   547 		__NK_ASSERT_ALWAYS(iWakeup == ERelease);
   539 	}
   548 	}
   542 //
   551 //
   543 // Diversion used to terminate 'stillborn' threads.
   552 // Diversion used to terminate 'stillborn' threads.
   544 // On entry, kernel is locked, interrupts are enabled and we hold an interlock mutex
   553 // On entry, kernel is locked, interrupts are enabled and we hold an interlock mutex
   545 //
   554 //
   546 	{
   555 	{
   547 	NThreadBase& me=*TheScheduler.iCurrentThread;
   556 	NThreadBase& me = *TheScheduler.iCurrentThread;
   548 	me.iHeldFastMutex->Signal();	// release the interlock
   557 	me.iHeldFastMutex->Signal();	// release the interlock
   549 	me.iNState=EDead;				// mark ourselves as dead which will take thread out of scheduler
   558 	me.iNState = EDead;				// mark ourselves as dead which will take thread out of scheduler
   550 	TheScheduler.Remove(&me);
   559 	TheScheduler.Remove(&me);
   551 	RescheduleNeeded();
   560 	RescheduleNeeded();
   552 	TScheduler::Reschedule();	// this won't return
   561 	TScheduler::Reschedule();	// this won't return
   553 	FAULT();
   562 	FAULT();
   554 	}
   563 	}
   556 void NThread::Stillborn()
   565 void NThread::Stillborn()
   557 //
   566 //
   558 // Called if the new thread creation was aborted - so it will not be killed in the usual manner
   567 // Called if the new thread creation was aborted - so it will not be killed in the usual manner
   559 //
   568 //
   560 // This function needs to exit the thread synchronously as on return we will destroy the thread control block
   569 // This function needs to exit the thread synchronously as on return we will destroy the thread control block
   561 // Thus wee need to use an interlock that ensure that the target thread runs the exit handler before we continue
   570 // Thus we need to use an interlock that ensure that the target thread runs the exit handler before we continue
   562 //
   571 //
   563 	{
   572 	{
   564 	// check if the Win32 thread was created
   573 	// check if the Win32 thread was created
   565 	if (!iWinThread)
   574 	if (!iWinThread)
   566 		return;
   575 		return;
   568 	NKern::Lock();
   577 	NKern::Lock();
   569 	Divert(&ExitSync);
   578 	Divert(&ExitSync);
   570 	ForceResume();
   579 	ForceResume();
   571 	// create and assign mutex to stillborn thread
   580 	// create and assign mutex to stillborn thread
   572 	NFastMutex interlock;
   581 	NFastMutex interlock;
   573 	interlock.iHoldingThread=this;
   582 	interlock.iHoldingThread = this;
   574 	iHeldFastMutex=&interlock;
   583 	iHeldFastMutex = &interlock;
   575 	interlock.Wait();			// interlock on thread exit handler
   584 	interlock.Wait();			// interlock on thread exit handler
   576 	interlock.Signal();
   585 	interlock.Signal();
   577 	NKern::Unlock();
   586 	NKern::Unlock();
   578 	}
   587 	}
   579 
   588 
   582 // Diversion used to terminate 'killed' threads.
   591 // Diversion used to terminate 'killed' threads.
   583 // On entry, kernel is locked and interrupts are enabled
   592 // On entry, kernel is locked and interrupts are enabled
   584 //
   593 //
   585 	{
   594 	{
   586 	NThreadBase& me = *TheScheduler.iCurrentThread;
   595 	NThreadBase& me = *TheScheduler.iCurrentThread;
       
   596 	__NK_ASSERT_ALWAYS(static_cast<NThread&>(me).iInKernel > 0);
   587 	me.iCsCount = 0;
   597 	me.iCsCount = 0;
   588 	__NK_ASSERT_ALWAYS(static_cast<NThread&>(me).iInKernel>0);
       
   589 	me.Exit();
   598 	me.Exit();
   590 	}
   599 	}
   591 
   600 
       
   601 inline void NThread::DoForceExit()
       
   602 	{
       
   603 	__NK_ASSERT_DEBUG(TheScheduler.iKernCSLocked);
       
   604 	Divert(&ExitAsync);
       
   605 	}
       
   606 
       
   607 void NThreadBase::ForceExit()
       
   608 //
       
   609 // Called to force the thread to exit when it resumes
       
   610 //
       
   611 	{
       
   612 	static_cast<NThread*>(this)->DoForceExit();
       
   613 	}
       
   614 
       
   615 void NThreadBase::OnExit()
       
   616 	{
       
   617 	}
       
   618 
   592 void NThreadBase::OnKill()
   619 void NThreadBase::OnKill()
   593 	{
   620 	{
   594 	}
   621 	}
   595 
   622 
   596 void NThreadBase::OnExit()
       
   597 	{
       
   598 	}
       
   599 
       
   600 inline void NThread::DoForceExit()
       
   601 	{
       
   602 	__NK_ASSERT_DEBUG(TheScheduler.iKernCSLocked);
       
   603 //
       
   604 	Divert(&ExitAsync);
       
   605 	}
       
   606 
       
   607 void NThreadBase::ForceExit()
       
   608 //
       
   609 // Called to force the thread to exit when it resumes
       
   610 //
       
   611 	{
       
   612 	static_cast<NThread*>(this)->DoForceExit();
       
   613 	}
       
   614 
       
   615 //
       
   616 // We need a global lock in the emulator to avoid scheduling reentrancy problems with the host
       
   617 // in particular, some host API calls acquire host mutexes, preempting such services results
       
   618 // in suspension of those threads which can cause deadlock if another thread requires that host
       
   619 // mutex.
       
   620 //
       
   621 // Because thread dreaction and code loading also require the same underlying mutex (used
       
   622 // by NT to protect DLL entrypoint calling), this would be rather complex with a fast mutex.
       
   623 // For now, keep it simple and use the preemption lock. Note that this means that the
       
   624 // MS timer DFC may be significantly delayed when loading large DLL trees, for example.
       
   625 //
       
   626 
       
   627 void SchedulerLock()
       
   628 //
       
   629 // Acquire the global lock. May be called before scheduler running, so handle that case
       
   630 //
       
   631 	{
       
   632 	if (TheScheduler.iCurrentThread)
       
   633 		{
       
   634 		EnterKernel();
       
   635 		NKern::Lock();
       
   636 		}
       
   637 	}
       
   638 
       
   639 void SchedulerUnlock()
       
   640 //
       
   641 // Release the global lock. May be called before scheduler running, so handle that case
       
   642 //
       
   643 	{
       
   644 	if (TheScheduler.iCurrentThread)
       
   645 		{
       
   646 		NKern::Unlock();
       
   647 		LeaveKernel();
       
   648 		}
       
   649 	}
       
   650