singrdk/base/Applications/Runtime/Full/System/Process.sg

591 lines
21 KiB
Plaintext
Raw Permalink Normal View History

2008-03-05 09:52:00 -05:00
///////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Note:
//
using System;
using System.Runtime.CompilerServices;
using System.Threading;
using Microsoft.SingSharp;
using Microsoft.Singularity;
using Microsoft.Singularity.Channels;
using Microsoft.Singularity.Security;
using Microsoft.Singularity.V1.Processes;
using Microsoft.Singularity.V1.Services;
using Microsoft.Singularity.V1.Types;
namespace System
{
[CLSCompliant(false)]
public sealed class Process
{
private ProcessHandle handle;
// Retrieve an endpoint passed as a parameter to this process.
//
public static unsafe Endpoint* in ExHeap GetStartupEndpoint(int arg)
{
SharedHeapService.Allocation* alloc =
ProcessService.GetStartupEndpoint(arg);
Endpoint* in ExHeap ep = (Endpoint* in ExHeap)alloc;
return ep;
}
// Retrieve an endpoint passed as a parameter to this process.
//
public static unsafe void RetStartupEndpoint(int arg,
[Claims] Endpoint* in ExHeap ep)
{
ProcessService.SetStartupEndpoint(arg, (SharedHeapService.Allocation*)ep);
}
#region Methods about current process
public static int GetStartupBoolArgCount()
{
return ProcessService.GetStartupBoolArgCount();
}
public static int GetStartupLongArgCount()
{
return ProcessService.GetStartupLongArgCount();
}
public static int GetStartupStringArgCount()
{
return ProcessService.GetStartupStringArgCount();
}
public static int GetStartupStringArrayArgCount()
{
return ProcessService.GetStartupStringArrayArgCount();
}
public static ParameterCode GetStartupLongArg(int index, out long value)
{
return ProcessService.GetStartupLongArg(index, out value);
}
public static ParameterCode GetStartupBoolArg(int index, out bool value)
{
return ProcessService.GetStartupBoolArg(index, out value);
}
public static unsafe ParameterCode GetStartupStringArrayArg(int index, out string[] arguments)
{
int count;
int totalCharCount;
ParameterCode code = ProcessService.GetStartupStringArrayArg(index,
null,
null,
out count,
out totalCharCount);
2008-11-17 18:29:00 -05:00
// REVIEW: for now NotSet is ignored and we return a string[1] below
2008-03-05 09:52:00 -05:00
if (code != ParameterCode.Success && code != ParameterCode.NotSet) {
arguments = new string[0];
return code;
}
if (count == 0) {
arguments = new string[0];
return ParameterCode.Success;
}
// Note: totalCharCount+1 because if we have an array of empty strings,
// the totalCharCount is 0 and then we can't take the address of &argArray[0] !
char[] argArray = new char [totalCharCount+1];
int [] intArray = new int[count];
fixed (int *intptr = &intArray[0]) {
fixed (char *argptr = &argArray[0]) {
ProcessService.GetStartupStringArrayArg(index,
argptr,
intptr,
out count,
out totalCharCount);
// now reconstruct the string array from the flattened char array
arguments = new string[count];
int offset = 0;
for (int i = 0; i < count; i++) {
arguments[i] = String.StringCTOR(
argptr, offset, intptr[i]);
offset += intptr[i];
}
}
}
return ParameterCode.Success;
}
public static unsafe ParameterCode GetStartupStringArg(int arg, out string value)
{
int len = 0;
ParameterCode code = ProcessService.GetStartupStringArg(arg, null, ref len);
if (code != ParameterCode.Success) {
value = null;
return code;
}
2008-11-17 18:29:00 -05:00
if (len == 0) {
// REVIEW: should this be "" or null?
2008-03-05 09:52:00 -05:00
value = null;
return ParameterCode.Success;
}
char[] argArray = new char [len];
fixed (char *argptr = &argArray[0]) {
ProcessService.GetStartupStringArg(arg,
argptr,
ref len);
value = String.StringCTOR(argptr, 0, len);
return ParameterCode.Success;
}
}
#endregion
#region Methods about other processes
public ParameterCode SetStartupLongArg(int index, long value)
{
ParameterCode p =
ProcessHandle.SetStartupLongArg(handle, index, value);
GC.KeepAlive(this);
return p;
}
public ParameterCode SetStartupBoolArg(int index, bool value)
{
ParameterCode p =
ProcessHandle.SetStartupBoolArg(handle, index, value);
GC.KeepAlive(this);
return p;
}
public unsafe ParameterCode SetStartupStringArrayArg(int index, string[]! strings)
{
ParameterCode p;
if (strings.Length > 0) {
int[]! lengths;
char[]! chars;
FlattenStringArray(strings, out lengths, out chars);
fixed (char *charptr = &chars[0]) {
fixed (int *intptr = &lengths[0]) {
p = ProcessHandle.SetStartupStringArrayArg(handle,
index,
charptr,
intptr,
strings.Length);
}
}
}
else {
p = ProcessHandle.SetStartupStringArrayArg(handle,
index,
null,
null,
strings.Length);
}
GC.KeepAlive(this);
return p;
}
public unsafe ParameterCode SetStartupStringArg(int index, string value)
{
ParameterCode p;
if (value != null && value.Length != 0) {
// String.m_firstChar is not accessible to sgc (defined in corlib)
// need to copy until the kernel and system are compiled
// with the same compiler
char[] c = new char[value.Length];
2008-11-17 18:29:00 -05:00
for (int i = 0; i < value.Length; i++) {
2008-03-05 09:52:00 -05:00
c[i] = value[i];
}
fixed ( char *argptr = &c[0] ) {
p = ProcessHandle.SetStartupStringArg(handle, index, argptr, value.Length);
}
}
// set "null"
else p = ProcessHandle.SetStartupStringArg(handle, index, null, 0);
GC.KeepAlive(this);
return p;
}
#endregion
// In order to pass the arguments to the kernel, we first need to
// flatten the arguments parameter from an array of strings to
// an array of characters (containing the contents of the strings).
private static unsafe void FlattenStringArray(string[]! arguments,
out int[]! argLengths,
out char[]! argVector)
{
int totalCharacters = 0;
int len = arguments.Length;
for (int arg = 0; arg < len; arg++) {
string argstring = arguments[arg];
if (argstring == null) continue;
totalCharacters += argstring.Length;
}
argVector = new char[totalCharacters + 1];
argLengths = new int[len];
int offset = 0;
for (int arg = 0; arg < len; arg++) {
string argstring = arguments[arg];
if (argstring == null) {
argLengths[arg] = 0;
continue;
}
int alen = argstring.Length;
argstring.CopyTo(0, argVector, offset, alen);
offset += alen;
argLengths[arg] = alen;
}
}
// In order to pass the arguments to the kernel, we first need to
// flatten the arguments parameter from an array of strings to
// an array of characters (containing the contents of the strings).
private static unsafe void FlattenArgs(string[]! arguments,
String role,
out int[]! argLengths,
out char[]! argVector,
out char[]! roleVector,
out int roleLength)
{
FlattenStringArray(arguments, out argLengths, out argVector);
// package the role parameters (if present)
if (role != null) {
roleLength = role.Length;
roleVector = new char[roleLength];
role.CopyTo(0, roleVector, 0, roleLength);
}
else {
roleLength = 0;
roleVector = new char[1];
}
}
/// <summary>
/// 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
/// </summary>
public unsafe bool BindToService(SystemType impType,
SystemType expType,
string! contract,
int startState,
int index)
{
// convert string to char* and length
char [] strChar = new char[contract.Length];
assert strChar != null;
contract.CopyTo(0, strChar, 0, contract.Length);
fixed ( char *strptr = &strChar[0] ) {
bool b = ProcessHandle.BindToService(handle,
impType,
expType,
strptr,
contract.Length,
startState,
index);
GC.KeepAlive(this);
return b;
}
}
[Microsoft.Contracts.NotDelayed]
public unsafe Process(String! cmd,
String action,
String role)
{
2008-11-17 18:29:00 -05:00
if (cmd.Length == 0)
throw new ArgumentException("The 'cmd' argument is required, and cannot be null or empty.", "cmd");
2008-03-05 09:52:00 -05:00
char[]! cmdVector;
char[]! actionVector;
char[]! roleVector;
int cmdLength;
int actionLength;
int roleLength;
// package the command named parameter
cmdLength = cmd.Length;
cmdVector = new char[cmdLength];
cmd.CopyTo(0, cmdVector, 0, cmdLength);
// package the action parameter(if present)
2008-11-17 18:29:00 -05:00
if (action != null && action.Length != 0) {
2008-03-05 09:52:00 -05:00
actionLength = action.Length;
actionVector = new char[actionLength];
action.CopyTo(0, actionVector, 0, actionLength);
}
else {
actionLength = 0;
actionVector = new char[1];
}
// package the role parameters (if present)
2008-11-17 18:29:00 -05:00
if (role != null && role.Length != 0) {
2008-03-05 09:52:00 -05:00
roleLength = role.Length;
roleVector = new char[roleLength];
role.CopyTo(0, roleVector, 0, roleLength);
}
else {
roleLength = 0;
roleVector = new char[1];
}
fixed (char *cmdptr = &cmdVector[0]) {
fixed (char *act = &actionVector[0]) {
fixed (char *rols = &roleVector[0]) {
ProcessHandle handleOnStack;
ProcessHandle.Create(cmdptr, cmdLength,
act, actionLength,
rols, roleLength,
out handleOnStack);
handle = handleOnStack;
}
}
}
if (handle.id == 0) {
throw new ProcessCreateException();
}
GC.KeepAlive(this);
}
[Microsoft.Contracts.NotDelayed]
public unsafe Process(String[]! arguments,
String role,
int endpointCount)
{
int[]! argLengths;
char[]! argVector;
char[]! roleVector;
int roleLength;
FlattenArgs(arguments, role,
out argLengths, out argVector, out roleVector, out roleLength);
fixed (char *args = &argVector[0]) {
fixed (int *lens = &argLengths[0]) {
fixed (char *rols = &roleVector[0]) {
ProcessHandle handleOnStack;
ProcessHandle.Create(args, lens, arguments.Length,
rols, roleLength, endpointCount,
out handleOnStack);
handle = handleOnStack;
}
}
}
if (handle.id == 0) {
throw new ProcessCreateException();
}
GC.KeepAlive(this);
ProcessService.Waypoint(573);
}
[Microsoft.Contracts.NotDelayed]
public unsafe Process(String[]! arguments,
String role,
[Claims] Endpoint* in ExHeap endpoint)
2008-11-17 18:29:00 -05:00
: this((!)arguments[0], null, role)
2008-03-05 09:52:00 -05:00
{
ProcessHandle.SetStartupEndpoint(handle, 0,
(SharedHeapService.Allocation *)endpoint);
GC.KeepAlive(this);
ProcessService.Waypoint(574);
}
[Microsoft.Contracts.NotDelayed]
public unsafe Process(String[]! arguments,
[Claims] Endpoint* in ExHeap exp)
: this(arguments, null, exp)
{
}
[Microsoft.Contracts.NotDelayed]
public unsafe Process(String[]! arguments,
2008-11-17 18:29:00 -05:00
String role)
: this(arguments, role, 0)
2008-03-05 09:52:00 -05:00
{
}
[Microsoft.Contracts.NotDelayed]
public unsafe Process(String[]! arguments)
: this(arguments, null, 0)
{
}
/// <summary>
/// Finalizer is responsible for freeing handle that keeps corresponding
/// kernel AutoResetEvent object live.
/// </summary>
~Process() {
Dispose(false);
}
public unsafe bool SetStartupEndpoint(int index,
[Claims] Endpoint * in ExHeap endpoint)
{
if (handle.id == 0) {
throw new ProcessStateException("disposed");
}
bool b = ProcessHandle.SetStartupEndpoint(handle, index,
(SharedHeapService.Allocation *)endpoint);
GC.KeepAlive(this);
return b;
}
public void Dispose(bool explicitDisposing)
{
if (handle.id != 0) {
ProcessHandle.Dispose(handle);
handle = new ProcessHandle();
}
}
public void Start()
{
if (handle.id == 0) {
throw new ProcessStateException("disposed");
}
bool unstarted = ProcessHandle.Start(handle);
GC.KeepAlive(this);
if (!unstarted) {
throw new ProcessStateException("started");
}
}
public void Join()
{
if (handle.id == 0) {
throw new ProcessStateException("disposed");
}
bool started;
ProcessHandle.Join(handle, out started);
GC.KeepAlive(this);
if (!started) {
throw new ProcessStateException("unstarted");
}
}
public bool Join(TimeSpan timeout)
{
if (handle.id == 0) {
throw new ProcessStateException("disposed");
}
bool started;
bool joined = ProcessHandle.Join(handle, timeout, out started);
GC.KeepAlive(this);
if (!started) {
throw new ProcessStateException("unstarted");
}
return joined;
}
public bool Join(SchedulerTime stop)
{
if (handle.id == 0) {
throw new ProcessStateException("disposed");
}
bool started;
bool joined = ProcessHandle.Join(handle, stop, out started);
GC.KeepAlive(this);
if (!started) {
throw new ProcessStateException("unstarted");
}
return joined;
}
public void Suspend(bool recursive)
{
if (handle.id == 0) {
throw new ProcessStateException("disposed");
}
bool started = ProcessHandle.Suspend(handle, recursive);
GC.KeepAlive(this);
if (!started) {
throw new ProcessStateException("unstarted");
}
}
public void Resume(bool recursive)
{
if (handle.id == 0) {
throw new ProcessStateException("disposed");
}
bool started = ProcessHandle.Resume(handle, recursive);
GC.KeepAlive(this);
if (!started) {
throw new ProcessStateException("unstarted");
}
}
public void Stop()
{
Stop((int) ProcessExitCode.StopDefault);
}
public void Stop(int exitcode)
{
if (handle.id == 0) {
throw new ProcessStateException("disposed");
}
ProcessHandle.Stop(handle, exitcode);
GC.KeepAlive(this);
}
public int Id
{
get {
int i =
(handle.id != 0) ? ProcessHandle.GetProcessId(handle) : 0;
GC.KeepAlive(this);
return i;
}
}
public Principal Principal
{
get
{
2008-11-17 18:29:00 -05:00
if (handle.id == 0) {
2008-03-05 09:52:00 -05:00
throw new ProcessStateException("disposed");
}
Principal p =
new Principal(ProcessHandle.GetPrincipalHandle(handle));
GC.KeepAlive(this);
return p;
}
}
public int ExitCode
{
get {
int i =
(handle.id != 0) ? ProcessHandle.GetExitCode(handle) : 0;
GC.KeepAlive(this);
return i;
}
}
public ProcessState State {
get {
ProcessState p =
(handle.id != 0) ? ProcessHandle.GetState(handle) : ProcessState.Stopped;
GC.KeepAlive(this);
return p;
}
}
}
}