/////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity - Singularity ABI // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: ProcessHandle.cs // // Note: // using System; using System.Collections; using System.Runtime.CompilerServices; using System.Threading; using Microsoft.Singularity; using Microsoft.Singularity.Io; using Microsoft.Singularity.Loader; using Microsoft.Singularity.Memory; using Microsoft.Singularity.V1.Services; using Microsoft.Singularity.V1.Security; using Microsoft.Singularity.Security; using Microsoft.Singularity.X86; using Microsoft.Singularity.V1.Types; using InternalProcessState = System.Threading.ProcessState; using ExternalProcessState = Microsoft.Singularity.V1.Processes.ProcessState; namespace Microsoft.Singularity.V1.Processes { public enum ProcessState { Active, Suspended, Stopped, } //| [CLSCompliant(false)] public struct ProcessHandle { public readonly UIntPtr id; public static readonly ProcessHandle Zero = new ProcessHandle(); internal ProcessHandle(UIntPtr id) { this.id = id; } [ExternalEntryPoint] public static unsafe bool CreateImpl( char *cmdName, int cmdLength, char *actionName, int actionLength, char *role, int roleLength, ProcessHandle *handle) { return Create(cmdName, cmdLength, actionName, actionLength, role, roleLength, out *handle); } public static unsafe bool Create(char *cmdName, int cmdLength, char *actionName, int actionLength, char *role, int roleLength, out ProcessHandle handle) { Kernel.Waypoint(550); string mycmd = null; if (cmdName != null && cmdLength > 0) { mycmd = String.StringCTOR(cmdName, 0, cmdLength); } else { //should never happen DebugStub.Break(); } string myrole = null; if (role != null && roleLength > 0) { myrole = String.StringCTOR(role, 0, roleLength); } string myaction = null; if (actionName != null && actionLength > 0) { myaction = String.StringCTOR(actionName, 0, actionLength); } Kernel.Waypoint(551); // // Find image to run. // Manifest appManifest; IoMemory image = Binder.LoadImage(Thread.CurrentProcess, mycmd, out appManifest); Kernel.Waypoint(552); if (image != null && image.Length > 0 && appManifest != null) { // // Check manifest to see what resources are needed // // // Create a Managed process, and a handle in the current // process to hold it. // // REVIEW create empty args array so that we // do not need to change the process constructor; String[] myargs; if (myaction != null) { myargs = new String[2]; myargs[1] = myaction; } else myargs = new String[1]; myargs[0] = mycmd; Process process = new Process(Thread.CurrentProcess, image, myrole, myargs, appManifest); // // Check manifest to see what resources are needed // int epCount = appManifest.SetEndpoints(process, myaction); #if VERBOSE DebugStub.WriteLine("new process create: endpoints from manifest {0}", __arglist( epCount)); #endif int boolCount, longCount, stringCount, stringArrayCount; bool ok = appManifest.GetParameterCounts(myaction, out boolCount, out longCount, out stringCount, out stringArrayCount); //DebugStub.WriteLine("ProcessHandle: args strings={0}, longs={1}, bools={2}", // __arglist(stringCount, longCount, boolCount)); process.SetBoolArgCount(boolCount); process.SetLongArgCount(longCount); process.SetStringArgCount(stringCount); process.SetStringArrayArgCount(stringArrayCount); handle = new ProcessHandle( Thread.CurrentProcess.AllocateHandle(process)); Tracing.Log(Tracing.Debug, "ProcessHandle.Create(out id={0:x8})", handle.id); Kernel.Waypoint(553); IoMemory.Release(image); appManifest = null; return true; } Tracing.Log(Tracing.Debug, "ProcessHandle.Create() failed"); handle = new ProcessHandle(); Kernel.Waypoint(554); return false; } [ExternalEntryPoint] public static unsafe bool CreateImpl( char *args, int *argLengths, int argCount, char *role, int roleLength, int endpointCount, ProcessHandle * handle) { return Create(args, argLengths, argCount, role, roleLength, endpointCount, out *handle); } public static unsafe bool Create(char *args, int *argLengths, int argCount, char *role, int roleLength, int endpointCount, out ProcessHandle handle) { Kernel.Waypoint(550); // // Create a kernel String[] object populated with the argument // values passed in from userland. // String[] arguments = new String[argCount]; int offset = 0; for (int argument = 0; argument < argCount; argument++) { arguments[argument] = String.StringCTOR( args, offset, argLengths[argument]); offset += argLengths[argument]; } string myrole = null; if (role != null && roleLength > 0) { myrole = String.StringCTOR(role, 0, roleLength); } Kernel.Waypoint(551); // haryadi -- this is currently a hack-kind of hook // if the app to be run is HelloMp then we intercept control // and run our own MpLoad, the Ap processor will run the HelloMp if (arguments.Length != 0 && arguments[0] == "hellomp") { // IoMemory mpImage = Binder.HelloMpLoadImage(); IoMemory mpImage = Binder.LoadRawImage("/init/hellomp", "hellomp.x86"); IoMemory mpLoadedImage; // mpLoadedImage should have physical address PEImage mpPeImage = PEImage.HelloMpLoad(Thread.CurrentProcess, mpImage, out mpLoadedImage); UIntPtr mpEntryPoint = mpPeImage.GetEntryPoint(mpLoadedImage); DebugStub.WriteLine ("HSG: Sending ApImage e.{0:x}", __arglist(mpEntryPoint)); // send IPI bool iflag = Processor.DisableInterrupts(); MpExecution.PutIntrApImage(1, mpEntryPoint); MpExecution.SendApImage(0,1); Processor.RestoreInterrupts(iflag); // uncomment this if want to run this on BSP // Processor.MpCallEntryPoint(mpEntryPoint); // return failure to Shell handle = new ProcessHandle(); return false; } // haryadi -- intercept TestMpAbi if (arguments.Length != 0 && arguments[0] == "testmpabi") { IoMemory mpImage = Binder.LoadRawImage("/init/testmpabi", "testmpabi.x86"); IoMemory mpLoadedImage; // mpLoadedImage should have physical address bool isForMp = true; PEImage mpPeImage = PEImage.Load(Thread.CurrentProcess, mpImage, out mpLoadedImage, isForMp); UIntPtr mpEntryPoint = mpPeImage.GetEntryPoint(mpLoadedImage); // prepare IPI // MpExecution.ApImage apImage = new MpExecution.ApImage(); // apImage.virtAddr = mpLoadedImage.VirtualAddress; // apImage.phyAddr = mpLoadedImage.PhysicalAddress.Value; // apImage.length = (UIntPtr)mpLoadedImage.Length; // apImage.entryPoint = mpEntryPoint; DebugStub.WriteLine ("HSG: Sending ApImage e.{0:x}", __arglist(mpEntryPoint)); // send IPI bool iflag = Processor.DisableInterrupts(); MpExecution.PutIntrApImage(1, mpEntryPoint); MpExecution.SendApImage(0,1); Processor.RestoreInterrupts(iflag); // uncomment this if want to run this on BSP // Processor.MpCallEntryPoint(mpEntryPoint); // return failure to Shell handle = new ProcessHandle(); return false; } // // Find image to run. // Manifest appManifest; IoMemory image = Binder.LoadImage(Thread.CurrentProcess, arguments[0], out appManifest); Kernel.Waypoint(552); if (image != null && image.Length > 0 && appManifest != null) { // // Check manifest to see what resources are needed // // // Create a Managed process, and a handle in the current // process to hold it. // Process process = new Process(Thread.CurrentProcess, image, myrole, arguments, appManifest); // // Check manifest to see what resources are needed // int epCount = appManifest.SetEndpoints(process,null); #if VERBOSE DebugStub.WriteLine("endpoints passed in={0}, endpoints from manifest {1}", __arglist(endpointCount, epCount)); #endif if (epCount == 0) { process.SetEndpointCount(endpointCount); } int boolCount, longCount, stringCount, stringArrayCount; bool ok = appManifest.GetParameterCounts(null, out boolCount, out longCount, out stringCount, out stringArrayCount); //DebugStub.WriteLine("ProcessHandle: args strings={0}, longs={1}, bools={2}", // __arglist(stringCount, longCount, boolCount)); process.SetBoolArgCount(boolCount); process.SetLongArgCount(longCount); process.SetStringArgCount(stringCount); process.SetStringArrayArgCount(stringArrayCount); handle = new ProcessHandle( Thread.CurrentProcess.AllocateHandle(process)); Tracing.Log(Tracing.Debug, "ProcessHandle.Create(out id={0:x8})", handle.id); Kernel.Waypoint(553); IoMemory.Release(image); appManifest = null; return true; } Tracing.Log(Tracing.Debug, "ProcessHandle.Create() failed"); handle = new ProcessHandle(); Kernel.Waypoint(554); return false; } /// /// Given 2 system types generate and initialize the two endpoints of /// a channel. The imp side will be set in the processes startup endpoint array /// at position "index". The exp side will be bound to a service based on global policy /// [ExternalEntryPoint] public static unsafe bool BindToService( ProcessHandle handle, SystemType impType, SystemType expType, char *contractChars, int contractLen, int startState, int index) { //convert contract to string if (contractLen == 0 ) return false; Process process = HandleTable.GetHandle(handle.id) as Process; string contract = String.StringCTOR(contractChars, 0, contractLen); if (contract == null) return false; return Binder.BindToService(process, impType, expType, contract, startState, index); } [ExternalEntryPoint] public static unsafe bool SetStartupEndpoint(ProcessHandle handle, int index, SharedHeapService.Allocation * endpoint) { Tracing.Log(Tracing.Debug, "ProcessHandle.SetStartupEndpoint(id={0:x8}, ndx={1}, ep={2:x8})", handle.id, (UIntPtr)index, (UIntPtr)endpoint); // // Convert the handle to a process; set the endpoint. // SharedHeap.Allocation *ep = (SharedHeap.Allocation *)endpoint; Process process = HandleTable.GetHandle(handle.id) as Process; return process.SetEndpoint(index, ref ep); } [ExternalEntryPoint] public static void Dispose(ProcessHandle handle) { Tracing.Log(Tracing.Debug, "ProcessHandle.Dispose(id={0:x8})", handle.id); // // Releasing the handle will allow the process to be // garbage-collected. // Thread.CurrentProcess.ReleaseHandle(handle.id); } [ExternalEntryPoint] public static bool Start(ProcessHandle handle) { Tracing.Log(Tracing.Debug, "ProcessHandle.Start(id={0:x8})", handle.id); // // Convert the handle to a process; call Start method. // Process process = HandleTable.GetHandle(handle.id) as Process; return process.Start(); } [ExternalEntryPoint] public static unsafe void JoinImpl(ProcessHandle handle, bool * started) { Join(handle, out *started); } public static void Join(ProcessHandle handle, out bool started) { Tracing.Log(Tracing.Debug, "ProcessHandle.Join(id={0:x8})", handle.id); // // Convert the handle to a process; call Join method. // Process process = HandleTable.GetHandle(handle.id) as Process; process.Join(out started); } [ExternalEntryPoint] public static unsafe bool JoinImpl( ProcessHandle handle, TimeSpan timeout, bool * started) { return Join(handle, timeout, out *started); } public static bool Join(ProcessHandle handle, TimeSpan timeout, out bool started) { Tracing.Log(Tracing.Debug, "ProcessHandle.Join(id={0:x8})", handle.id); // // Convert the handle to a process; call Join method. // Process process = HandleTable.GetHandle(handle.id) as Process; bool ret = process.Join(timeout, out started); return ret; } [ExternalEntryPoint] public static unsafe bool JoinImpl( ProcessHandle handle, SchedulerTime stop, bool * started) { return Join(handle, stop, out *started); } public static bool Join(ProcessHandle handle, SchedulerTime stop, out bool started) { Tracing.Log(Tracing.Debug, "ProcessHandle.Join(id={0:x8})", handle.id); // // Convert the handle to a process; call Join method. // Process process = HandleTable.GetHandle(handle.id) as Process; bool ret = process.Join(stop, out started); return ret; } [ExternalEntryPoint] public static bool Suspend(ProcessHandle handle, bool recursive) { Tracing.Log(Tracing.Debug, "ProcessHandle.Suspend(id={0:x8})", handle.id); // // Convert the handle to a process; call Suspend method. // Process process = HandleTable.GetHandle(handle.id) as Process; return process.Suspend(recursive); } [ExternalEntryPoint] public static bool Resume(ProcessHandle handle, bool recursive) { Tracing.Log(Tracing.Debug, "ProcessHandle.Resume(id={0:x8})", handle.id); // // Convert the handle to a process; call Resume method. // Process process = HandleTable.GetHandle(handle.id) as Process; return process.Resume(recursive); } [ExternalEntryPoint] public static void Stop(ProcessHandle handle, int exitcode) { Tracing.Log(Tracing.Debug, "ProcessHandle.Stop(id={0:x8})", handle.id); // // Convert the handle to a process; call Stop method. // Process process = HandleTable.GetHandle(handle.id) as Process; process.Stop(exitcode); } [ExternalEntryPoint] public static void SuspendBarrier() { Process.SuspendBarrier(); } [ExternalEntryPoint] public static int GetProcessId(ProcessHandle handle) { Tracing.Log(Tracing.Debug, "ProcessHandle.GetProcessId(id={0:x8})", handle.id); // // Convert the handle to a process; retrieve ProcessId. // Process process = HandleTable.GetHandle(handle.id) as Process; return process.ProcessId; } [ExternalEntryPoint] public static int GetExitCode(ProcessHandle handle) { Tracing.Log(Tracing.Debug, "ProcessHandle.GetExitCode(id={0:x8})", handle.id); // // Convert the handle to a process; retrieve ExitCode. // Process process = HandleTable.GetHandle(handle.id) as Process; return process.ExitCode; } [ExternalEntryPoint] public static PrincipalHandle GetPrincipalHandle(ProcessHandle handle) { Tracing.Log(Tracing.Debug, "ProcessHandle.GetPrincipalHandle(id={0:x8})", handle.id); Process process = HandleTable.GetHandle(handle.id) as Process; return new PrincipalHandle(process.Principal.Val); } [ExternalEntryPoint] public static ExternalProcessState GetState(ProcessHandle handle) { Process process = HandleTable.GetHandle(handle.id) as Process; switch (process.State) { case InternalProcessState.Unstarted: case InternalProcessState.Running: return ExternalProcessState.Active; case InternalProcessState.Suspending: case InternalProcessState.SuspendingRecursive: case InternalProcessState.Suspended: return ExternalProcessState.Suspended; case InternalProcessState.Stopping: case InternalProcessState.Stopped: return ExternalProcessState.Stopped; default: // handle new missing case DebugStub.Break(); return ExternalProcessState.Stopped; } } [ExternalEntryPoint] public static unsafe ParameterCode SetStartupStringArrayArg ( ProcessHandle handle, int index, char *args, int *argLengths, int argCount) { Process process = HandleTable.GetHandle(handle.id) as Process; // // Create a kernel String[] object populated with the argument // values passed in from userland. // String[] arguments = new String[argCount]; int offset = 0; for (int argument = 0; argument < argCount; argument++) { arguments[argument] = String.StringCTOR( args, offset, argLengths[argument]); offset += argLengths[argument]; } return (ParameterCode) process.SetStartupStringArrayArg(index, arguments); } #if false [ExternalEntryPoint] public static int GetStartupStringArgCount(ProcessHandle handle) { Process process = HandleTable.GetHandle(handle.id) as Process; return process.GetStartupStringArgCount(); } [ExternalEntryPoint] public static unsafe int GetStartupStringArg(ProcessHandle handle, int arg, char * output, int maxput) { Process process = HandleTable.GetHandle(handle.id) as Process; string s = process.GetStartupStringArg(arg); Tracing.Log(Tracing.Debug, "Process.GetStartupStringArg(arg={0}, out={1:x8}, max={2}) = {3}", (UIntPtr)unchecked((uint)arg), (UIntPtr)output, (UIntPtr)unchecked((uint)maxput), (UIntPtr)unchecked((uint)(s != null ? s.Length : 0))); if (s == null) { return 0; } if (output == null) { return s.Length + 1; } return s.InternalGetChars(output, maxput); } #endif [ExternalEntryPoint] public static unsafe ParameterCode SetStartupStringArg( ProcessHandle handle, int arg, char * input, int length) { string s; if (length == 0) s = null; else s = String.StringCTOR(input, 0, length); Process process = HandleTable.GetHandle(handle.id) as Process; return (ParameterCode) process.SetStartupStringArg(arg, s); } #if false [ExternalEntryPoint] public static int GetStartupLongArgCount(ProcessHandle handle) { Process process = HandleTable.GetHandle(handle.id) as Process; return process.GetStartupLongArgCount(); } [ExternalEntryPoint] public static ParameterCode GetStartupLongArg(ProcessHandle handle, int index, out long value) { Process process = HandleTable.GetHandle(handle.id) as Process; return (ParameterCode) process.GetStartupLongArg(index, out value); } #endif [ExternalEntryPoint] public static ParameterCode SetStartupLongArg(ProcessHandle handle, int index, long value) { Process process = HandleTable.GetHandle(handle.id) as Process; return (ParameterCode) process.SetStartupLongArg(index, value); } #if false [ExternalEntryPoint] public static int GetStartupBoolArgCount(ProcessHandle handle) { Process process = HandleTable.GetHandle(handle.id) as Process; return process.GetStartupBoolArgCount(); } [ExternalEntryPoint] public static ParameterCode GetStartupBoolArg(ProcessHandle handle, int index, out bool value) { Process process = HandleTable.GetHandle(handle.id) as Process; return (ParameterCode)process.GetStartupBoolArg(index, out value); } #endif [ExternalEntryPoint] public static ParameterCode SetStartupBoolArg(ProcessHandle handle, int index, bool value) { Process process = HandleTable.GetHandle(handle.id) as Process; return (ParameterCode) process.SetStartupBoolArg(index, value); } } }