//////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // Note: // using System; using System.Collections; using System.Reflection; using System.Threading; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Microsoft.Bartok.Runtime; using Microsoft.Singularity.Io; using Microsoft.Singularity.V1.Services; using Microsoft.Singularity.Eventing; [assembly: AssemblyTitle("Microsoft.Singularity")] [assembly: AssemblyProduct("Microsoft Research Singularity Runtime")] [assembly: AssemblyCompany("Microsoft Corporation")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyKeyFile("public.snk")] [assembly: AssemblyDelaySign(true)] namespace Microsoft.Singularity { [NoCCtor] [CLSCompliant(false)] [AccessedByRuntime("referenced from hal.cpp")] public class AppRuntime { // Note: This function is called by Hal.cpp. [AccessedByRuntime("referenced from hal.cpp")] public static unsafe int AppStart(Type userClass) { System.GCs.Transitions.ThreadStart(); int result = 0; string arg0 = "(unknown)"; try { Tracing.Log(Tracing.Audit, "Runtime.Main()"); // Initialize the primitive runtime, which calls the // class constructor for Runtime(). VTable.Initialize((RuntimeType)typeof(AppRuntime)); //VTable.ParseArgs(args); Tracing.Log(Tracing.Audit, "Enabling GC Heap"); GC.EnableHeap(); Controller.InitializeSystem(); GCProfilerLogger.StartProfiling(); InitializeConsole(); SetDebuggerPresence(DebugService.IsDebuggerPresent()); int argCount = 0; int argMaxLen = 0; for (;; argCount++) { int len = ProcessService.GetStartupArg(argCount, null, 0); if (len == 0) { break; } if (argMaxLen < len) { argMaxLen = len; } } char[] argArray = new char [argMaxLen]; string[] args = new string[argCount]; for (int arg = 0; arg < argCount; arg++) { fixed (char *argptr = &argArray[0]) { int len = ProcessService.GetStartupArg(arg, argptr, argArray.Length); args[arg] = String.StringCTOR(argptr, 0, len); if (arg == 0) arg0 = args[arg]; } } #if DEBUG || true // Record the first argument passed to this program, under the assumption that // this is the application name. We use this string in DebugStub.WriteLine. // Also, if the name has an extension, such as ".x86", chop it off. // Also chop off any path prefix, such as "/init/". appName = arg0; int index = appName.LastIndexOf('.'); if (index != -1) appName = appName.Substring(0, index); index = appName.LastIndexOf('/'); if (index != -1) appName = appName.Substring(index + 1); // The default DebugName value for the main thread is "main"; // apps can override this by setting Thread.CurrentThread.DebugName. Thread mainThread = Thread.CurrentThread; if (mainThread != null) { mainThread.DebugName = "main"; } #endif if (userClass != null) { VTable.initType((RuntimeType)userClass); } result = CallMain(args); if (!MainReturnsInt()) result = 0; Tracing.Log(Tracing.Audit, "Main thread exited [{0}]", (UIntPtr)unchecked((uint)result)); } catch (Exception e) { Tracing.Log(Tracing.Fatal, "Failed with exception {0}.{1}", e.GetType().Namespace, e.GetType().Name); Tracing.Log(Tracing.Trace, "Exception message was {0}", e.ToString()); TopLevelException(e); result = -1; } Thread.RemoveThread(Thread.CurrentThread.threadIndex); Thread.JoinAll(); try { FinalizeConsole(); } catch (Exception e) { Tracing.Log(Tracing.Fatal, "An exception occurred while shutting down the console: {0}", e.ToString()); } Controller.Finalize(); Tracing.Log(Tracing.Audit, "Runtime shutdown started."); VTable.Shutdown(result); Tracing.Log(Tracing.Audit, "Runtime exiting [{0}]", (UIntPtr)unchecked((uint)result)); return result; } /// /// This method runs when the "main" thread terminates by throwing an exception. /// It is a separate method, rather than simply code within the AppStart method, /// in order to make life easier during debugging. /// /// private static void TopLevelException(Exception/*!*/ ex) { DebugStub.WriteLine("AppRuntime: Main app thread terminated with exception:"); for (Exception focus = ex; focus != null; focus = focus.InnerException) { DebugStub.WriteLine("{0}: {1}", __arglist(focus.GetType().FullName, focus.Message)); } } #if DEBUG || true /// /// Returns the name of the application, as determined by the first parameter /// passed in the argv block. This property is only present on DEBUG builds /// (Debug and Prototype). It is provided for DebugStub.WriteLine, to provide /// useful debugging spew. /// public static string AppName { [NoHeapAllocation] get { return appName; } } private static string appName; #endif [AccessedByRuntime("output to header : defined in hal.cpp")] [MethodImpl(MethodImplOptions.InternalCall)] [StackBound(256)] private static extern int CallMain(String[] args); [AccessedByRuntime("output to header: defined in hal.cpp")] [MethodImpl(MethodImplOptions.InternalCall)] [StackBound(256)] private static extern bool MainReturnsInt(); [AccessedByRuntime("output to header: defined in hal.cpp")] [MethodImpl(MethodImplOptions.InternalCall)] [StackBound(256)] private static extern void SetDebuggerPresence(bool debuggerPresent); internal static void Shutdown(int exitCode) { // // Gracefully close down the process. // Tracing.Log(Tracing.Audit, "Runtime.Shutdown({0})", (UIntPtr)unchecked((uint)exitCode)); DebugStub.WriteLine("Runtime.Shutdown({0})", __arglist(exitCode)); VTable.Shutdown(exitCode); Tracing.Log(Tracing.Audit, "Runtime.Shutdown({0}) terminating", (UIntPtr)unchecked((uint)exitCode)); ProcessService.Stop(exitCode); } internal static void Stop(int exitCode) { // // Halt the process immediately. // Tracing.Log(Tracing.Audit, "Runtime.Stop({0})", (UIntPtr)unchecked((uint)exitCode)); DebugStub.WriteLine("Runtime.Stop({0})", __arglist(exitCode)); ProcessService.Stop(exitCode); } ////////////////////////////////////////////////////////////////////// // [NoHeapAllocation] public static UIntPtr AddressOf(Object o) { return Magic.addressOf(o); } [NoHeapAllocation] public static UIntPtr SizeOf(Object o) { return System.GCs.ObjectLayout.Sizeof(o); } public static void InitType(Type ty) { VTable.initType((RuntimeType) ty); } public static void DumpPageTable() { System.GCs.PageTable.Dump("PageTable"); } ////////////////////////////////////////////////////////////////////// // public static bool EnableGCVerify { get { return VTable.enableGCVerify; } set { VTable.enableGCVerify = value; } } public static bool EnableGCAccounting { get { return VTable.enableGCAccounting; } set { VTable.enableGCAccounting = value; if (value == true) { System.GCs.MemoryAccounting.Initialize(GC.gcType); } } } public static uint GCPerfCounter { get { return System.GC.perfCounter; } set { System.GC.perfCounter = value; } } /// /// This stub method is provided for so that System.Console.dll can override it for those /// apps that want a console. This is necessary, in order to initialize and shutdown the /// console at the right time. /// private static void InitializeConsole() { } /// /// This stub method is provided for so that System.Console.dll can override it for those /// apps that want a console. This is necessary, in order to initialize and shutdown the /// console at the right time. /// private static void FinalizeConsole() { } } }