private static unsafe void ThreadStub(int threadIndex) { Transitions.ThreadStart(); GC.ThreadStartNotification(threadIndex); Thread currentThread = threadTable[threadIndex]; if (AddThread(threadIndex)) { // Log Thread Start. Tracing.Log(Tracing.Audit, "ThreadStub(atid={0}) Entered", (UIntPtr) unchecked ((uint)threadIndex)); ThreadStart startFun = currentThread.threadStart; try { startFun(); } catch (Exception uncaughtException) { // Save Uncaught Exception in Thread instance. currentThread.lastUncaughtException = uncaughtException; // Dump (possibly nested) Exceptions to the Debugger. // Note: The first line identifies the outer exception, // later lines identify the inner exceptions nesting level. string formatString; uint nestingLevel = 0; Exception currentException = uncaughtException; formatString = "Thread{0,3} Outer" + " Exception: Type '{2}', Message '{3}'."; while (currentException != null) { DebugStub.WriteLine( formatString, __arglist(threadIndex, nestingLevel, currentException.GetType().ToString(), currentException.Message)); currentException = currentException.InnerException; formatString = "Thread{0,3} Inner{1,2}" + " Exception: Type '{2}', Message '{3}'."; if (++nestingLevel > 16) { break; } } // Assert (always asserts as exception is never null here). string message = uncaughtException.Message; if (message == null) { message = String.Empty; } VTable.Assert(uncaughtException == null, "Thread " + threadIndex + " failed with Exception Type '" + uncaughtException.GetType().ToString() + "', Message '" + message + "'."); } // Log Thread Exit. Tracing.Log(Tracing.Audit, "ThreadStub(atid={0}) Exiting", (UIntPtr) unchecked ((uint)threadIndex)); } currentThread.joinEvent.Set(); RemoveThread(threadIndex); GC.DeadThreadNotification(currentThread); bool disabled = Processor.DisableLocalPreemption(); // REVIEW: this is a dangerous locking strategy as the transition code // may decide it needs to wake up another thread. Thread.threadTableLock.Acquire(currentThread); try { Transitions.ThreadEnd(threadIndex); // You may not do any calls out of proc after this point! threadTable[threadIndex] = null; Transitions.DeadThreadNotification(threadIndex); } finally { Thread.threadTableLock.Release(currentThread); Processor.RestoreLocalPreemption(disabled); } }