commit 4e1c631ec85a8b05ec2a7c0d1805c47ba4f2138d Author: modeco80 Date: Wed Mar 5 09:52:00 2008 -0500 RDK 1.1 diff --git a/Building and Running Singularity RDK 1.1.pdf b/Building and Running Singularity RDK 1.1.pdf new file mode 100644 index 0000000..a25dc83 Binary files /dev/null and b/Building and Running Singularity RDK 1.1.pdf differ diff --git a/Singularity RDK 1.1 License.pdf b/Singularity RDK 1.1 License.pdf new file mode 100644 index 0000000..b452acc Binary files /dev/null and b/Singularity RDK 1.1 License.pdf differ diff --git a/base/Applications/AppendFormat/AppendFormat.csproj b/base/Applications/AppendFormat/AppendFormat.csproj new file mode 100644 index 0000000..284eb64 --- /dev/null +++ b/base/Applications/AppendFormat/AppendFormat.csproj @@ -0,0 +1,25 @@ + + + + + + + Exe + AppendFormat + + + + + + + + + diff --git a/base/Applications/AppendFormat/AppendFormat.sg b/base/Applications/AppendFormat/AppendFormat.sg new file mode 100644 index 0000000..a882247 --- /dev/null +++ b/base/Applications/AppendFormat/AppendFormat.sg @@ -0,0 +1,59 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// + +using System; +using System.Text; +using System.Threading; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.FileSystem; +using Microsoft.Singularity.V1.Services; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + + +namespace Microsoft.Singularity.Applications +{ + [ConsoleCategory( DefaultAction=true)] + internal class Parameters + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal Parameters(); + + internal int AppMain() { + return AppendFormat.AppMain(this); + } + } + + public class AppendFormat + { + public static string ToLegibleString(byte[]! b) + { + StringBuilder legible = new StringBuilder(); + for (int i = 0; i < b.Length; i++) { + legible.AppendFormat("{0:x2}", b[i]); + } + return legible.ToString(); + } + + internal static int AppMain(Parameters! config) + { + byte [] key = new byte[2]; + string s = ToLegibleString(key); + Console.WriteLine("s="+s); + return 0; + } + } +} diff --git a/base/Applications/Applications.proj b/base/Applications/Applications.proj new file mode 100644 index 0000000..a9184df --- /dev/null +++ b/base/Applications/Applications.proj @@ -0,0 +1,26 @@ + + + + + + + + + + + + + diff --git a/base/Applications/Benchmarks/BartokH/Child/BartokHChild.csproj b/base/Applications/Benchmarks/BartokH/Child/BartokHChild.csproj new file mode 100644 index 0000000..9cc4fa8 --- /dev/null +++ b/base/Applications/Benchmarks/BartokH/Child/BartokHChild.csproj @@ -0,0 +1,43 @@ + + + + + + Exe + bartokp + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/base/Applications/Benchmarks/BartokH/Child/Child.sg b/base/Applications/Benchmarks/BartokH/Child/Child.sg new file mode 100644 index 0000000..d8c4f15 --- /dev/null +++ b/base/Applications/Benchmarks/BartokH/Child/Child.sg @@ -0,0 +1,397 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: BartokP.sg +// +// Note: Compiler Phase +// + +//#define NONONNULLTYPECHECK // required on Singularity, no affect on other Windows. + +using Microsoft.SingSharp; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Endpoint; +using Microsoft.Singularity.V1.Services; + +using System; +using System.Runtime.CompilerServices; +using System.Threading; + +using Microsoft.Singularity; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Extending; +using Microsoft.Singularity.Configuration; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; + +using Bartok.Contracts; +using Bartok.Analysis.Lir; +using Bartok.Convert; +using Bartok.Datatype; +using Bartok.CfgUtil; +using Bartok.Lir; +using Bartok.Opt.Lir; +using Bartok.Utility; +using Bartok.DebugInfo; +using Bartok.Regalloc; +using Bartok.Marshal; + +[assembly: Transform(typeof(WebAppResourceTransform))] + +namespace Bartok.Child +{ + [Category("WebApp")] + internal class Parameters + { + [Endpoint] + public readonly TRef sendRef; + + [BoolParameter("where", Default=false, + HelpMessage="Show what space we are running in")] + internal bool doWhere; + + reflective private Parameters(); + + internal int AppMain() { + return BartokP.AppMain(this); + } + } + + public class BartokP + { + internal static int AppMain(Parameters! config) + { + // DebugStub.WriteLine("Child::GC Verify enabled"); + // AppRuntime.EnableGCVerify = true; + //AppRuntime.EnableGCAccounting = true; + //DebugStub.WriteLine("Child: Enabled GC Accounting"); + //DebugStub.WriteLine("Child: Began execution!"); + + if (config.doWhere) { + DebugStub.WriteLine("BartokP running!"); + } + + ExtensionContract.Exp ep = config.sendRef.Acquire(); + + CompilerPhaseContract.Exp cp = ep as CompilerPhaseContract.Exp; + + if (cp != null) { + DoPhase(cp); + delete cp; + return 0; + } + + // Wrong contract type! + delete ep; + return 1; + } + + private static void ReadOpen(CheapState! cs, byte[]! in ExHeap bytes) + { + uint regionSize; + uint region; + regionSize = (uint)bytes.Length; + unsafe { + fixed (byte *pdst = &bytes[0]) { + region = (uint)pdst; + cs.ReadOpen(region, regionSize); + } + } + } + + private static void ReadClose(CheapState! cs) + { +#if false + if (cs.oig != null) { + DebugStub.WriteLine("--- Stub .Read Close {0,8} bytes {1,5} objects", + __arglist(cs.read, cs.loadCount)); + } +#endif + cs.ReadClose(); + } + + private static void WriteOpen(CheapState! cs, byte[]! in ExHeap bytes) + { + uint regionSize; + uint region; + regionSize = (uint)bytes.Length; + unsafe { + fixed (byte *pdst = &bytes[0]) { + region = (uint)pdst; + cs.WriteOpen(region, regionSize); + } + } + } + + private static void WriteClose(CheapState! cs) + { +#if false + if (cs.oig != null) { + DebugStub.WriteLine("--- Stub .WriteClose {0,8} bytes {1,5} objects", + __arglist(cs.used, cs.oig.m_currentCount)); + } +#endif + cs.WriteClose(); + } + + private static void DoPhase(CompilerPhaseContract.Exp! cp) + { + GraphColoringReal gcr; + CheapState! cs = new CheapState(0, false); + + CheapMarshal.InitTypes(); + + // Track statics before they can be replicated in a method call. + RegisterX86.TrackAsGlobal(cs); + OpCodesX86.TrackAsGlobal(cs); + + cp.SendReadyToInit(); + bool halt = false; +#if USE_SWITCH_RECEIVE + switch receive + { + case cp.InitPhaseReq(byte[]! in ExHeap buffer): + RegDesc regs; + CallConv conv; + AbstractTarget target; + GlobalLayoutData globalLayoutData; + int pageSize; + int stackThreshhold; + bool isNoisy; + CSRT runtime; + StageControlProxy controls; + + beg = Processor.GetCycleCount(); + ReadOpen(cs, buffer); + RegDesc.CheapRead(cs, out regs); + CallConv.CheapRead(cs, out conv); + AbstractTarget.CheapRead(cs, out target); + GlobalLayoutData.CheapRead(cs, out globalLayoutData); + cs.Read(out pageSize); + cs.Read(out stackThreshhold); + cs.Read(out isNoisy); + CSRT.CheapRead(cs, out runtime); + StageControlProxy.CheapRead(cs, out controls); + ReadClose(cs); + + DebugStub.AddToPerfCounter(1, Processor.GetCycleCount() - beg); + + CSRT.runtime = runtime; + if (controls != null) { + controls.SetValues(); + } + + if (globalLayoutData != null) { + RepInfo.LayoutInfoFactory = globalLayoutData.LayoutInfoFactory; + RepInfo.SetX86Layout(); + } + + target.TrackAsGlobal(cs); + regs.TrackAsGlobal(cs); + conv.TrackAsGlobal(cs); + runtime.TrackAsGlobal(cs); + cs.DumpGlobal("chld"); + +#if false + DebugStub.WriteLine("-------- GraphColoring::Stub Init -----"); +#endif + + gcr = new GraphColoringReal(regs, + conv, + target, + globalLayoutData, + pageSize, + stackThreshhold, + isNoisy); + + beg = Processor.GetCycleCount(); + WriteOpen(cs, buffer); + WriteClose(cs); + DebugStub.AddToPerfCounter(2, Processor.GetCycleCount() - beg); + cp.SendInitPhaseRsp(buffer); + break; + case cp.ChannelClosed(): + Console.WriteLine("Compiler channel closed unexpectedly before init."); + return; + } +#else + byte[]! in ExHeap buffer; + cp.RecvInitPhaseReq(out buffer); + + RegDesc regs; + CallConv conv; + AbstractTarget target; + GlobalLayoutData globalLayoutData; + int pageSize; + int stackThreshhold; + bool isNoisy; + CSRT runtime; + StageControlProxy controls; + + ulong beg = Processor.GetCycleCount(); + ReadOpen(cs, buffer); + RegDesc.CheapRead(cs, out regs); + CallConv.CheapRead(cs, out conv); + AbstractTarget.CheapRead(cs, out target); + GlobalLayoutData.CheapRead(cs, out globalLayoutData); + cs.Read(out pageSize); + cs.Read(out stackThreshhold); + cs.Read(out isNoisy); + CSRT.CheapRead(cs, out runtime); + StageControlProxy.CheapRead(cs, out controls); + ReadClose(cs); + + DebugStub.AddToPerfCounter(1, Processor.GetCycleCount() - beg); + + CSRT.runtime = runtime; + if (controls != null) { + controls.SetValues(); + } + + if (globalLayoutData != null) { + RepInfo.LayoutInfoFactory = globalLayoutData.LayoutInfoFactory; + RepInfo.SetX86Layout(); + } + + // DebugStub.WriteLine(":: Chld Targ Globals"); + ((!)target).TrackAsGlobal(cs); + // DebugStub.WriteLine(":: Chld Regs Globals"); + ((!)regs).TrackAsGlobal(cs); + // DebugStub.WriteLine(":: Chld Conv Globals"); + ((!)conv).TrackAsGlobal(cs); + // DebugStub.WriteLine(":: Chld CSRT Globals"); + ((!)runtime).TrackAsGlobal(cs); + + // cs.DumpGlobal("chld"); + +#if false + DebugStub.WriteLine("-------- GraphColoring::Stub Init -----"); +#endif + + gcr = new GraphColoringReal(regs, + conv, + target, + globalLayoutData, + pageSize, + stackThreshhold, + isNoisy); + + beg = Processor.GetCycleCount(); + WriteOpen(cs, buffer); + WriteClose(cs); + DebugStub.AddToPerfCounter(2, Processor.GetCycleCount() - beg); + cp.SendInitPhaseRsp(buffer); +#endif + + while (!halt) { +#if USE_SWITCH_RECEIVE + switch receive + { + case cp.GetPhaseNameReq(): + char[]! in ExHeap name = (!)Bitter.FromString(gcr.PhaseName); + cp.SendGetPhaseNameRsp(name); + break; + + case cp.ProcessFunctionReq(byte[]! in ExHeap buffer): + FunctionDef f; + ChooseRepResult r; + + beg = Processor.GetCycleCount(); + ReadOpen(cs, buffer); + FunctionDef.CheapRead(cs, out f); + ChooseRepResult.CheapRead(cs, out r); + ReadClose(cs); + DebugStub.AddToPerfCounter(1, Processor.GetCycleCount() - beg); + + gcr.Go(f, r); + + beg = Processor.GetCycleCount(); + WriteOpen(cs, buffer); + if (f != null) { + OperandArray.CheapWrite(cs, f.actualArgs); + LirBasicBlock.CheapWrite(cs, f.prolog); + LirBasicBlock.CheapWrite(cs, f.epilog); + LirBasicBlock.CheapWrite(cs, f.unwind); + cs.Write(f.omitFramePointer); + cs.Write(f.spillSlotCount); + Operand.CheapWrite(cs, f.stackSlotMap); + SequencedCfg.CheapWrite(cs, f.code); + OperandArray.CheapWrite(cs, f.pinned); + OperandArray.CheapWrite(cs, f.formals); + Operand.CheapWrite(cs, f.ret); + } + WriteClose(cs); + DebugStub.AddToPerfCounter(2, Processor.GetCycleCount() - beg); + cp.SendProcessFunctionRsp(buffer); + break; + + case cp.TermPhaseReq(): + gcr.Term(); + cp.SendTermPhaseRsp(); + halt = true; + break; + + case cp.ChannelClosed(): + halt = true; + Console.WriteLine("Compiler channel closed unexpectedly."); + break; + } +#else + int which; + + cp.RecvRequest(out which, out buffer); + if (which == (int)RequestKind.ProcessFunction) { + FunctionDef f; + ChooseRepResult r; + + beg = Processor.GetCycleCount(); + ReadOpen(cs, buffer); + FunctionDef.CheapRead(cs, out f); + ChooseRepResult.CheapRead(cs, out r); + ReadClose(cs); + DebugStub.AddToPerfCounter(1, Processor.GetCycleCount() - beg); + +#if DEBUG_FUNCTION_CALLS + DebugStub.WriteLine(); + DebugStub.WriteLine("*** {0} ***", __arglist(((!)f).name.ToString())); +#endif + gcr.Go(f, r); + + beg = Processor.GetCycleCount(); + WriteOpen(cs, buffer); + if (f != null) { + OperandArray.CheapWrite(cs, f.actualArgs); + LirBasicBlock.CheapWrite(cs, f.prolog); + LirBasicBlock.CheapWrite(cs, f.epilog); + LirBasicBlock.CheapWrite(cs, f.unwind); + cs.Write(f.omitFramePointer); + cs.Write(f.spillSlotCount); + Operand.CheapWrite(cs, f.stackSlotMap); + SequencedCfg.CheapWrite(cs, f.code); + OperandArray.CheapWrite(cs, f.pinned); + OperandArray.CheapWrite(cs, f.formals); + Operand.CheapWrite(cs, f.ret); + } + WriteClose(cs); + DebugStub.AddToPerfCounter(2, Processor.GetCycleCount() - beg); +#if DEBUG_FUNCTION_CALLS + DebugStub.WriteLine("--- {0} ---", __arglist(((!)f).name.ToString())); + DebugStub.WriteLine(); +#endif + } + else if (which == (int)RequestKind.Terminate) { + gcr.Term(); + halt = true; + } + else { + DebugStub.WriteLine("Unknown request: {0}", __arglist(which)); + } + cp.SendResponse(buffer); +#endif + } + } + } +} diff --git a/base/Applications/Benchmarks/BartokH/Contracts/BartokHContracts.csproj b/base/Applications/Benchmarks/BartokH/Contracts/BartokHContracts.csproj new file mode 100644 index 0000000..6f7a166 --- /dev/null +++ b/base/Applications/Benchmarks/BartokH/Contracts/BartokHContracts.csproj @@ -0,0 +1,16 @@ + + + + + + Library + Bartok.Contracts + + + + + + + + + diff --git a/base/Applications/Benchmarks/BartokH/Contracts/CompilerPhaseContract.sg b/base/Applications/Benchmarks/BartokH/Contracts/CompilerPhaseContract.sg new file mode 100644 index 0000000..4284674 --- /dev/null +++ b/base/Applications/Benchmarks/BartokH/Contracts/CompilerPhaseContract.sg @@ -0,0 +1,69 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: CompilerPhaseContract.sg +// + +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Endpoint; +using Microsoft.Singularity.V1.Services; + +using System; +using System.Runtime.CompilerServices; +using System.Threading; + +using Microsoft.Singularity.Extending; + +namespace Bartok.Contracts +{ + public enum RequestKind { + GetPhaseName = 1, + ProcessFunction = 2, + Terminate = 3, + }; + + public contract CompilerPhaseContract : ExtensionContract + { + in message InitPhaseReq(byte[]! in ExHeap buffer); + out message InitPhaseRsp(byte[]! in ExHeap buffer); + +#if USE_SWITCH_RECEIVE + in message GetPhaseNameReq(); + out message GetPhaseNameRsp(char[]! in ExHeap name); + + in message ProcessFunctionReq(byte[]! in ExHeap buffer); + out message ProcessFunctionRsp(byte[]! in ExHeap buffer); + + in message TermPhaseReq(); + out message TermPhaseRsp(); +#else + in message Request(int which, byte[]! in ExHeap buffer); + out message Response(byte[]! in ExHeap buffer); +#endif + + out message ReadyToInit(); + + override state Start : one { + ReadyToInit! -> PreInit; + } + + state PreInit : one { + InitPhaseReq? -> InitPhaseRsp! -> Running; + } + + state Running : one { +#if USE_SWITCH_RECEIVE + GetPhaseNameReq? -> GetPhaseNameRsp! -> Running; + ProcessFunctionReq? -> ProcessFunctionRsp! -> Running; + TermPhaseReq? -> TermPhaseRsp! -> End; +#else + Request? -> Response! -> Running; +#endif + } + + state End: ; + } +} diff --git a/base/Applications/Benchmarks/BartokH/host/Bartok.cs b/base/Applications/Benchmarks/BartokH/host/Bartok.cs new file mode 100644 index 0000000..52dc058 --- /dev/null +++ b/base/Applications/Benchmarks/BartokH/host/Bartok.cs @@ -0,0 +1,1559 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// + +#define NONONNULLTYPECHECK // required on Singularity, no affect on other Windows. + +namespace Bartok { + + using System; + using System.IO; + using System.Text; + using System.Collections; + using Bartok.Utility; + using Bartok.Datatype; + using Bartok.CfgUtil; + using Bartok.Ir; + using Bartok.Lir; + using Bartok.Analysis; + using Bartok.Opt.IrCleanup; + using Bartok.Opt.Ir; + using Bartok.Opt.Lir; + using Bartok.Opt; + using Bartok.Regalloc; + using Bartok.Opt.Ssa; + using Bartok.Backend; + +#if ON_SINGULARITY + using Microsoft.Singularity; +#endif + + // + // Bartok.cs + // + // Main entry point for compiler + + // "public class Bartok {..}" breaks the namespace lookup of Bartok.* + // Is this a bug? + public class BartokClass { + + public static long CHECK_COUNT = 0; + public static long CHECK_COUNT_LOWER = 0; + + public static int Main(String[] args) { +#if ON_SINGULARITY + // AppRuntime.EnableGCVerify = false; + // DebugStub.WriteLine("Bartok Host: Enabled GC Verifier"); + // AppRuntime.EnableGCAccounting = true; + // DebugStub.WriteLine("Bartok Host: Enabled GC Accounting"); +#endif + Bartok.MSIL.MetaDataUtil.Configure(new MetaDataOutput()); + + try { + ProcessCmdLine(args); + if((fileNames.Count == 0) && (linkNames.Count == 0)) { + CHECK_COUNT++; + CHECK_COUNT_LOWER++; + + PrintUsage(); + Util.Error("\nno files to process...aborting."); + Util.Exit(-11); + } + + if(StageControl.AtomicSupport) { + StageControl.TryAllSupport = true; + } + + Util.Message(NoiseLevel.PerPhase, + "fileNames = " + + new CollectionFormatter(fileNames)); + Util.Message(NoiseLevel.PerPhase, + "refFileNames = " + + new CollectionFormatter(refFileNames)); + Util.Message(NoiseLevel.PerPhase, + "libDirNames = " + + new CollectionFormatter(libDirNames)); + Util.Message(NoiseLevel.PerPhase, + "outputDirName = " + outputDirName); + + if (overrideNames.Count > 0) { + Util.Message(NoiseLevel.PerPhase, + "overrideNames = " + + new CollectionFormatter(overrideNames)); + } + if (entryPoints.Count > 0) { + Util.Message(NoiseLevel.PerPhase, + "entryPoints = " + + new CollectionFormatter(entryPoints)); + } + + // Create helper data structures + DateTime startTime = Util.startTime; + bool fLoadDebugInfo = StageControl.SymbolicDebug; + StageControl.BartokLinkPhase = false; + if (StageControl.CompileOnly) { + // separate compilation + foreach (String fileName in fileNames) { + String outputName = + ComputeOutputName(fileName, outputDirName); + ArrayList loadFileNames = new ArrayList(1); + loadFileNames.Add(fileName); + String shortName = GetShortName(fileName).ToLower(); + + // we need to compile mscorlib.dll together with + // system.dll + bool fDefineOverride = shortName.Equals("mscorlib.dll"); + + TypeData typeData = new TypeData(); + CompileFile(typeData, loadFileNames, refFileNames, + overrideNames, overrideDefNames, + fDefineOverride, outputName, + startTime, fLoadDebugInfo); + } + } else { + // Create output root name. + if (outputRootName == null) { + outputRootName = (String) fileNames[0]; + } + + // strip off extension, if there is one. + int dotIndex = outputRootName.LastIndexOf('.'); + if (dotIndex != -1) { + String ext = outputRootName.Substring(dotIndex + 1); + if (ext.Equals("dll") || ext.Equals("obj") + || ext.Equals("exe")) { + outputRootName = + outputRootName.Substring(0, dotIndex); + } + } + + bool fDefineOverride = StageControl.WholeProgram; + TypeData typeData = new TypeData(); + String objFileName = + CompileFile(typeData, fileNames, refFileNames, + overrideNames, overrideDefNames, fDefineOverride, + outputRootName, startTime, fLoadDebugInfo); + linkNames.Add(objFileName); + +#if DO_LINK + StageControl.BartokLinkPhase = true; + BartokLinker bartokLinker = new BartokLinker(); + typeData = StageControl.WholeProgram ? typeData : null; + bartokLinker.Link(typeData, fileNames, linkNames, + refFileNames, overrideNames, overrideDefNames, + libDirNames, + entryPoints, initializerSkips, + outputRootName); +#endif + } + } catch(AbortException) { + // Abort code already dumped the stack + Util.Exit(-1); + } catch(Exception e) { + Util.Error("Internal uncaught {0} exception", e); + Util.Exit(-1); + } + Util.Message(NoiseLevel.PerPhase, + "STATIC COUNT IS: " + CHECK_COUNT); + Util.Message(NoiseLevel.PerPhase, + "STATIC LOWER IS: " + CHECK_COUNT_LOWER); + return 0; + } + + private static String CompileFile(TypeData typeData, + ArrayList fileNames, + ArrayList refFileNames, + ArrayList overrideNames, + ArrayList overrideDefNames, + bool fDefineOverride, + String outputName, + DateTime startTime, + bool fLoadDebugInfo) { + ConvertMsil2Ir(fileNames, refFileNames, overrideNames, + overrideDefNames, fDefineOverride, startTime, + fLoadDebugInfo, typeData); + + CHECK_COUNT++; + CHECK_COUNT_LOWER++; + + +#if SELF_PROFILING + System.GC.Collect(); + long memoryUsage = System.GC.GetTotalMemory(false); + Util.Message("memory usage: " + memoryUsage); +#endif + + if (entryPoints.Count > 0) { + Util.Message(NoiseLevel.PerPhase, + "entryPoints = " + + new CollectionFormatter(entryPoints)); + } + if(!StageControl.CompileOnly && (entryPoints.Count == 0)) { + Util.Abort("No entry points found"); + } + + typeData.ComputeEntryMethod(entryPoints); + Util.Assert(typeData.EntryPoints.Count == entryPoints.Count); + + // register all global analysis + AnalysisRegistry analysisRegistry = RegisterAnalysis(typeData); + + // Create a series of phases that are each applied to the + // whole program. + Bartok.Ir.PhaseList phases = new Bartok.Ir.PhaseList("ir"); + + CHECK_COUNT--; + CHECK_COUNT_LOWER--; + + AddPhases(phases, analysisRegistry, outputName, typeData); + + Util.Message(phases.ComponentPhases.ToString()); + if (StageControl.DumpContainers) { + phases.Add(new TypeDataPrettyPhase("After IR:")); + } + Bartok.Opt.IrCleanup.Statistics.Reset(typeData); + BartokList phaseNames = phases.ComponentPhases; + foreach(Object phaseObj in phaseNames) { + if(!(phaseObj is string)) { + Util.Warn("Not string: {0}X", + phaseObj.ToString()); + continue; + } + string phaseName = (string)phaseObj; + if(phaseName.IndexOf(' ') != -1) { + Util.Warn("Phase has a space in name: {0}", phaseName); + } + } + foreach(string phaseName in StageControl.disabledPhaseNames) { + if(phaseNames.Contains(phaseName)) { + continue; + } + if(StageControl.disabledPhaseNamesFound.Contains(phaseName)) { + continue; + } + Util.Abort("Couldn't find phase: " + phaseName); + } + phases.Go(typeData); + + Bartok.Opt.IrCleanup.Statistics.Summary(); + +#if SELF_PROFILING + memoryUsage = System.GC.GetTotalMemory(false); + Util.Message("memory usage: " + memoryUsage); +#endif + + // backend phases: + Util.Message("outputRootName = " + outputName); + + String objFileName = LirPhases.run(typeData, fileNames, outputName, + StageControl.GenObjFile); + System.GC.Collect(); + Util.Message("End of Bartok: " + GC.GetTotalMemory(false)); + return objFileName; + } + + private static void ConvertMsil2Ir(ArrayList fileNames, + ArrayList refFileNames, + ArrayList overrideNames, + ArrayList overrideDefNames, + bool fDefineOverride, + DateTime startTime, + bool fLoadDebugInfo, + TypeData typeData) { + // Remove redundant fileNames + // Remove refFileNames that are redundant with fileNames + for(int i=0; i= NoiseLevel.PerPhase; + + Bartok.MSIL.MetaDataResolver libResolver = + new Bartok.MSIL.MetaDataResolver(refFileNames, libDirNames, + startTime, fLoadDebugInfo, + fMsilMessages); + Bartok.MSIL.MetaDataResolver overrideResolver; + if (fDefineOverride) { + // load code + overrideResolver = + new Bartok.MSIL.MetaDataResolver(overrideNames, + startTime, + fLoadDebugInfo, + fTranslateTryAll, + fTranslateAtomic, + fMsilMessages); + } else { + // don't load code + overrideResolver = + new Bartok.MSIL.MetaDataResolver(overrideNames, + libDirNames, + startTime, fLoadDebugInfo, + fMsilMessages); + } + Bartok.MSIL.MetaDataResolver overrideDefResolver = + new Bartok.MSIL.MetaDataResolver(overrideDefNames, startTime, + fLoadDebugInfo, + fTranslateTryAll, + fTranslateAtomic, + fMsilMessages); + Bartok.MSIL.MetaDataResolver loadResolver = + new Bartok.MSIL.MetaDataResolver(fileNames, startTime, + fLoadDebugInfo, + fTranslateTryAll, + fTranslateAtomic, + fMsilMessages); + Bartok.MSIL.MetaDataResolver[] resolvers = + new Bartok.MSIL.MetaDataResolver[] { + libResolver, overrideResolver, overrideDefResolver, + loadResolver + }; + Bartok.MSIL.MetaDataResolver.ResolveCustomAttributes(resolvers); + MetaDataParser parser = + new MetaDataParser(entryPoints.Count == 0 ? entryPoints : null); + Util.TimestampMessage(NoiseLevel.PerPhase, + "translating from MSIL"); + parser.Parse(loadResolver, overrideResolver, + overrideDefResolver, libResolver, + typeData, fDefineOverride, false); + + Util.TimestampMessage(NoiseLevel.PerPhase, + "finished translating"); + } + + private static AnalysisRegistry RegisterAnalysis(TypeData typeData) { + AnalysisRegistry analysisRegistry = new AnalysisRegistry(typeData); + analysisRegistry.RegisterAnalysis(VirtualCallAnalysis.makeFactory()); + return analysisRegistry; + } + + private static void AddPhases(Bartok.Ir.PhaseList phases, + AnalysisRegistry analysisRegistry, + String outputName, + TypeData typeData) { + if (StageControl.PrintContainers) { + phases.Add(new TypeDataPrintPhase("After parse:")); + } + if (StageControl.DumpContainers) { + phases.Add(new TypeDataPrettyPhase("After parse:")); + } + if (StageControl.SingSharpTemplateRemover) { + phases.Add(new SingSharpTemplateRemover()); + } + if (StageControl.RuntimeMods) { + phases.Add(new RuntimeMods()); + } + if (StageControl.IrMultiPropSimple) { + phases.Add(new IrMultiPropSimple("System.GC")); + } + if (StageControl.IrDeadAssignmentSimple1) { + phases.Add(new IrDeadAssignmentSimplePhase("System.GC")); + } + if (StageControl.IrTreeShake) { + phases.Add(new IrTreeShake(typeData.EntryPoints, + dynamicLoads, + StageControl.WholeProgram, + analysisRegistry)); + } + + /* + phases.Add + (new DynamicCount + ("VirtualCallsStart", + new DynamicCount.OpcodeFilter + (Operator.OpCodes.CallVirtual, + Operator.OpCodes.InterfaceCall), + DynamicCount.Granularity.PerSite)); + */ + + /* + phases.Add + (new DynamicCount + ("ASCstart", + new DynamicCount.OpcodeFilter + (Operator.OpCodes.CheckArrayStore, + Operator.OpCodes.CheckVectorStore), + DynamicCount.Granularity.PerSite)); + */ + + if (StageControl.PtrAnalysis) { + phases.Add(PtrTypeSimpleSystem.CreateAnalysis()); + phases.Add(PtrTypeHierarchySystem.CreateAnalysis()); + phases.Add(PtrTypeSetSystem.CreateAnalysis()); + } + + // create wrapper that insert calls to leaveGCSafeState and + // enterGCSafeState. + phases.Add(new CreateEntryPointWrapper()); + + // trap ValueType.Equals and override it by compiler generated + // routines. + if (StageControl.IrOverrideValueTypeEquals) { + phases.Add(new Convert.ValueTypeEquals()); + } + + if (StageControl.LimitedReflection) { + phases.Add(new Convert.OverrideVTableInit()); + } + + if (StageControl.IrConvertSizeofPrimitive) { + Convert.ToMir.Mask mask = Convert.ToMir.Mask.SizeofPrimitive; + phases.Add(new Convert.ToMir(mask)); + } + + /* SPOONS: region related phases: + // A temporary pass that cleans up the scratch objects so that the + // DemandAnalysis is not confused by the randomness that the tree + // shaker leaves behind. + phases.Add(new CleanScratch()); + + // Build a "Foo_layout" for each class "Foo"; other setup required + // by DemandAnalysis. + phases.Add(new LayoutBuilder()); + + // Perform first- and last-use analysis; add explicit region + // variables and effects. + phases.Add(new DemandAnalysis()); + + // Print the code + phases.Add(new TypeDataPrettyPhase("After Demand:")); + */ + + // Perform first- and last-use analysis; add explicit region + // variables and effects. + + // must happen after DemandAnalysis, but before any inlining / + // rearranging basic blocks or calls. +#if !VC + if(StageControl.TryAllSupport) { + phases.Add(new Bartok.Convert.PropagateLogging(analysisRegistry)); + phases.Add(new TypeDataDummyPhase()); + } +#endif + + if (StageControl.IrScanCallEffects) { + phases.Add(new IrScanCallEffects()); + } + + if(StageControl.DumpInheritance) { + phases.Add(new DumpInheritancePhase(StageControl.DumpInheritanceFile)); + } + +#if PHX_TODO + phases.Add(new TypeDataToPhoenix()); +#endif + phases.Add(new TypeInit(initializerSkips)); + + if (StageControl.InstrumentCalls) { + phases.Add(new InstrumentCalls()); + } + + if (StageControl.IrStoreChecks) { + phases.Add(new IrStoreCheckElim()); + } + if (StageControl.BuildC2Mods + && StageControl.UnmanagedStrings) { + phases.Add(new IrUnmanagedStrings()); + } + phases.Add(IrCleanup.Create()); + if (StageControl.BuildC2Mods + && StageControl.IdentifyAsMethods) { + phases.Add(new IrIdentifyAsMethods()); + } + + if (StageControl.WholeProgram + && StageControl.IrDeadAssignmentSimpleFormals + && StageControl.IrTreeShake) { + phases.Add(new IrDeadAssignmentSimpleFormalsPhase()); + phases.Add(new IrTreeShake(typeData.EntryPoints, + dynamicLoads, + StageControl.WholeProgram, + analysisRegistry)); + } + + phases.Add(new Convert.IrInsertDelegate()); + + IrFieldAnalysis fieldAnalysis = null; + if (StageControl.GCType == + StageControl.ReferenceCountingCollector && + StageControl.RCCollectorOptRCSubsumed && + StageControl.RCCollectorOptRCSubsumedByROFields) { + IrFieldAnalysis.FieldFilter filter = + new IrFieldAnalysis.RCAproposFieldFilter(); + fieldAnalysis = new IrFieldAnalysis(true, filter); + phases.Add(fieldAnalysis); + } + + if(StageControl.IrInlineConstructor) { + phases.Add(new Convert.ToMir(Convert.ToMir.Mask.Constructor)); + } + // When only one class implements an interface, replace the interface + // with the class. + if (StageControl.IrInterfaceElim && StageControl.WholeProgram) { + phases.Add(new InterfaceElim()); + } + + if (StageControl.IrSimpleInliner) { + phases.Add(new IrSimpleInliner(new IrInline(), false, false, false)); + } else if (StageControl.IrAttributeInliner) { + // inline methods that has [inline] attributes. + phases.Add(new IrSimpleInliner(new IrInline(), false, false)); + } + + if (StageControl.FailAfterInliner) { + phases.Add(new FailPhase()); + } + + if (StageControl.IrMultiPropSimple) { + phases.Add(new IrMultiPropSimple()); + } + if (StageControl.IrSuppressExnEdges) { + phases.Add(new IrSuppressExnEdges()); + } + if (StageControl.IrLoadStoreOpt) { + phases.Add(new IrLoadStoreOpt(analysisRegistry)); + } + if (StageControl.DevirtualizeCall) { + phases.Add(new IrDevirtualizeCall(analysisRegistry)); + } + + if (StageControl.IrSimpleInliner && + StageControl.IrInlinerDoIncreaseSize) { + phases.Add(new IrSimpleInliner(new IrInline(), true, false, false)); + } + + if (StageControl.LazyTypeInits) { + phases.Add(new TypeInit(initializerSkips, true)); + } + + // Eliminate unnecessary instanceOf/check casts. Only makes + // 2 passes by punting back edges. + if (StageControl.IrTypeTestElimPunt) { + phases.Add(new TypeTestElimPunt()); + } + + // Eliminate unnecessary instanceOf/check casts - full iterative + // analysis. More expensive than the above analysis, but yields + // little improvement in practice. + if (StageControl.IrTypeTestElim) { + phases.Add(new TypeTestElim()); + } + + // Deletes all CheckCasts and instanceOf IDisposable for sake of + // experimentation. Normally not enabled, as it is unsafe. + + if (StageControl.IrDeleteCheckCasts) { + phases.Add(new DeleteCheckCast()); + } + + if (StageControl.IrConvertOpt) { + phases.Add(new IrConvertOpt()); + phases.Add(new IrDeadAssignmentSimplePhase()); + phases.Add(new IrReverseCopyProp()); + } + + // Just do thread analysis once. + IrLockedFields locks = null; + if (StageControl.ExtendThreadFieldsABCD || + StageControl.SsaNullCheckGlobalThreaded) { + + if (StageControl.IrTreeShake) { + phases.Add(new IrTreeShake(typeData.EntryPoints, + dynamicLoads, + StageControl.WholeProgram, + analysisRegistry)); + } + + if(StageControl.OptimisticLocking) { + locks = new ClassIrLockedFields(analysisRegistry); + } else { + locks = new IrLockedFields(analysisRegistry); + } + phases.Add(locks); + } + + // Array bounds check elimination + if (StageControl.ABCD) { + phases.Add(new ABCD(analysisRegistry, locks)); + } + + if (StageControl.IrConvertArrayBounds) { + Convert.ToMir.Mask mask = Convert.ToMir.Mask.CheckVectorBounds; + phases.Add(new Convert.ToMir(mask)); + } + + if (StageControl.IrConvertInferface) { + Convert.ToMir.Mask mask = Convert.ToMir.Mask.InterfaceCall; + phases.Add(new Convert.ToMir(mask)); + } + + if (StageControl.IrConvertSimpleArrayAccess) { + Convert.ToMir.Mask mask = Convert.ToMir.Mask.SimpleArrayAccess; + phases.Add(new Convert.ToMir(mask)); + } + + if (StageControl.IrCloneLoopHeader) { + phases.Add(new IrCloneLoopHeader()); + phases.Add(new IrJumpElim()); + phases.Add(new IrMultiPropSimple()); + } + + if (StageControl.SsaOpts) { + if (StageControl.SsaNullCheckGlobalThreaded) { + phases.Add(SSAPhase.Create(analysisRegistry, locks)); + } else { + phases.Add(SSAPhase.Create()); + } + } + + if(locks != null) { + locks = null; + } + + // IrInsertStructCopy phase insert a StructCopy() method + // to each struct type, and lower struct Id operators + // to a call to StructCopy() method. + phases.Add(new Convert.IrInsertStructCopy()); + +#if !VC + if(StageControl.TryAllSupport) { + phases.Add(new IrInsertLogging()); + } + + if(StageControl.TryAllSupport && + StageControl.AtomicSupportUpdateEnlistOptFlow) { + // without the IrLoadStoreOpt here, EnlistIndirects + // generated by [Store]StructFields can't be moved. + phases.Add(new IrLoadStoreOpt(analysisRegistry)); + phases.Add(new IrInsertUpdateEnlistments()); + // otherwise CSE misses things that it should be eliminating + phases.Add(new IrMultiPropSimple()); + } + + if (StageControl.TryAllSupport && + StageControl.IrKeepManager) { + phases.Add(new IrKeepManager(analysisRegistry)); + } +#endif + + if(StageControl.IrStructVectorOperations) { + phases.Add(new IrStruct(true)); + } + + if (StageControl.IrLoadStoreOpt) { + phases.Add(new IrLoadStoreOpt(analysisRegistry)); + } + +#if !VC + if (StageControl.TryAllSupport && + StageControl.AtomicSupportUpdateEnlistOpt) { + phases.Add(new IrSimpleAvoidUpgrade()); + } +#endif + + if (StageControl.IrConvertComplexArrayAccess) { + Convert.ToMir.Mask mask = Convert.ToMir.Mask.ComplexArrayAccess; + phases.Add(new Convert.ToMir(mask)); + } + + if (StageControl.IrConvertExpandedArrayAccess) { + Convert.ToMir.Mask mask = Convert.ToMir.Mask.ExpandedArrayAccess; + phases.Add(new Convert.ToMir(mask)); + } + + if (StageControl.ArraySupportOptimizePass && StageControl.SsaOpts) { + phases.Add(SSAPhase.Create()); + } + +#if !VC + if (StageControl.TryAllSupport && + StageControl.TryAllSupportOptimizePass && + StageControl.SsaOpts) { + phases.Add(SSAPhase.Create()); + } +#endif + + if (StageControl.IrInitStaticField) { + phases.Add(new IrInitStaticField()); + } + + if (StageControl.LazyTypeInits + && StageControl.TypeInitRemoveEmptyCctors) { + phases.Add(new TypeInit(initializerSkips, true)); + } + + if (StageControl.GCType == + StageControl.ReferenceCountingCollector) { + phases.Add(new IrStructRCUpdate()); + } + + if (StageControl.GCType == + StageControl.DeferredReferenceCountingCollector) { + phases.Add(new IrStructDRCUpdate()); + } + + if (StageControl.IrTreeShake && StageControl.IrTreeShakeLate) { + phases.Add(new IrTreeShake(typeData.EntryPoints, + dynamicLoads, + StageControl.WholeProgram, + analysisRegistry)); + } + + if (StageControl.TypedReference) { + phases.Add(new Convert.ToMir(Convert.ToMir.Mask.Vararg1)); + + // All of vararg1 must finish before vararg2, so we wrap vararg2 + // in a typedata phase to enforce that. + phases.Add(new TypeDataMethodPhase + (new Convert.ToMir(Convert.ToMir.Mask.Vararg2))); + } + + /* + // We do not know where all of the calls will be because lowering can + // introduce calls. We make a best guess here. If we moved all + // call-generating lowering to HIR (via ToMir or equivalent), then + // this could be easily done. We are currently missing calls for the + // following: + // - pinvoke, stubs, etc + // - some arithmetic conversions + // - casts - can't add because not all are calls + // - RC, tryall, atomic + // - others? + phases.Add + (new DynamicCount + ("Calls", + new DynamicCount.OpcodeFilter + (Operator.OpCodes.Call, + Operator.OpCodes.CallIndirect, + Operator.OpCodes.CallVirtual, + Operator.OpCodes.InterfaceCall, + Operator.OpCodes.MonitorEnter, + Operator.OpCodes.MonitorExit, + Operator.OpCodes.IndirectToData, + Operator.OpCodes.CustomGetSize, + Operator.OpCodes.CheckVectorStore, + Operator.OpCodes.CheckVectorElementAddress, + Operator.OpCodes.InitVector, + Operator.OpCodes.CheckArrayStore, + Operator.OpCodes.CheckArrayElementAddress, + Operator.OpCodes.InitArray, + Operator.OpCodes.InitType, + Operator.OpCodes.GetITable, + Operator.OpCodes.NewObject, + Operator.OpCodes.NewVector, + Operator.OpCodes.NewArray), + DynamicCount.Granularity.Global)); + phases.Add(new TypeDataDummyPhase()); + phases.Add + (new DynamicCount + ("VirtualCallsEnd", + new DynamicCount.OpcodeFilter + (Operator.OpCodes.CallVirtual, + Operator.OpCodes.InterfaceCall), + DynamicCount.Granularity.PerSite)); + + phases.Add + (new DynamicCount + ("ASCend", + new DynamicCount.OpcodeFilter + (Operator.OpCodes.CheckArrayStore, + Operator.OpCodes.CheckVectorStore), + DynamicCount.Granularity.PerSite)); + phases.Add(new TypeDataDummyPhase()); + + phases.Add + (new DynamicCount + ("WB", + new DynamicCount.OpcodeFilter + (Operator.OpCodes.LocWriteBarrier), + DynamicCount.Granularity.Global)); + phases.Add(new TypeDataDummyPhase()); + */ + + if (StageControl.WholeProgram && StageControl.OptRuntimeData) { + phases.Add(new RuntimeData()); + } + + if (StageControl.IrConvertArrayOpt) { + phases.Add(new IrConvertArrayOpt()); + } + + // insert write barrier after chooserep so we know the size of + // of objects. This is needed because we try to remove write + // barrier when we store to the young generation, however, + // big objects are in the old generation even though it is + // newly created. Therefore, we need to know object size to + // know if it is a big object. + if (StageControl.InsertWriteBarrier) { + phases.Add(new IrWriteBarrier()); + phases.Add(new Convert.ToMir + (Convert.ToMir.Mask.ConvertWriteBarrier)); + } + + // convert type tests and sizeof effect to Mir + Convert.ToMir.Mask typeMask = Convert.ToMir.Mask.CheckCast + | Convert.ToMir.Mask.Sizeof; + if (!(StageControl.GCType == + StageControl.ReferenceCountingCollector || + StageControl.GCType == + StageControl.DeferredReferenceCountingCollector)) { + typeMask |= Convert.ToMir.Mask.GetCurrentThread; + } + if (StageControl.TypedReference) { + typeMask |= Convert.ToMir.Mask.TypedRef; + } + phases.Add(new Convert.ToMir(typeMask)); + + if (StageControl.IrSimpleInliner) { + phases.Add(new IrSimpleInliner(new IrInline(), false, true, + true, 0, 0, 0)); + } + + if(StageControl.TypeInitElim) { + phases.Add(new IrTypeInitElim(analysisRegistry)); + } + + if (StageControl.IrRemoveDoubleCmp) { + phases.Add(new IrCmpElim()); + } + + if (StageControl.IrArrayBaseLength) { + phases.Add(new IrArrayBaseLength()); + phases.Add(new IrDeadAssignmentSimplePhase()); + } + + if (StageControl.IrInitTypeInliner && + StageControl.LazyTypeInits) { + phases.Add(new IrInitTypeInliner(typeData, new IrInline())); + } + + if (StageControl.GCType == + StageControl.ReferenceCountingCollector) { + if (StageControl.RCCollectorShowStatistics) { + String message = "Before RC Update Injection"; + phases.Add(new IrBBStats(message)); + } + + phases.Add(new IrRCUpdate()); + + if (StageControl.RCCollectorShowStatistics) { + String message = "After RC Update Injection"; + phases.Add(new IrBBStats(message)); + } + if (StageControl.RCCollectorOptImmortals) { + phases.Add(new IrImmortalObjectRCUpdates()); + } + if (StageControl.RCCollectorOptRCSubsumed) { + IrSimpleThreadEscape threadLocalObjects = null; + if (StageControl.RCCollectorOptThreadLocalAnalysis) { + IrLockedFields threadSafeFields = null; + if (StageControl.WholeProgram && + StageControl. + RCCollectorOptRCSubsumedByTSFields) { + threadSafeFields = + new IrLockedFields(analysisRegistry); + phases.Add(threadSafeFields); + } + threadLocalObjects = + new IrSimpleThreadEscape(analysisRegistry, + threadSafeFields); + phases.Add(threadLocalObjects); + } + IrRCSubsumedRCUpdates rcSubsumption = + new IrRCSubsumedRCUpdates(analysisRegistry, + fieldAnalysis, + threadLocalObjects); + phases.Add(rcSubsumption); + } + if (StageControl.RCCollectorOptCoalescingUpdates) { + phases.Add(new IrBBLocalCoalesceRCUpdates()); + } + if (StageControl. + RCCollectorOptStaticAcyclicRefTypeUpdates) { + phases.Add(new IrAcyclicRefTypeRCUpdates()); + } + if (StageControl.RCCollectorOptNonNullRCUpdates) { + phases.Add(SSAPhase.NullCheckAnalysis()); + } + if (StageControl.RCCollectorShowStatistics) { + String message = "After RC Optimizations"; + phases.Add(new IrBBStats(message)); + } + + Convert.ToMir.Mask mask = Convert.ToMir.Mask.RCUpdate | + Convert.ToMir.Mask.GetCurrentThread; + phases.Add(new Convert.ToMir(mask)); + if (StageControl.RCCollectorOptInlineRCUpdates && + StageControl.IrSimpleInliner) { + phases.Add(new IrSimpleInliner(new IrInline(), + true, + false, + true)); + } + phases.Add(new TypeDataDummyPhase()); + } + + if (StageControl.GCType == + StageControl.DeferredReferenceCountingCollector) { + if (StageControl.RCCollectorShowStatistics) { + String message = "Before DRC Update Injection"; + phases.Add(new IrBBStats(message)); + } + + phases.Add(new IrDRCUpdate()); + + if (StageControl.RCCollectorShowStatistics) { + String message = "After DRC Update Injection"; + phases.Add(new IrBBStats(message)); + } + if (StageControl.RCCollectorOptImmortals) { + phases.Add(new IrImmortalObjectRCUpdates()); + } + if (StageControl.RCCollectorOptCoalescingUpdates) { + phases.Add(new IrBBLocalCoalesceRCUpdates()); + } + if (StageControl. + RCCollectorOptStaticAcyclicRefTypeUpdates) { + phases.Add(new IrAcyclicRefTypeRCUpdates()); + } + if (StageControl.RCCollectorOptNonNullRCUpdates) { + phases.Add(SSAPhase.NullCheckAnalysis()); + } + if (StageControl.RCCollectorShowStatistics) { + String message = "After DRC Optimizations"; + phases.Add(new IrBBStats(message)); + } + + Convert.ToMir.Mask mask = Convert.ToMir.Mask.RCUpdate | + Convert.ToMir.Mask.GetCurrentThread; + phases.Add(new Convert.ToMir(mask)); + if (StageControl.RCCollectorOptInlineRCUpdates && + StageControl.IrSimpleInliner) { + phases.Add(new IrSimpleInliner(new IrInline(), + true, + false, + true)); + } + phases.Add(new TypeDataDummyPhase()); + } + + +#if !VC + if(StageControl.TryAllSupport && + StageControl.TryAllDecomposeOpt) { + phases.Add(new IrDecomposeTransMemChecks(analysisRegistry)); + // IrDecomposeTransMemChecks emits GetCurrentThread ops + phases.Add(new IrLoadStoreOpt(analysisRegistry)); + Convert.ToMir.Mask mask = Convert.ToMir.Mask.GetCurrentThread; + phases.Add(new Convert.ToMir(mask)); + } + + if (StageControl.TryAllSupport && + StageControl.IrConvertTryAll) { + Convert.ToMir.Mask mask = Convert.ToMir.Mask.TryAll; + phases.Add(new Convert.ToMir(mask)); + if (StageControl.IrSimpleInliner) { + phases.Add(new IrSimpleInliner(new IrInline(), + true, + false)); + } + } +#endif + + // The inliners may inline some of the methods that handle special + // MSIL opcodes, adding in instructions like Id that we + // don't expect to see this late in the lowering. Add one more + // scan of the code to remove them. + phases.Add(new Convert.IrInsertStructCopy()); + + if (StageControl.IrTreeShake && StageControl.IrTreeShakeLate) { + phases.Add(new IrTreeShake(typeData.EntryPoints, + dynamicLoads, + StageControl.WholeProgram, + analysisRegistry)); + } + + if (StageControl.PtrAnalysis) { + phases.Add(PtrTypeSimpleSystem.CreateAnalysis()); + phases.Add(PtrTypeHierarchySystem.CreateAnalysis()); + phases.Add(PtrTypeSetSystem.CreateAnalysis()); + } + + if (StageControl.PrintContainers) { + phases.Add(new TypeDataPrintPhase("end of HIR:")); + } + } + + public static ArrayList fileNames; + public static ArrayList refFileNames; + public static ArrayList libDirNames; + private static ArrayList outputDirNames; + public static String outputDirName; + public static ArrayList overrideNames; + public static ArrayList overrideDefNames; + public static String outputRootName; + public static ArrayList entryPoints; + public static ArrayList linkNames; + private static ArrayList initializerSkips; + private static ArrayList dynamicLoads; + private static bool alreadyPrintedUsage = false; + + private static String StripName(String fileName) { + // strip off extension, if there is one. + int dotIndex = fileName.LastIndexOf('.'); + if (dotIndex != -1) { + String ext = fileName.Substring(dotIndex + 1); + if (ext.Equals("dll") || ext.Equals("obj") + || ext.Equals("exe")) { + fileName = fileName.Substring(0, dotIndex); + } + } + return fileName; + } + + private static String GetShortName(String fileName) { + int charindex = Math.Max(fileName.LastIndexOf('/'), + fileName.LastIndexOf('\\')); + String shortName = (charindex >= 0) + ? fileName.Substring(charindex + 1) + : fileName; + return shortName; + } + + private static String GetDirName(String fileName) { + int charindex = Math.Max(fileName.LastIndexOf('/'), + fileName.LastIndexOf('\\')); + String dirName = (charindex >= 0) + ? fileName.Substring(0, charindex + 1) + : ""; + return dirName; + } + + private static String ComputeOutputName(String inputFileName, + String outputDirName) { + String fileName = Path.GetFileNameWithoutExtension(inputFileName); + String outputName = outputDirName + '\\' + fileName; + return outputName; + } + + private static void ProcessCmdLine(String[] args) { + fileNames = new ArrayList(); + refFileNames = new ArrayList(); + libDirNames = new ArrayList(); + overrideNames = new ArrayList(); + overrideDefNames = new ArrayList(); + outputDirNames = new ArrayList(); + entryPoints = new ArrayList(); + initializerSkips = new ArrayList(); + linkNames = new ArrayList(); + dynamicLoads = new ArrayList(); + int index = 0; +#if ON_SINGULARITY + index = 1; +#endif + while (index < args.Length) { + String argument = args[index]; + if ((argument[0] == '-') || (argument[0] == '/')) { + String option = argument.Substring(1); + ProcessOption(argument, option, args, ref index); + } else { + index++; + fileNames.Add(argument); + } + } + switch (outputDirNames.Count) { + case 0: { + outputDirName = ".\\debug"; + break; + } + case 1: { + outputDirName = (String)outputDirNames[0]; + break; + } + default: { + Util.Error("Error: specified multiple output directories {0}", + new CollectionFormatter(outputDirNames)); + break; + } + } + + if((StageControl.GCType == StageControl.ReferenceCountingCollector) + && StageControl.StructInheritance) { + Util.Abort("Error: RC Collector code has not been updated to " + + "handle struct inheritance"); + } + if((StageControl.GCType == + StageControl.DeferredReferenceCountingCollector) + && StageControl.StructInheritance) { + Util.Abort("Error: Deferred RC Collector code has not been updated to " + + "handle struct inheritance"); + } + } + + private static void ProcessOption(String argument, String option, + String[] args, ref int index) { + String loweredOption = option.ToLower(); + String optionValue; + + if (IsOption(args, option, loweredOption, "entry:", + ref index, out optionValue)) { + AddSemicolonDelimitedNames(entryPoints, optionValue); + } else if (IsOption(args, option, loweredOption, "reference:", + ref index, out optionValue) + || IsOption(args, option, loweredOption, "r:", + ref index, out optionValue)) { + AddSemicolonDelimitedNames(refFileNames, optionValue); + } else if (IsOption(args, option, loweredOption, "bartoklink:", + ref index, out optionValue)) { + AddSemicolonDelimitedNames(linkNames, optionValue); + } else if (IsOption(args, option, loweredOption, "override:", + ref index, out optionValue)) { + AddSemicolonDelimitedNames(overrideNames, optionValue); + } else if (IsOption(args, option, loweredOption, "overridedef:", + ref index, out optionValue)) { + AddSemicolonDelimitedNames(overrideDefNames, optionValue); + } else if (IsOption(args, option, loweredOption, "lib:", + ref index, out optionValue)) { + AddSemicolonDelimitedNames(libDirNames, optionValue); + } else if (IsOption(args, option, loweredOption, "out:", + ref index, out optionValue)) { + outputRootName = optionValue; + } else if (IsOption(args, option, loweredOption, "outdir:", + ref index, out optionValue)) { + AddSemicolonDelimitedNames(outputDirNames, optionValue); + } else if (IsOption(args, option, loweredOption, "skip:", + ref index, out optionValue)) { + AddSemicolonDelimitedNames(initializerSkips, optionValue); + } else if (IsOption(args, option, loweredOption, "substitute:", + ref index, out optionValue)) { + StageControl.substituteString = optionValue; + } else if (IsOption(args, option, loweredOption, "disable:", + ref index, out optionValue)) { + StageControl.disabledPhaseNames.Add(optionValue); + } else if (IsOption(args, option, loweredOption, "dynamicload:", + ref index, out optionValue)) { + AddSemicolonDelimitedNames(dynamicLoads, optionValue); + } else if (IsOption(args, option, loweredOption, "features:", + ref index, out optionValue)) { + StageControl.mixinConditionals = + StageControl.mixinConditionals + "," + optionValue; + } else if (IsOption(args, option, loweredOption, "noisymethod:", + ref index, out optionValue)) { + StageControl.noisyMethodNames.Add(optionValue); + //Util.Message("noisyMethodNames=" + // + StageControl.noisyMethodNames); + } else if (IsOption(args, option, loweredOption, "debugmethod:", + ref index, out optionValue)) { + StageControl.debugMethodNames.Add(optionValue); + StageControl.noisyMethodNames.Add(optionValue); + //Util.Message("debugMethodNames=" + // + StageControl.debugMethodNames); + } else if (IsOption(args, option, loweredOption, "verbosity:", + ref index, out optionValue)) { + Verbosity.FromString(optionValue); + } else if (IsOption(args, option, loweredOption, "marksweepgc", + ref index, out optionValue)) { + StageControl.GCType = StageControl.MarkSweepCollector; + StageControl.GCLargeObjectSize = 2040; + StageControl.InlineSegregatedFreeList = true; + StageControl.InsertWriteBarrier = false; + } else if (IsOption(args, option, loweredOption, "semispacegc", + ref index, out optionValue)) { + StageControl.GCType = StageControl.SemispaceCollector; + StageControl.InsertWriteBarrier = true; + } else if (IsOption(args, option, loweredOption, "slidinggc", + ref index, out optionValue)) { + StageControl.GCType = StageControl.SlidingCollector; + StageControl.InsertWriteBarrier = true; + } else if (IsOption(args, option, loweredOption, "adaptivecopyinggc", + ref index, out optionValue)) { + StageControl.GCType = StageControl.AdaptiveCopyingCollector; + StageControl.InsertWriteBarrier = true; + } else if (IsOption(args, option, loweredOption, + "referencecountinggc", + ref index, out optionValue)) { + StageControl.GCType = StageControl.ReferenceCountingCollector; + StageControl.InsertWriteBarrier = false; + StageControl.GCInlineAllocations = false; + StageControl.mixinConditionals = + StageControl.mixinConditionals + ",ReferenceCountingGC"; + if (StageControl.RCCollectorVerifyRefCounts) { + StageControl.UseVTableBits = true; + StageControl.mixinConditionals = + StageControl.mixinConditionals + + ",ReferenceCountingGCVerification"; + } + } else if (IsOption + (args, option, loweredOption, "deferredreferencecountinggc", + ref index, out optionValue)) { + + StageControl.GCType = StageControl.DeferredReferenceCountingCollector; + StageControl.InsertWriteBarrier = false; + StageControl.GCInlineAllocations = false; + StageControl.mixinConditionals = + StageControl.mixinConditionals + ",DeferredReferenceCountingGC"; + if (StageControl.RCCollectorVerifyRefCounts) { + StageControl.UseVTableBits = true; + StageControl.mixinConditionals = + StageControl.mixinConditionals + + ",DeferredReferenceCountingGCVerification"; + } + } else if (IsOption(args, option, loweredOption, "concurrentmsgc", + ref index, out optionValue)) { + StageControl.GCType = StageControl.ConcurrentMSCollector; + StageControl.GCLargeObjectSize = 2040; + StageControl.Wb = StageControl.WbCMS; + StageControl.GCInlineAllocations = false; + StageControl.InlineSegregatedFreeList = true; + StageControl.PreWriteBarrier = true; + StageControl.InsertWriteBarrier = true; + StageControl.GCInlineWriteBarrier = false; + StageControl.GCWriteBarrierTracksStaticFields = true; + StageControl.mixinConditionals = + StageControl.mixinConditionals + ",ConcurrentMSGC"; + } else if (IsOption(args, option, loweredOption, "nullgc", + ref index, out optionValue)) { + StageControl.GCType = StageControl.NullCollector; + StageControl.InsertWriteBarrier = false; + } else if (IsOption(args, option, loweredOption, "atomicrcgc", + ref index, out optionValue)) { + StageControl.GCType = StageControl.AtomicRCCollector; + StageControl.GCLargeObjectSize = 2040; + StageControl.Wb = StageControl.WbARC; + StageControl.GCInlineAllocations = false; + StageControl.InlineSegregatedFreeList = true; + StageControl.InsertWriteBarrier = true; + StageControl.GCInlineWriteBarrier = false; + StageControl.GCWriteBarrierTracksStaticFields = true; + } else if (IsOption(args, option, loweredOption, "minopt", + ref index, out optionValue)) { + StageControl.SsaOpts = false; + StageControl.IrInterfaceElim = false; + StageControl.DevirtualizeCall = false; + StageControl.IrTypeTestElimPunt = false; + StageControl.IrTypeTestElim = false; + StageControl.IrSimpleInliner = false; + + // IR clean up optimizations + StageControl.IrDeadAssignmentSimple2 = false; + StageControl.IrCleanupStructOperations = false; + StageControl.IrShortCircuitBBlocks = false; + StageControl.IrTreeShakeLate = false; + StageControl.IrArrayLoadStoreOpt = false; + StageControl.IrConvertSimpleArrayAccess = false; + + // from the backend + StageControl.RegAllocCoalesce = false; + StageControl.RegAllocSpill = StageControl.SpillOptimizeSinglePass; + StageControl.OptLirCompactify = false; + StageControl.OptLirGlobalConstantProp = false; + StageControl.OptLirLocalConstantProp = true; + StageControl.OptLirImproveCC = false; + StageControl.OptLirPeephole = false; + StageControl.OptLirReverseCSE = false; + StageControl.OptLirGlobalCopyProp = false; + StageControl.OptLirLocalCopyProp = true; + StageControl.LayoutLoopHeaderLast = false; + + if (StageControl.SymbolicDebug) { + StageControl.OptimizeLocals = false; + } + } else if (IsOption(args, option, loweredOption, "nohiropt", + ref index, out optionValue)) { + StageControl.ABCD = false; + StageControl.DevirtualizeCall = false; + StageControl.IdentifyAsMethods = false; + StageControl.IrAttributeInliner = false; + StageControl.IrBBLocalCopyProp = false; + StageControl.IrCleanup = false; + StageControl.IrCleanupStructOperations = false; + StageControl.IrCloneLoopHeader = false; + StageControl.IrConvertOpt = false; + StageControl.IrDeadAssignmentSimple1 = false; + StageControl.IrDeadAssignmentSimple2 = false; + StageControl.IrInitStaticField = false; + StageControl.IrInterfaceElim = false; + StageControl.IrJumpElim = false; + StageControl.IrLoadStoreOpt = false; + StageControl.IrMultiPropSimple = false; + StageControl.IrPeepholeNull = false; + StageControl.IrRemoveDoubleCmp = false; + StageControl.IrReverseCopyProp = false; + StageControl.IrShortCircuitBBlocks = false; + StageControl.IrSimpleInliner = false; + StageControl.IrStoreChecks = false; + StageControl.IrTreeShakeLate = false; + StageControl.IrTypeTestElimPunt = false; + StageControl.SsaArraySimple = false; + StageControl.SsaDeadCode = false; + StageControl.SsaLoopInv = false; + StageControl.SsaNullCheck = false; + StageControl.SsaOpts = false; + StageControl.TypeInitRemoveEmptyCctors = false; + StageControl.UnmanagedStrings = false; + } else if (IsOption(args, option, loweredOption, "singularity", + ref index, out optionValue)) { + StageControl.SingSharpTemplateRemover = true; + StageControl.DisablePInvoke = true; + StageControl.StrictEcma = true; + StageControl.CustomAllocatorTypes = true; + StageControl.SurrogateBoxing = true; + StageControl.StructInheritance = true; + StageControl.IrTreeShakeCreatePointedToStructs = true; + StageControl.IrTreeShakeLate = false; // not tested + StageControl.TypeInitRemoveEmptyCctors = false; // not tested + StageControl.CheckNoHeapAllocation = true; + } else if (IsOption(args, option, loweredOption, "verbosehelp", + ref index, out optionValue)) { + PrintUsage(); + StageControl.PrintUsage(); + } else if (IsOption(args, option, loweredOption, "verbosehelpalpha", + ref index, out optionValue)) { + PrintUsage(); + StageControl.PrintUsageAlpha(); + } else if (IsOption(args, option, loweredOption, "x86", + ref index, out optionValue)) { + StageControl.TargetArch = StageControl.X86; + StageControl.Target64Bit = false; + } else if (IsOption(args, option, loweredOption, "x64", + ref index, out optionValue)) { + StageControl.TargetArch = StageControl.X64; + StageControl.Target64Bit = true; + } else if (IsOption(args, option, loweredOption, "help", + ref index, out optionValue) + || IsOption(args, option, loweredOption, "?", + ref index, out optionValue)) { + PrintUsage(); + } else if (IsOption + (args, option, loweredOption, "centralpt", + ref index, out optionValue)) { + StageControl.PTType = StageControl.CentralPT; + } else if (IsOption + (args, option, loweredOption, "centralpthimem", + ref index, out optionValue)) { + StageControl.PTType = StageControl.CentralPTHimem; + } else if (IsOption + (args, option, loweredOption, "flatdistributedpt", + ref index, out optionValue)) { + StageControl.PTType = StageControl.FlatDistributedPT; + } else if (IsOption + (args, option, loweredOption, "flatdistributedtestpt", + ref index, out optionValue)) { + StageControl.PTType = StageControl.FlatDistributedPTTest; + } else if (StageControl.SetOptionFromCommandLine(loweredOption)) { + index++; + } else if (loweredOption.StartsWith("stagecontrol")) { + Util.AbortUserCE("/stagecontrol no longer supported; " + + "use the option directly"); + } else { + Util.AbortUserCE("Unknown option: " + option); + } + } + + private static bool IsOption(String[] args, + String option, String loweredOption, + String possibleOptionName, + ref int index, out String optionValue) { + if(possibleOptionName.EndsWith(":")) { + if(loweredOption.StartsWith(possibleOptionName)) { + index++; + if(option.Length == possibleOptionName.Length) { + // case: "/option: value" + optionValue = args[index++]; + } else { + // case: "/option:value" + optionValue = option.Substring(possibleOptionName.Length); + } + return true; + } + } else { + if(loweredOption == possibleOptionName) { + index++; + optionValue = null; + return true; + } + } + + optionValue = null; + return false; + } + + private static void AddSemicolonDelimitedNames(ArrayList names, + String argument) { + int index = 0; + StringBuilder buf = new StringBuilder(); + while (index < argument.Length) { + if (argument[index] != ';') { + buf.Append(argument[index]); + index++; + } + else { + if (buf.Length > 0) { + names.Add(buf.ToString()); + buf = new StringBuilder(); + } + index++; + } + } + names.Add(buf.ToString()); + } + + public static void PrintUsage() { + if (alreadyPrintedUsage) { + return; + } + alreadyPrintedUsage = true; + Util.Message( +@"Usage: + bartok [options] files + +Bartok main options (case insensitive): + /entry: ;;... specify entry points + /reference: ;;... reference metadata from assembly files + /r: ;;... short form of /reference: + /bartoklink: ;;... reference precompiled object files + /override: ;;... files overriding /r: metadata + /lib: ;;... additional dirs to search for references + /out: output file name + /outdir: dir for output .exe, asm, obj, etc. + (defaults to .\\debug) + /skip: ;;... specify type initializers to disable + if building static ordering + /substitute:=, rename TypeRefs before performing lookup + =,... + /disable: disable a phase + /dynamicload: make type available for dynamic loading + /features: << TODO >> + /noisymethod: enable noisy output for meth + /debugmethod: enable debug+noisy output for meth + /verbosity: set output level {Silence,PerPhase, + PerClass,PerMethod,PerBlock, + PerInstruction} (defaults to PerPhase) + /marksweepgc compile for mark-sweep collector + /semispacegc compile for semispace collector + /slidinggc compile for sliding collector + /adaptivecopyinggc compile for semispace-sliding hybrid + collector + /referencecountinggc compile for reference counting collector + /deferredreferencecountinggc compile for deferred reference counting collector + /concurrentmsgc compile for concurrent mark-sweep + collector + /nullgc compile for no collector + /minopt disable most optimizations + /nohiropt disable all HIR optimizations + /singularity set default Singularity options + /verbosehelp help message including stage control + options by category + /verbosehelpalpha help message including stage control + options in alphabetical order + /help or /? help message"); + } + } + + internal class MetaDataOutput : Bartok.MSIL.IMetaDataOutput { + public TextWriter Log { get { return Util.Log; } } + public TextWriter ErrorOut { get { return Util.ErrorOut; } } + public TextWriter WarnOut { get { return Util.WarnOut; } } + + public void Error(string msg) + { + Util.Error(msg); + } + + public void Error(string format, params Object[] objs) + { + Util.Error(format, objs); + } + + public void ErrorDetail(string msg) + { + Util.ErrorDetail(msg); + } + + public void Warn(string msg) + { + Util.Warn(msg); + } + + public void Warn(string format, params Object[] objs) + { + Util.Warn(format, objs); + } + + public void WarnDetail(string msg) + { + Util.WarnDetail(msg); + } + + public void Message(string msg) + { + Util.Message(msg); + } + } +} diff --git a/base/Applications/Benchmarks/BartokH/host/BartokHHost.csproj b/base/Applications/Benchmarks/BartokH/host/BartokHHost.csproj new file mode 100644 index 0000000..00f16d1 --- /dev/null +++ b/base/Applications/Benchmarks/BartokH/host/BartokHHost.csproj @@ -0,0 +1,48 @@ + + + + + + Exe + bartok + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/base/Applications/Benchmarks/BartokH/host/Proxy.sg b/base/Applications/Benchmarks/BartokH/host/Proxy.sg new file mode 100644 index 0000000..a15127a --- /dev/null +++ b/base/Applications/Benchmarks/BartokH/host/Proxy.sg @@ -0,0 +1,392 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Proxy.sg +// +// Note: Compiler Phase +// + +//#define DO_LOCAL + +using Microsoft.SingSharp; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Endpoint; +using Microsoft.Singularity.V1.Services; + +using System; +using System.Runtime.CompilerServices; +using System.Threading; + +using Microsoft.Singularity; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Extending; +using Microsoft.Singularity.Configuration; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; + +using Bartok.Contracts; +using Bartok.Analysis.Lir; +using Bartok.Convert; +using Bartok.Datatype; +using Bartok.CfgUtil; +using Bartok.Lir; +using Bartok.Opt.Lir; +using Bartok.Utility; +using Bartok.DebugInfo; +using Bartok.Regalloc; +using Bartok.Marshal; +using Bartok.Regalloc; + +namespace Bartok.Regalloc +{ + public class GraphColoring : Phase{ + private CheapState! cs; + private VContainer bufferData; +#if DO_LOCAL + private GraphColoringReal gcr; +#else + private TRef child; +#endif + + private static void ReadOpen(CheapState! cs, byte[]! in ExHeap bytes) + { + uint regionSize; + uint region; + regionSize = (uint)bytes.Length; + unsafe { + fixed (byte *pdst = &bytes[0]) { + region = (uint)pdst; + cs.ReadOpen(region, regionSize); + } + } + } + + private static void ReadClose(CheapState! cs) + { +#if false + if (cs.oig != null) { + DebugStub.WriteLine("--- Proxy.Read Close {0,8} bytes {1,5} objects", + __arglist(cs.read, cs.loadCount)); + } +#endif + cs.ReadClose(); + } + + private static void WriteOpen(CheapState! cs, byte[]! in ExHeap bytes) + { + uint regionSize; + uint region; + regionSize = (uint)bytes.Length; + unsafe { + fixed (byte *pdst = &bytes[0]) { + region = (uint)pdst; + cs.WriteOpen(region, regionSize); + } + } + } + + private static void WriteClose(CheapState! cs) + { +#if false + if (cs.oig != null) { + DebugStub.WriteLine("--- Proxy.WriteClose {0,8} bytes {1,5} objects", + __arglist(cs.used, cs.oig.m_currentCount)); + } +#endif + cs.WriteClose(); + } + + [Microsoft.Contracts.NotDelayed] + public GraphColoring(RegDesc regs, CallConv conv, AbstractTarget target, + GlobalLayoutData globalLayoutData, + int pageSize, int stackThreshhold, + bool isNoisy) + { + CheapMarshal.InitTypes(); + + cs = new CheapState(0, true); + base(); +#if false + + Console.WriteLine("-------- GraphColoring Init -----"); + DebugStub.WriteLine("-------- GraphColoring::Proxy Init -----"); +#endif + +#if DO_LOCAL + gcr = new GraphColoringReal(regs, + conv, + target, + globalLayoutData, + pageSize, + stackThreshhold, + isNoisy); +#else // !DO_LOCAL + // Make a new channel. + CompilerPhaseContract.Imp! cp; + CompilerPhaseContract.Exp! ep; + CompilerPhaseContract.NewChannel(out cp, out ep); + + // Start up our child + string[] args = new string[3]; + args[0] = "BartokP.x86"; + args[1] = "-where"; + args[2] = "!"; + Process cproc = new Process(args, (Endpoint * in ExHeap)ep); + + // set the where parameter to true + ParameterCode code; + code = cproc.SetStartupBoolArg(0, true); + if (code != ParameterCode.Success){ + Console.WriteLine("unable to set bool index 0. error={0}", code); + delete cp; + return; + } + + byte[]! in ExHeap bytes = (!)new [ExHeap] byte [2 * 1024 * 1024]; + + cproc.Start(); + + // Track statics before they can be replicated in a method call. + RegisterX86.TrackAsGlobal(cs); + OpCodesX86.TrackAsGlobal(cs); + + cp.RecvReadyToInit(); + + StageControlProxy controls = new StageControlProxy(); + controls.GetValues(); + + ulong beg = Processor.GetCycleCount(); + WriteOpen(cs, bytes); + RegDesc.CheapWrite(cs, regs); + CallConv.CheapWrite(cs, conv); + AbstractTarget.CheapWrite(cs, target); + GlobalLayoutData.CheapWrite(cs, globalLayoutData); + cs.Write(pageSize); + cs.Write(stackThreshhold); + cs.Write(isNoisy); + CSRT.CheapWrite(cs, CSRT.runtime); + StageControlProxy.CheapWrite(cs, controls); + WriteClose(cs); + DebugStub.AddToPerfCounter(0, Processor.GetCycleCount() - beg); + + //DebugStub.WriteLine(":: Host Targ Globals"); + target.TrackAsGlobal(cs); + //DebugStub.WriteLine(":: Host Regs Globals"); + regs.TrackAsGlobal(cs); + //DebugStub.WriteLine(":: Host Conv Globals"); + conv.TrackAsGlobal(cs); + //DebugStub.WriteLine(":: Host CSRT Globals"); + CSRT.runtime.TrackAsGlobal(cs); + + //cs.DumpGlobal("host"); + + cp.SendInitPhaseReq(bytes); +#if USE_SWITCH_RECEIVE + switch receive + { + case cp.InitPhaseRsp(byte[]! in ExHeap obytes): + ReadOpen(cs, obytes); + ReadClose(cs); + bufferData = new VContainer (obytes); + child = new TRef(cp); + return; + case cp.ChannelClosed(): + Console.WriteLine("Child closed channel!"); + throw new Exception("Child closed channel!"); + } +#else + byte[]! in ExHeap obytes; + cp.RecvInitPhaseRsp(out obytes); + ReadOpen(cs, obytes); + ReadClose(cs); + bufferData = new VContainer (obytes); + child = new TRef(cp); +#endif +#endif // !DO_LOCAL + } + + private string GetPhaseName() + { +#if DO_LOCAL + return gcr.PhaseName; +#else // !DO_LOCAL + if (child == null) { + Console.WriteLine("!!! Internal Error!"); + return ""; + } + +#if USE_SWITCH_RECEIVE + CompilerPhaseContract.Imp! cp = child.Acquire(); + + cp.SendGetPhaseNameReq(); + switch receive + { + case cp.GetPhaseNameRsp(char[]! in ExHeap name): + string ph = Bitter.ToString(name); + child.Release(cp); + delete name; + return ph; + case cp.ChannelClosed(): + Console.WriteLine("Child closed channel!"); + throw new Exception("Child closed channel!"); + } +#else + return "[regalloc]"; +#endif +#endif // !DO_LOCAL + } + + public override string PhaseName + { + get { + return GetPhaseName(); + } + } + + public override void Term() + { +#if DO_LOCAL + gcr.Term(); +#else // !DO_LOCAL + if (child == null) { + Console.WriteLine("!!! Internal Error!"); + return; + } + +#if USE_SWITCH_RECEIVE + CompilerPhaseContract.Imp! cp = child.Acquire(); + + cp.SendTermPhaseReq(); + switch receive + { + case cp.TermPhaseRsp(): + ReadOpen(cs, obytes); + ReadClose(cs); + child.Release(cp); + return; + case cp.ChannelClosed(): + Console.WriteLine("Child closed channel!"); + throw new Exception("Child closed channel!"); + } +#else + if (bufferData == null) { + Console.WriteLine("!!! Internal Error!"); + return; + } + + CompilerPhaseContract.Imp! cp = child.Acquire(); + byte[]! in ExHeap bytes = bufferData.Acquire(); + WriteOpen(cs, bytes); + WriteClose(cs); + cp.SendRequest((int)RequestKind.Terminate, bytes); + cp.RecvResponse(out bytes); + ReadOpen(cs, bytes); + ReadClose(cs); + bufferData.Release(bytes); + child.Release(cp); +#endif +#endif // !DO_LOCAL + } + + protected override void run(FunctionDef f, object r) + { +#if DO_LOCAL + gcr.Go(f, r); +#else // !DO_LOCAL + if (child == null || bufferData == null || f == null || r == null) { + Console.WriteLine("!!! Internal Error!"); + return; + } + +#if false + Console.WriteLine("-------- GraphColoring Run {0} -----", f.ToString()); +#endif + + CompilerPhaseContract.Imp! cp = child.Acquire(); + byte[]! in ExHeap bytes = bufferData.Acquire(); + + ulong beg = Processor.GetCycleCount(); + WriteOpen(cs, bytes); + FunctionDef.CheapWrite(cs, f); + ChooseRepResult.CheapWrite(cs, (ChooseRepResult)r); + WriteClose(cs); + DebugStub.AddToPerfCounter(0, Processor.GetCycleCount() - beg); + +#if USE_SWITCH_RECEIVE + cp.SendProcessFunctionReq(bytes); + switch receive + { + case cp.ProcessFunctionRsp(obytes): + beg = Processor.GetCycleCount(); + ReadOpen(cs, obytes); + OperandArray.CheapRead(cs, out f.actualArgs); + LirBasicBlock.CheapRead(cs, out f.prolog); + LirBasicBlock.CheapRead(cs, out f.epilog); + LirBasicBlock.CheapRead(cs, out f.unwind); + cs.Read(out f.omitFramePointer); + cs.Read(out f.spillSlotCount); + Operand.CheapRead(cs, out f.stackSlotMap); + SequencedCfg.CheapRead(cs, out f.code); + OperandArray.CheapRead(cs, out f.pinned); + OperandArray.CheapRead(cs, out f.formals); + Operand.CheapRead(cs, out f.ret); + ReadClose(cs); + DebugStub.AddToPerfCounter(3, Processor.GetCycleCount() - beg); + + bufferData.Release(obytes); + child.Release(cp); + return; + + case cp.ChannelClosed(): + Console.WriteLine("Child closed channel!"); + throw new Exception("Child closed channel!"); + } +#else + cp.SendRequest((int)RequestKind.ProcessFunction, bytes); + cp.RecvResponse(out bytes); + + beg = Processor.GetCycleCount(); + ReadOpen(cs, bytes); + OperandArray.CheapRead(cs, out f.actualArgs); + LirBasicBlock.CheapRead(cs, out f.prolog); + LirBasicBlock.CheapRead(cs, out f.epilog); + LirBasicBlock.CheapRead(cs, out f.unwind); + cs.Read(out f.omitFramePointer); + cs.Read(out f.spillSlotCount); + Operand.CheapRead(cs, out f.stackSlotMap); + SequencedCfg.CheapRead(cs, out f.code); + OperandArray.CheapRead(cs, out f.pinned); + OperandArray.CheapRead(cs, out f.formals); + Operand.CheapRead(cs, out f.ret); + ReadClose(cs); + DebugStub.AddToPerfCounter(3, Processor.GetCycleCount() - beg); + + bufferData.Release(bytes); + child.Release(cp); +#endif +#endif // !DO_LOCAL + } + +#if TIMING + private const string componentName = "Back End Coloring"; + private static int componentId; + private const string allocFunctionName = "Back End Coloring allocFunction"; + private static int allocFunctionId; + private const string deadCodeName = "Back End Coloring dead code elimination"; + private static int deadCodeId; + private const string copyPropName = "Back End Coloring copy propagation"; + private static int copyPropId; + private const string coalesceName = "Back End Coloring coalescing"; + private static int coalesceId; + private const string interferenceName = "Back End Coloring interference"; + private static int interferenceId; + private const string colorAndSpillName = "Back End Coloring ColorAndSpill"; + private static int colorAndSpillId; + private const string coloringName = "Back End Coloring Coloring"; + private static int coloringId; +#endif + } /* class GraphColoring */ +} diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Analysis.dll b/base/Applications/Benchmarks/BartokH/msil/Bartok.Analysis.dll new file mode 100644 index 0000000..5049227 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Analysis.dll differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Analysis.pdb b/base/Applications/Benchmarks/BartokH/msil/Bartok.Analysis.pdb new file mode 100644 index 0000000..35e4bf3 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Analysis.pdb differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Backend.dll b/base/Applications/Benchmarks/BartokH/msil/Bartok.Backend.dll new file mode 100644 index 0000000..535c600 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Backend.dll differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Backend.pdb b/base/Applications/Benchmarks/BartokH/msil/Bartok.Backend.pdb new file mode 100644 index 0000000..27f1b84 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Backend.pdb differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.CfgUtil.dll b/base/Applications/Benchmarks/BartokH/msil/Bartok.CfgUtil.dll new file mode 100644 index 0000000..512bba1 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.CfgUtil.dll differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.CfgUtil.pdb b/base/Applications/Benchmarks/BartokH/msil/Bartok.CfgUtil.pdb new file mode 100644 index 0000000..80d2018 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.CfgUtil.pdb differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Cheap.dll b/base/Applications/Benchmarks/BartokH/msil/Bartok.Cheap.dll new file mode 100644 index 0000000..9dd951e Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Cheap.dll differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Cheap.pdb b/base/Applications/Benchmarks/BartokH/msil/Bartok.Cheap.pdb new file mode 100644 index 0000000..48f438a Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Cheap.pdb differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Coff.dll b/base/Applications/Benchmarks/BartokH/msil/Bartok.Coff.dll new file mode 100644 index 0000000..4976de4 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Coff.dll differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Coff.pdb b/base/Applications/Benchmarks/BartokH/msil/Bartok.Coff.pdb new file mode 100644 index 0000000..fe11439 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Coff.pdb differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Convert.dll b/base/Applications/Benchmarks/BartokH/msil/Bartok.Convert.dll new file mode 100644 index 0000000..ce7a174 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Convert.dll differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Convert.pdb b/base/Applications/Benchmarks/BartokH/msil/Bartok.Convert.pdb new file mode 100644 index 0000000..994861c Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Convert.pdb differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Datatype.dll b/base/Applications/Benchmarks/BartokH/msil/Bartok.Datatype.dll new file mode 100644 index 0000000..b36dadd Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Datatype.dll differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Datatype.pdb b/base/Applications/Benchmarks/BartokH/msil/Bartok.Datatype.pdb new file mode 100644 index 0000000..02d8276 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Datatype.pdb differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.DebugInfo.dll b/base/Applications/Benchmarks/BartokH/msil/Bartok.DebugInfo.dll new file mode 100644 index 0000000..5d7a962 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.DebugInfo.dll differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.DebugInfo.pdb b/base/Applications/Benchmarks/BartokH/msil/Bartok.DebugInfo.pdb new file mode 100644 index 0000000..b79fc31 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.DebugInfo.pdb differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Encode.dll b/base/Applications/Benchmarks/BartokH/msil/Bartok.Encode.dll new file mode 100644 index 0000000..85fb9b2 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Encode.dll differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Encode.pdb b/base/Applications/Benchmarks/BartokH/msil/Bartok.Encode.pdb new file mode 100644 index 0000000..cba2032 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Encode.pdb differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Ir.dll b/base/Applications/Benchmarks/BartokH/msil/Bartok.Ir.dll new file mode 100644 index 0000000..fa413fa Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Ir.dll differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Ir.pdb b/base/Applications/Benchmarks/BartokH/msil/Bartok.Ir.pdb new file mode 100644 index 0000000..15507f2 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Ir.pdb differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Lir.dll b/base/Applications/Benchmarks/BartokH/msil/Bartok.Lir.dll new file mode 100644 index 0000000..d6acec1 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Lir.dll differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Lir.pdb b/base/Applications/Benchmarks/BartokH/msil/Bartok.Lir.pdb new file mode 100644 index 0000000..b49d630 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Lir.pdb differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.MSIL.dll b/base/Applications/Benchmarks/BartokH/msil/Bartok.MSIL.dll new file mode 100644 index 0000000..2ce8101 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.MSIL.dll differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.MSIL.pdb b/base/Applications/Benchmarks/BartokH/msil/Bartok.MSIL.pdb new file mode 100644 index 0000000..727f8a4 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.MSIL.pdb differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Mangle.dll b/base/Applications/Benchmarks/BartokH/msil/Bartok.Mangle.dll new file mode 100644 index 0000000..0df01c5 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Mangle.dll differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Mangle.pdb b/base/Applications/Benchmarks/BartokH/msil/Bartok.Mangle.pdb new file mode 100644 index 0000000..55c9193 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Mangle.pdb differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Marshal.dll b/base/Applications/Benchmarks/BartokH/msil/Bartok.Marshal.dll new file mode 100644 index 0000000..94ca79c Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Marshal.dll differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Marshal.pdb b/base/Applications/Benchmarks/BartokH/msil/Bartok.Marshal.pdb new file mode 100644 index 0000000..412b8ea Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Marshal.pdb differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Opt.dll b/base/Applications/Benchmarks/BartokH/msil/Bartok.Opt.dll new file mode 100644 index 0000000..90158a6 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Opt.dll differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Opt.pdb b/base/Applications/Benchmarks/BartokH/msil/Bartok.Opt.pdb new file mode 100644 index 0000000..578ae1f Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Opt.pdb differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Profile.dll b/base/Applications/Benchmarks/BartokH/msil/Bartok.Profile.dll new file mode 100644 index 0000000..3cdc7a3 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Profile.dll differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Profile.pdb b/base/Applications/Benchmarks/BartokH/msil/Bartok.Profile.pdb new file mode 100644 index 0000000..07f6d0b Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Profile.pdb differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Proxy.pdb b/base/Applications/Benchmarks/BartokH/msil/Bartok.Proxy.pdb new file mode 100644 index 0000000..21432fc Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Proxy.pdb differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Regalloc.dll b/base/Applications/Benchmarks/BartokH/msil/Bartok.Regalloc.dll new file mode 100644 index 0000000..a81ee5b Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Regalloc.dll differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Regalloc.pdb b/base/Applications/Benchmarks/BartokH/msil/Bartok.Regalloc.pdb new file mode 100644 index 0000000..4c6a2d3 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Regalloc.pdb differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Regreal.dll b/base/Applications/Benchmarks/BartokH/msil/Bartok.Regreal.dll new file mode 100644 index 0000000..64f9591 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Regreal.dll differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Regreal.pdb b/base/Applications/Benchmarks/BartokH/msil/Bartok.Regreal.pdb new file mode 100644 index 0000000..b56f699 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Regreal.pdb differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Regstub.dll b/base/Applications/Benchmarks/BartokH/msil/Bartok.Regstub.dll new file mode 100644 index 0000000..56e87e5 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Regstub.dll differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Regstub.pdb b/base/Applications/Benchmarks/BartokH/msil/Bartok.Regstub.pdb new file mode 100644 index 0000000..12cd1eb Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Regstub.pdb differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Tables.dll b/base/Applications/Benchmarks/BartokH/msil/Bartok.Tables.dll new file mode 100644 index 0000000..2b6df5f Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Tables.dll differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Tables.pdb b/base/Applications/Benchmarks/BartokH/msil/Bartok.Tables.pdb new file mode 100644 index 0000000..64589d1 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Tables.pdb differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Utility.dll b/base/Applications/Benchmarks/BartokH/msil/Bartok.Utility.dll new file mode 100644 index 0000000..68a9dba Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Utility.dll differ diff --git a/base/Applications/Benchmarks/BartokH/msil/Bartok.Utility.pdb b/base/Applications/Benchmarks/BartokH/msil/Bartok.Utility.pdb new file mode 100644 index 0000000..6a4dfa6 Binary files /dev/null and b/base/Applications/Benchmarks/BartokH/msil/Bartok.Utility.pdb differ diff --git a/base/Applications/Benchmarks/Benchmarks.proj b/base/Applications/Benchmarks/Benchmarks.proj new file mode 100644 index 0000000..d3e437e --- /dev/null +++ b/base/Applications/Benchmarks/Benchmarks.proj @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/base/Applications/Benchmarks/CreateProcess/CreateProcess.cs b/base/Applications/Benchmarks/CreateProcess/CreateProcess.cs new file mode 100644 index 0000000..545647c --- /dev/null +++ b/base/Applications/Benchmarks/CreateProcess/CreateProcess.cs @@ -0,0 +1,431 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: CreateProcess.cs +// +// Note: Singularity micro-benchmark program. +// +using Microsoft.Singularity; +using Microsoft.Singularity.V1.Services; +using Microsoft.Singularity.V1.Threads; +using System; +using System.Runtime.CompilerServices; +using System.Diagnostics; +using System.Threading; + +using Microsoft.Singularity.Channels; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications +{ + [ConsoleCategory(HelpMessage="CreateProcess benchmark test", DefaultAction=true)] + internal class Parameters + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [BoolParameter( "q", Default=false, HelpMessage="Quiet Mode.")] + internal bool quietMode; + + [LongParameter( "r", Default=1, HelpMessage="Repetition count.")] + internal long repetitions; + + reflective internal Parameters(); + + internal int AppMain() { + return CreateProcessTest.AppMain(this); + } + } + + // + // The goal of this test is to time how long it takes to + // create a process. + // + public class CreateProcessTest + { + private static bool AtRing3; + +#if x64_PERF + [CLSCompliant(false)] + public struct PerfEvtSel + { + // Bits and Flags + public const uint CNT_MASK = 0xff000000; + public const uint INV = 0x00800000; + public const uint EN = 0x00400000; + public const uint INT = 0x00100000; + public const uint PC = 0x00080000; + public const uint E = 0x00040000; + public const uint OS = 0x00020000; + public const uint USR = 0x00010000; + public const uint UNIT_MASK = 0x0000ff00; + public const uint SELECTOR = 0x000000ff; + + // Common setting: Count all, but don't interrupt, + public const uint COUNT = (EN | PC | OS | USR); + + // Selector values. + public const uint DtlbL1MissL2Hit = 0x45; // Speculative + public const uint DtlbL1MissL2Miss = 0x46; // Speculative + public const uint CyclesNotHalted = 0x76; + public const uint RequestsToL2Cache = 0x7d; + public const uint ItlbL1MissL2Hit = 0x84; + public const uint ItlbL1MissL2Miss = 0x85; + public const uint RetiredInstructions = 0xc0; + public const uint RetiredBranchInstructions = 0xc2; + public const uint RetiredBranchesMispredicted = 0xc3; + public const uint RetiredBranchesTaken = 0xc4; + public const uint CyclesInterruptsMasked = 0xcd; + public const uint CyclesInterruptsBlocked = 0xce; + } + + public static void Reset(uint pmc, ulong value) + { + // Clear the event selector. + Processor.WriteMsr(0xc0010000 + pmc, 0); + // Clear the performance counter. + Processor.WriteMsr(0xc0010004 + pmc, 0); + // Enable the event selector. + Processor.WriteMsr(0xc0010000 + pmc, value); + } + + public static string EvtSelToString(ulong value) + { + switch (value & 0xff) { + case PerfEvtSel.DtlbL1MissL2Hit: return "DTLB_L2_Hit"; + case PerfEvtSel.DtlbL1MissL2Miss: return "DTBL_L2_Miss"; + case PerfEvtSel.CyclesNotHalted: return "CyclesNotHalted"; + case PerfEvtSel.RequestsToL2Cache: return "TLB_L2_Requests"; + case PerfEvtSel.ItlbL1MissL2Hit: return "ITLB_L2_Hit"; + case PerfEvtSel.ItlbL1MissL2Miss: return "ITLB_L2_Miss"; + case PerfEvtSel.RetiredInstructions: return "Retired_Inst."; + case PerfEvtSel.RetiredBranchInstructions: return "Branches"; + case PerfEvtSel.RetiredBranchesMispredicted:return "Br_Mispredicted"; + case PerfEvtSel.RetiredBranchesTaken: return "Br_Taken"; + case PerfEvtSel.CyclesInterruptsMasked: return "Ints_Masked (cyc)"; + case PerfEvtSel.CyclesInterruptsBlocked: return "Ints_Blocked (cyc)"; + default: + return String.Format("{0:x16}", value); + } + } + + private static ulong x64_i0, x64_p0; + private static ulong x64_i1, x64_p1; + private static ulong x64_i2, x64_p2; + private static ulong x64_i3, x64_p3; +#endif + + private static void DualWriteLine(string message) + { + Console.WriteLine(message); + DebugStub.WriteLine(message); + } + + public struct PerfSnap + { + private bool disabled; + private long begCycleCount; + private long endCycleCount; + private long begSwitchCount; + private long endSwitchCount; + private long begInterruptCount; + private long endInterruptCount; + private long begKernelGcCount; + private long endKernelGcCount; + private long begProcessGcCount; + private long endProcessGcCount; + private long iterations; + private ulong begAllocatedCount; + private ulong begAllocatedBytes; + private ulong begFreedCount; + private ulong begFreedBytes; + private ulong endAllocatedCount; + private ulong endAllocatedBytes; + private ulong endFreedCount; + private ulong endFreedBytes; + private ulong begStackGets; + private ulong begStackRets; + private ulong endStackGets; + private ulong endStackRets; + + + public long Cycles { get { return endCycleCount - begCycleCount; } } + public long Interrupts { get { return endInterruptCount - begInterruptCount; } } + public long Switches { get { return endSwitchCount - begSwitchCount; } } + public long KernelGCs { get { return endKernelGcCount - begKernelGcCount; } } + public long ProcessGCs { get { return endProcessGcCount - begProcessGcCount; } } + public ulong AllocatedCount { get { return endAllocatedCount-begAllocatedCount; } } + public ulong AllocatedBytes { get { return endAllocatedBytes-begAllocatedBytes; } } + public ulong FreedCount { get { return endFreedCount - begFreedCount; } } + public ulong FreedBytes { get { return endFreedBytes - begFreedBytes; } } + public ulong StackGets { get { return endStackGets - begStackGets; } } + public ulong StackRets { get { return endStackRets - begStackRets; } } + + public void Start() + { + if (!AtRing3) { + disabled = Processor.DisableInterrupts(); + } + + int collectorCount; + long collectorMillis; + long collectorBytes; + GC.PerformanceCounters(out collectorCount, + out collectorMillis, + out collectorBytes); + + ulong stackGets; + ulong stackRets; + StackService.GetUsageStatistics(out stackGets, + out stackRets); + begStackGets = stackGets; + begStackRets = stackRets; + + ulong allocatedCount; + ulong allocatedBytes; + ulong freedCount; + ulong freedBytes; + PageTableService.GetUsageStatistics(out allocatedCount, + out allocatedBytes, + out freedCount, + out freedBytes); + begAllocatedCount = allocatedCount; + begAllocatedBytes = allocatedBytes; + begFreedCount = freedCount; + begFreedBytes = freedBytes; + + begInterruptCount = ProcessService.GetKernelInterruptCount(); + begSwitchCount = ProcessService.GetContextSwitchCount(); + begKernelGcCount = ProcessService.GetKernelGcCount(); + begProcessGcCount = collectorCount; + +#if x64_PERF + // Set up for perf counting + if (!AtRing3) { + // Reset the performance counters to what we're interested in. + Reset(0, PerfEvtSel.COUNT | PerfEvtSel.CyclesNotHalted); + Reset(1, PerfEvtSel.COUNT | PerfEvtSel.RetiredInstructions); + Reset(2, PerfEvtSel.COUNT | PerfEvtSel.RetiredBranchInstructions); + Reset(3, PerfEvtSel.COUNT | PerfEvtSel.RequestsToL2Cache | 0x400); + } else { + // We're not allowed to reset the perf counters, so take note + // of their current values; we will subtract from this later. + x64_i0 = Processor.ReadPmc(0); + x64_i1 = Processor.ReadPmc(1); + x64_i2 = Processor.ReadPmc(2); + x64_i3 = Processor.ReadPmc(3); + } +#endif + + begCycleCount = unchecked((long)Processor.CycleCount); + } + + public void Finish(long iterations) + { + endCycleCount = unchecked((long)Processor.CycleCount); + +#if X64_PERF + x64_p0 = Processor.ReadPmc(0); + x64_p1 = Processor.ReadPmc(1); + x64_p2 = Processor.ReadPmc(2); + x64_p3 = Processor.ReadPmc(3); +#endif + + endInterruptCount = ProcessService.GetKernelInterruptCount(); + endSwitchCount = ProcessService.GetContextSwitchCount(); + endKernelGcCount = ProcessService.GetKernelGcCount(); + + int collectorCount; + long collectorMillis; + long collectorBytes; + GC.PerformanceCounters(out collectorCount, + out collectorMillis, + out collectorBytes); + endProcessGcCount = collectorCount; + + ulong allocatedCount; + ulong allocatedBytes; + ulong freedCount; + ulong freedBytes; + PageTableService.GetUsageStatistics(out allocatedCount, + out allocatedBytes, + out freedCount, + out freedBytes); + endAllocatedCount = allocatedCount; + endAllocatedBytes = allocatedBytes; + endFreedCount = freedCount; + endFreedBytes = freedBytes; + + ulong stackGets; + ulong stackRets; + StackService.GetUsageStatistics(out stackGets, + out stackRets); + endStackGets = stackGets; + endStackRets = stackRets; + + if (!AtRing3) { + Processor.RestoreInterrupts(disabled); + } + + this.iterations = iterations; + } + + public void Display(string name) + { + DualWriteLine( + String.Format("{0,-16} {1,6:d} x{2,8:d} ={3,12:d} " + + "[swi={4,6:d} int={5,3:d} gc={6:d}/{7:d}]", + name, + iterations, + Cycles / iterations, + Cycles, + Switches, + Interrupts, + KernelGCs, + ProcessGCs) + ); + + + if (AllocatedCount != 0 || FreedCount != 0 || StackGets != 0) { + DualWriteLine( + string.Format( + " " + + "[alloc={0,4:d}/{1,8:x} free={2,4:d}/{3,8:x} " + + "stack={4,4:d}/{5,4:d}]", + AllocatedCount, + AllocatedBytes, + FreedCount, + FreedBytes, + StackGets, + StackRets) + ); + } + +#if x64_PERF + if (!AtRing3) { + // Read off the current MSR values and turn them + // into nice labels + ulong e0 = Processor.ReadMsr(0xc0010000); + ulong e1 = Processor.ReadMsr(0xc0010001); + ulong e2 = Processor.ReadMsr(0xc0010002); + ulong e3 = Processor.ReadMsr(0xc0010003); + + DualWriteLine( + String.Format("evt: {0,16} {1,16} {2,16} {3,16}", + EvtSelToString(e0), + EvtSelToString(e1), + EvtSelToString(e2), + EvtSelToString(e3))); + } else { + // Subtract from the initial perf-counter values to + // get the delta we want + x64_p0 -= x64_i0; + x64_p1 -= x64_i1; + x64_p2 -= x64_i2; + x64_p3 -= x64_i3; + } + + DualWriteLine( + String.Format("pmc: {0:d16} {1:d16} {2:d16} {3:d16} {4:d16}\n\n", + Cycles, x64_p0, x64_p1, x64_p2, x64_p3)); +#endif + } + } + + + internal static int AppMain(Parameters! config) + { + bool runQuiet = config.quietMode; + long repetitions = config.repetitions; + + Console.Write("\nProcess creation test\n\n"); + string [] arguments; + for (long i = 0; i < repetitions; i++) { + arguments = new string[2]; + arguments[0] = "testpe.x86"; + arguments[1] = "!"; // Special flag to not notify debugger. + TimeProcess(arguments, runQuiet); + } + return 0; + } + + public static void TimeProcess(String[]! args, bool runQuiet) + { + ulong baseline; + ulong created; + ulong started; + ulong exited; + Process process = null; + + PerfSnap snap = new PerfSnap(); + + snap.Start(); + try { + ProcessService.Waypoint0(); + baseline = Processor.CycleCount; + + // + // Time process creation. + // + ProcessService.Waypoint(1500); + process = new Process(args); + created = Processor.CycleCount; + + // + // Time process start. + // + ProcessService.Waypoint(1501); + + process.Start(); + started = Processor.CycleCount; + + ProcessService.Waypoint(1502); + // + // Time process execution. + // + process.Join(); + ProcessService.Waypoint(1503); + exited = Processor.CycleCount; + } + finally { + snap.Finish(1); + } + + snap.Display("CreateProc"); + + ProcessService.Waypoint(1504); + process.Dispose(true); + ProcessService.Waypoint(1505); + ProcessService.WaypointDump(); + + + if (runQuiet) { + return; + } + + // + // Tell the world. + // + Console.WriteLine(); + Console.WriteLine("Tested process: {0}", args[0]); + Console.WriteLine("Create process: {0,15:d} cycles", created - baseline); + Console.WriteLine("Start process: {0,15:d} cycles", started - created); + Console.WriteLine("Run process: {0,15:d} cycles", exited - started); + Console.WriteLine("Total: {0,15:d} cycles", exited - baseline); + Console.WriteLine("Process.Create: {0,15:d} cycles", started - baseline); + Console.WriteLine(); + Console.WriteLine(); + } + } +} diff --git a/base/Applications/Benchmarks/CreateProcess/CreateProcess.csproj b/base/Applications/Benchmarks/CreateProcess/CreateProcess.csproj new file mode 100644 index 0000000..d1d0b64 --- /dev/null +++ b/base/Applications/Benchmarks/CreateProcess/CreateProcess.csproj @@ -0,0 +1,25 @@ + + + + + + + Exe + CreateProcess + + + + + + + + + diff --git a/base/Applications/Benchmarks/SharedHeap/SharedHeapBench.cs b/base/Applications/Benchmarks/SharedHeap/SharedHeapBench.cs new file mode 100644 index 0000000..d0f9695 --- /dev/null +++ b/base/Applications/Benchmarks/SharedHeap/SharedHeapBench.cs @@ -0,0 +1,107 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: SharedHeapBench.cs +// +// Note: Singularity micro-benchmark program. +// +using Microsoft.Singularity; +using Microsoft.Singularity.V1.Services; +using Microsoft.Singularity.V1.Threads; +using System; +using System.Runtime.CompilerServices; +using System.Diagnostics; +using System.Threading; + +using Microsoft.Singularity.Channels; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications { + [ConsoleCategory(HelpMessage="Show attributes associated with a file", DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [BoolParameter( "q", Default=false, HelpMessage="Quiet Mode.")] + internal bool quietMode; + + [LongParameter( "r", Default=1, HelpMessage="Repetition count.")] + internal long repetitions; + + reflective internal Parameters(); + + internal int AppMain() { + return SharedHeapBench.AppMain(this); + } + } + // + // The goal of this test is to time how long it takes to + // create a process. + // + public class SharedHeapBench + { + internal static int AppMain(Parameters! config) + { + int iterations = 10000; + + Console.Write("\nTime alloc/free ops in the shared heap\n\n"); + + TimeCycle(10, iterations); + + Thread.Sleep(1000); + + TimeCycle(100, iterations); + + Thread.Sleep(1000); + + TimeCycle(1000, iterations); + + Thread.Sleep(1000); + + TimeCycle(10000, iterations); + + return 0; + } + + // + // The goal of this routine is to focus on the shared heap operations + // themselves. So we allocate and then free the same amount of memory + // repeatedly, which (for small region allocations) won't cause us to + // go to the Page manager in steady state. + // + public static void TimeCycle(int bytes, int iterations) + { + + ulong before = Processor.CycleCount; + + for (int loop = 0; loop < iterations; loop++) { + SharedHeapService.Allocation *mem; + + mem = (SharedHeapService.Allocation *) + SharedHeapService.Allocate((UIntPtr)bytes, typeof(byte).GetSystemType(), 0); + SharedHeapService.Free(mem); + } + + ulong after = Processor.CycleCount; + + // + // Tell the world. + // + Console.Write("\nTested {0} alloc/free iterations of {1} bytes\n", + iterations, bytes); + Console.Write("Total cycles: {0}\n", after - before); + Console.Write("\n\n"); + } + } +} diff --git a/base/Applications/Benchmarks/SharedHeap/SharedHeapBench.csproj b/base/Applications/Benchmarks/SharedHeap/SharedHeapBench.csproj new file mode 100644 index 0000000..488507b --- /dev/null +++ b/base/Applications/Benchmarks/SharedHeap/SharedHeapBench.csproj @@ -0,0 +1,25 @@ + + + + + + + Exe + SharedHeapBench + + + + + + + + + diff --git a/base/Applications/Benchmarks/SingBench/BenchChild/BenchChild.sg b/base/Applications/Benchmarks/SingBench/BenchChild/BenchChild.sg new file mode 100644 index 0000000..e80ec6c --- /dev/null +++ b/base/Applications/Benchmarks/SingBench/BenchChild/BenchChild.sg @@ -0,0 +1,118 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: BenchChild.sg +// +// Note: Simple ping-pong second child process +// + +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Diagnostics.Contracts; +using Microsoft.Singularity.Endpoint; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.V1.Services; + +using System; +using System.Runtime.CompilerServices; +using System.Threading; + +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Extending; +using Microsoft.Singularity.Configuration; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +[assembly: Transform(typeof(WebAppResourceTransform))] + + +namespace Microsoft.Singularity.Applications.Singbench +{ + [Category("WebApp")] + internal class Parameters + { + [Endpoint] + public readonly TRef sendRef; + + [BoolParameter("where", Default=false, HelpMessage="Show what space we are running in")] + internal bool doWhere; + + reflective private Parameters(); + + internal int AppMain() { + return BenchChild.AppMain(this); + } + } + + public class BenchChild + { + internal static int AppMain(Parameters! config) + { + if (config.doWhere) { + if (Processor.AtKernelPrivilege()) { + DualWriteLine("Benchchild running at KERNEL privilege"); + } else { + DualWriteLine("Benchchild running at USER privilege"); + } + } + + ExtensionContract.Exp ep = (config.sendRef).Acquire(); + + + SendTestContract.Exp simpleConn = ep as SendTestContract.Exp; + + if (simpleConn != null) { + DoSimpleTest(simpleConn); + } + + BufferTestContract.Exp bufferConn = ep as BufferTestContract.Exp; + + if (bufferConn != null) { + DoBufferTest(bufferConn); + } + + // Wrong contract type! + delete ep; + return 0; + } + + private static void DoSimpleTest(SendTestContract.Exp! conn) + { + conn.SendTestReady(); + int arg; + + while(true) { + conn.RecvReq(out arg); + + if (arg == -1) { + return; + } + + conn.SendResp(arg); + } + } + + private static void DoBufferTest(BufferTestContract.Exp! conn) + { + int arg; + byte[]! in ExHeap buffer; + + conn.SendBufferReady(); + + while (true) { + conn.RecvReq(out arg, out buffer); + conn.SendResp(buffer); + if (arg == 0) { + return; + } + } + } + + private static void DualWriteLine(string message) + { + Console.WriteLine(message); + DebugStub.WriteLine(message); + } + } +} diff --git a/base/Applications/Benchmarks/SingBench/BenchChild/SingBenchChild.csproj b/base/Applications/Benchmarks/SingBench/BenchChild/SingBenchChild.csproj new file mode 100644 index 0000000..7a6e884 --- /dev/null +++ b/base/Applications/Benchmarks/SingBench/BenchChild/SingBenchChild.csproj @@ -0,0 +1,30 @@ + + + + + + + Exe + benchchild + true + + + + + + + + + + + + + diff --git a/base/Applications/Benchmarks/SingBench/Contracts/ChannelTestContract.sg b/base/Applications/Benchmarks/SingBench/Contracts/ChannelTestContract.sg new file mode 100644 index 0000000..4f9447a --- /dev/null +++ b/base/Applications/Benchmarks/SingBench/Contracts/ChannelTestContract.sg @@ -0,0 +1,44 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: MemoryContract.sg +// Note: Contract definition for the memory diagnostic module +// + +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Endpoint; +using Microsoft.Singularity.V1.Services; + +using System; +using System.Runtime.CompilerServices; +using System.Threading; + +using Microsoft.Singularity.Extending; + +namespace Microsoft.Singularity.Applications.Singbench +{ + public contract SendTestContract : ExtensionContract + { + in message Req(int x); + out message Resp(int x); + + out message TestReady(); + + override state Start : TestReady! -> ReadyState; + state ReadyState : Req? -> Resp! -> ReadyState; + } + + public contract BufferTestContract : ExtensionContract + { + in message Req(int remain, byte[]! in ExHeap buffer); + out message Resp(byte[]! in ExHeap buffer); + + out message BufferReady(); + + override state Start : BufferReady! -> ReadyState; + state ReadyState : Req? -> Resp! -> ReadyState; + } +} diff --git a/base/Applications/Benchmarks/SingBench/Contracts/SingBench.Contracts.csproj b/base/Applications/Benchmarks/SingBench/Contracts/SingBench.Contracts.csproj new file mode 100644 index 0000000..f20c244 --- /dev/null +++ b/base/Applications/Benchmarks/SingBench/Contracts/SingBench.Contracts.csproj @@ -0,0 +1,29 @@ + + + + + + + Library + SingBench.Contracts + + + + + + + + + + + + + diff --git a/base/Applications/Benchmarks/SingBench/SingBench.proj b/base/Applications/Benchmarks/SingBench/SingBench.proj new file mode 100644 index 0000000..e267a9d --- /dev/null +++ b/base/Applications/Benchmarks/SingBench/SingBench.proj @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/base/Applications/Benchmarks/SingBench/SingBench/PerfSnap.sg b/base/Applications/Benchmarks/SingBench/SingBench/PerfSnap.sg new file mode 100644 index 0000000..11eb7ab --- /dev/null +++ b/base/Applications/Benchmarks/SingBench/SingBench/PerfSnap.sg @@ -0,0 +1,293 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: PerfSnap.sg +// +// Note: Performance measurer for Singularity Benchmark +// + +using System; +using System.Threading; +using Microsoft.Singularity.V1.Services; + +namespace Microsoft.Singularity.Applications.Singbench +{ + public struct PerfSnap + { + // Global options for all instances + static bool xmlOutput = false; + static bool atRing3 = false; + + private bool disabled; + private long begCycleCount; + private long endCycleCount; + private long begSwitchCount; + private long endSwitchCount; + private long begInterruptCount; + private long endInterruptCount; + private long begKernelGcCount; + private long endKernelGcCount; + private long begProcessGcCount; + private long endProcessGcCount; + private long iterations; + private ulong begAllocatedCount; + private ulong begAllocatedBytes; + private ulong begFreedCount; + private ulong begFreedBytes; + private ulong endAllocatedCount; + private ulong endAllocatedBytes; + private ulong endFreedCount; + private ulong endFreedBytes; + private ulong begStackGets; + private ulong begStackRets; + private ulong endStackGets; + private ulong endStackRets; + + + public long Cycles { get { return endCycleCount - begCycleCount; } } + public long Interrupts { get { return endInterruptCount - begInterruptCount; } } + public long Switches { get { return endSwitchCount - begSwitchCount; } } + public long KernelGCs { get { return endKernelGcCount - begKernelGcCount; } } + public long ProcessGCs { get { return endProcessGcCount - begProcessGcCount; } } + public ulong AllocatedCount { get { return endAllocatedCount-begAllocatedCount; } } + public ulong AllocatedBytes { get { return endAllocatedBytes-begAllocatedBytes; } } + public ulong FreedCount { get { return endFreedCount - begFreedCount; } } + public ulong FreedBytes { get { return endFreedBytes - begFreedBytes; } } + public ulong StackGets { get { return endStackGets - begStackGets; } } + public ulong StackRets { get { return endStackRets - begStackRets; } } + + public void Start() + { + if (!atRing3) { + disabled = Processor.DisableInterrupts(); + // flush out pending IO interrupts + Thread.Yield(); + Thread.Yield(); + Thread.Yield(); + Thread.Yield(); + Thread.Yield(); + } + + int collectorCount; + long collectorMillis; + long collectorBytes; + GC.PerformanceCounters(out collectorCount, + out collectorMillis, + out collectorBytes); + + ulong stackGets; + ulong stackRets; + StackService.GetUsageStatistics(out stackGets, + out stackRets); + begStackGets = stackGets; + begStackRets = stackRets; + + ulong allocatedCount; + ulong allocatedBytes; + ulong freedCount; + ulong freedBytes; + PageTableService.GetUsageStatistics(out allocatedCount, + out allocatedBytes, + out freedCount, + out freedBytes); + begAllocatedCount = allocatedCount; + begAllocatedBytes = allocatedBytes; + begFreedCount = freedCount; + begFreedBytes = freedBytes; + + begInterruptCount = ProcessService.GetKernelInterruptCount(); + begSwitchCount = ProcessService.GetContextSwitchCount(); + begKernelGcCount = ProcessService.GetKernelGcCount(); + begProcessGcCount = collectorCount; + +#if x64_PERF + // Set up for perf counting + if (!atRing3) { + // Reset the performance counters to what we're interested in. + Reset(0, PerfEvtSel.COUNT | PerfEvtSel.CyclesNotHalted); + Reset(1, PerfEvtSel.COUNT | PerfEvtSel.RetiredInstructions); + Reset(2, PerfEvtSel.COUNT | PerfEvtSel.RetiredBranchInstructions); + Reset(3, PerfEvtSel.COUNT | PerfEvtSel.RequestsToL2Cache | 0x400); + } else { + // We're not allowed to reset the perf counters, so take note + // of their current values; we will subtract from this later. + x64_i0 = Processor.ReadPmc(0); + x64_i1 = Processor.ReadPmc(1); + x64_i2 = Processor.ReadPmc(2); + x64_i3 = Processor.ReadPmc(3); + } +#endif + + begCycleCount = unchecked((long)Processor.CycleCount); + } + + public void Finish(long iterations) + { + endCycleCount = unchecked((long)Processor.CycleCount); + +#if X64_PERF + x64_p0 = Processor.ReadPmc(0); + x64_p1 = Processor.ReadPmc(1); + x64_p2 = Processor.ReadPmc(2); + x64_p3 = Processor.ReadPmc(3); +#endif + + endInterruptCount = ProcessService.GetKernelInterruptCount(); + endSwitchCount = ProcessService.GetContextSwitchCount(); + endKernelGcCount = ProcessService.GetKernelGcCount(); + + int collectorCount; + long collectorMillis; + long collectorBytes; + GC.PerformanceCounters(out collectorCount, + out collectorMillis, + out collectorBytes); + endProcessGcCount = collectorCount; + + ulong allocatedCount; + ulong allocatedBytes; + ulong freedCount; + ulong freedBytes; + PageTableService.GetUsageStatistics(out allocatedCount, + out allocatedBytes, + out freedCount, + out freedBytes); + endAllocatedCount = allocatedCount; + endAllocatedBytes = allocatedBytes; + endFreedCount = freedCount; + endFreedBytes = freedBytes; + + ulong stackGets; + ulong stackRets; + StackService.GetUsageStatistics(out stackGets, + out stackRets); + endStackGets = stackGets; + endStackRets = stackRets; + + if (!atRing3) { + Processor.RestoreInterrupts(disabled); + } + + this.iterations = iterations; + } + + public void Display(string name) + { + if (xmlOutput) { + DisplayXml(name); + } else { + DisplayText(name); + } + } + + private static void WriteXmlValue(string name, long value) + { + DualWriteLine( + String.Format(" {0} {1:d} ", name, value) + ); + } + + private static void WriteXmlValue(string name, ulong value) + { + DualWriteLine( + String.Format(" {0} {1:d} ", name, value) + ); + } + + private void DisplayXml(string name) + { + DualWriteLine( + String.Format("", name) + ); + WriteXmlValue("CyclesPerIteration", Cycles / iterations); + WriteXmlValue("Cycles", Cycles); + WriteXmlValue("Iterations", iterations); + WriteXmlValue("Switches", Switches); + WriteXmlValue("Interrupts", Interrupts); + WriteXmlValue("KernelGCs", KernelGCs); + WriteXmlValue("ProcessGCs", ProcessGCs); + WriteXmlValue("AllocationCount", AllocatedCount); + WriteXmlValue("AllocationBytes", AllocatedBytes); + WriteXmlValue("FreedCount", FreedCount); + WriteXmlValue("FreedBytes", FreedBytes); + WriteXmlValue("StackGetCount", StackGets); + WriteXmlValue("StackReturnCount", StackRets); + DualWriteLine(""); + } + + private void DisplayText(string name) + { + DualWriteLine( + String.Format("{0,-16} {1,6:d} x{2,8:d} ={3,12:d} " + + "[swi={4,6:d} int={5,3:d} gc={6:d}/{7:d}]", + name, + iterations, + Cycles / iterations, + Cycles, + Switches, + Interrupts, + KernelGCs, + ProcessGCs) + ); + + if (AllocatedCount > 1 || FreedCount > 1 || StackGets > 1) { + DualWriteLine( + string.Format( + " " + + "[alloc={0,4:d}/{1,8:x} free={2,4:d}/{3,8:x} " + + "stack={4,4:d}/{5,4:d}]", + AllocatedCount, + AllocatedBytes, + FreedCount, + FreedBytes, + StackGets, + StackRets) + ); + } + +#if x64_PERF + if (!atRing3) { + // Read off the current MSR values and turn them + // into nice labels + ulong e0 = Processor.ReadMsr(0xc0010000); + ulong e1 = Processor.ReadMsr(0xc0010001); + ulong e2 = Processor.ReadMsr(0xc0010002); + ulong e3 = Processor.ReadMsr(0xc0010003); + + DualWriteLine( + String.Format("evt: {0,16} {1,16} {2,16} {3,16}", + EvtSelToString(e0), + EvtSelToString(e1), + EvtSelToString(e2), + EvtSelToString(e3))); + } else { + // Subtract from the initial perf-counter values to + // get the delta we want + x64_p0 -= x64_i0; + x64_p1 -= x64_i1; + x64_p2 -= x64_i2; + x64_p3 -= x64_i3; + } + + DualWriteLine( + String.Format("pmc: {0:d16} {1:d16} {2:d16} {3:d16} {4:d16}\n\n", + Cycles, x64_p0, x64_p1, x64_p2, x64_p3)); +#endif + } + + private static void DualWriteLine(string message) + { + Console.WriteLine(message); + DebugStub.WriteLine(message); + } + + public static void SetOptions(bool ring3, bool doXmlOutput) + { + PerfSnap.atRing3 = ring3; + PerfSnap.xmlOutput = doXmlOutput; + } + } +} diff --git a/base/Applications/Benchmarks/SingBench/SingBench/SingBench.sg b/base/Applications/Benchmarks/SingBench/SingBench/SingBench.sg new file mode 100644 index 0000000..899b93c --- /dev/null +++ b/base/Applications/Benchmarks/SingBench/SingBench/SingBench.sg @@ -0,0 +1,1434 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: SingBench.sg +// +// Note: Benchmark suite for Singularity primitives +// +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Diagnostics.Contracts; +using Microsoft.Singularity.Endpoint; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.V1.Services; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; + +using System; +using System.Runtime.CompilerServices; +using System.Threading; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications.Singbench +{ + [ConsoleCategory(HelpMessage="Singularity Benchmark Application", DefaultAction=true)] + internal sealed class Parameters + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef memoryRef; + + [BoolParameter( "b", Default=false , HelpMessage="Break at start of tests.")] + internal bool breakIn; + + [BoolParameter( "n", Default=true , HelpMessage="No GC between tests.")] + internal bool allowGC; + + [BoolParameter( "w", Default=false , HelpMessage="Wait for key press between tests.")] + internal bool pauseForKeys; + + [BoolParameter( "x", Default=false , HelpMessage="XML output.")] + internal bool xmlOutput; + + [LongParameter( "i", Default=10000 , HelpMessage="Iterate tests times.")] + internal long iterations; + + reflective internal Parameters(); + + internal int AppMain() { + return SingBench.AppMain(this); + } + } + + public class SingBench + { + private static bool atRing3; + +#if x64_PERF + [CLSCompliant(false)] + public struct PerfEvtSel + { + // Bits and Flags + public const uint CNT_MASK = 0xff000000; + public const uint INV = 0x00800000; + public const uint EN = 0x00400000; + public const uint INT = 0x00100000; + public const uint PC = 0x00080000; + public const uint E = 0x00040000; + public const uint OS = 0x00020000; + public const uint USR = 0x00010000; + public const uint UNIT_MASK = 0x0000ff00; + public const uint SELECTOR = 0x000000ff; + + // Common setting: Count all, but don't interrupt, + public const uint COUNT = (EN | PC | OS | USR); + + // Selector values. + public const uint DtlbL1MissL2Hit = 0x45; // Speculative + public const uint DtlbL1MissL2Miss = 0x46; // Speculative + public const uint CyclesNotHalted = 0x76; + public const uint RequestsToL2Cache = 0x7d; + public const uint ItlbL1MissL2Hit = 0x84; + public const uint ItlbL1MissL2Miss = 0x85; + public const uint RetiredInstructions = 0xc0; + public const uint RetiredBranchInstructions = 0xc2; + public const uint RetiredBranchesMispredicted = 0xc3; + public const uint RetiredBranchesTaken = 0xc4; + public const uint CyclesInterruptsMasked = 0xcd; + public const uint CyclesInterruptsBlocked = 0xce; + } + + public static void Reset(uint pmc, ulong value) + { + // Clear the event selector. + Processor.WriteMsr(0xc0010000 + pmc, 0); + // Clear the performance counter. + Processor.WriteMsr(0xc0010004 + pmc, 0); + // Enable the event selector. + Processor.WriteMsr(0xc0010000 + pmc, value); + } + + public static string EvtSelToString(ulong value) + { + switch (value & 0xff) { + case PerfEvtSel.DtlbL1MissL2Hit: return "DTLB_L2_Hit"; + case PerfEvtSel.DtlbL1MissL2Miss: return "DTBL_L2_Miss"; + case PerfEvtSel.CyclesNotHalted: return "CyclesNotHalted"; + case PerfEvtSel.RequestsToL2Cache: return "TLB_L2_Requests"; + case PerfEvtSel.ItlbL1MissL2Hit: return "ITLB_L2_Hit"; + case PerfEvtSel.ItlbL1MissL2Miss: return "ITLB_L2_Miss"; + case PerfEvtSel.RetiredInstructions: return "Retired_Inst."; + case PerfEvtSel.RetiredBranchInstructions: return "Branches"; + case PerfEvtSel.RetiredBranchesMispredicted:return "Br_Mispredicted"; + case PerfEvtSel.RetiredBranchesTaken: return "Br_Taken"; + case PerfEvtSel.CyclesInterruptsMasked: return "Ints_Masked (cyc)"; + case PerfEvtSel.CyclesInterruptsBlocked: return "Ints_Blocked (cyc)"; + default: + return String.Format("{0:x16}", value); + } + } + + private static ulong x64_i0, x64_p0; + private static ulong x64_i1, x64_p1; + private static ulong x64_i2, x64_p2; + private static ulong x64_i3, x64_p3; +#endif + + private static void DualWriteLine(string message) + { + Console.WriteLine(message); + DebugStub.WriteLine(message); + } + + private static int peerIterations; + private static AutoResetEvent peerReady; + private static AutoResetEvent peerBegin; + private static AutoResetEvent peerFinish; + + private static AutoResetEvent waitPerfEvent1; + private static AutoResetEvent waitPerfEvent2; + + private static long startWaitPerfClock; + private static ulong startCount; + private static ulong endCount; + + private static bool allowGC = false; + private static bool pauseForKeys = false; + private static bool breakIn = false; + + + //////////////////////////////////////////////// CycleCount Read Test. + // + public static void DoGetCycleCountPerf(int iterations) + { + PerfSnap snap = new PerfSnap(); + + snap.Start(); + try { + for (int i = 0; i < iterations; i++) { + Processor.GetCycleCount(); + } + } + finally { + snap.Finish(iterations); + } + + snap.Display("Read CC"); + } + + /////////////////////////////////////////////////// Interlocked Tests. + // + public static void DoInterlockedIncrementPerf(int iterations) + { + PerfSnap snap = new PerfSnap(); + + snap.Start(); + try { + int test = 0; + for (int i = 0; i < iterations; i++) { + Interlocked.Increment(ref test); + } + } + finally { + snap.Finish(iterations); + } + + snap.Display("Lock Inc"); + } + + public static void DoInterlockedExchangeSucceedPerf(int iterations) + { + PerfSnap snap = new PerfSnap(); + + snap.Start(); + try { + int test = 0; + for (int i = 0; i < iterations; i++) { + Interlocked.CompareExchange(ref test, 0, 0); + } + } + finally { + snap.Finish(iterations); + } + + snap.Display("Lock Ex Succ"); + } + + public static void DoInterlockedExchangeFailPerf(int iterations) + { + PerfSnap snap = new PerfSnap(); + + snap.Start(); + try { + int test = 0; + for (int i = 0; i < iterations; i++) { + Interlocked.CompareExchange(ref test, 0, 1); + } + } + finally { + snap.Finish(iterations); + } + + snap.Display("Lock Ex Fail"); + } + + ////////////////////////////////////////////// Interrupt Disable Test. + // + public static void DoDisableIrqPerf(int iterations) + { + if (atRing3) { + // Skip this test; it would cause us to fault. + return; + } + + PerfSnap snap = new PerfSnap(); + + bool saved = Processor.DisableInterrupts(); + System.Diagnostics.Debug.Assert(saved == true); + + try { + snap.Start(); + for (int i = 0; i < iterations; i++) { + Processor.RestoreInterrupts(saved); + saved = Processor.DisableInterrupts(); + } + } + finally { + snap.Finish(iterations); + Processor.RestoreInterrupts(saved); + } + + snap.Display("Irq SVE/RSTR"); + } + + //////////////////////////////////////////////////////////// ABI Test. + // + public static void DoAbiPerf(int iterations) + { + PerfSnap snap = new PerfSnap(); + + snap.Start(); + try { + for (int i = 0; i < iterations; i++) { + Thread.NativeNoOp(); + } + } + finally { + snap.Finish(iterations); + } + snap.Display("Nothing"); + + if (breakIn) { + DebugStub.Break(); + } + + snap.Start(); + try { + for (int i = 0; i < iterations; i++) { + // This ought to be approximately a minimal ABI call + // Thread.SpinWait(0); + // XXX Thread.SpinWait doesn't traverse ABI for the time + // being. + //DebugStub.Break(); + ProcessService.GetCyclesPerSecond(); + //DebugStub.Break(); + } + } + finally { + snap.Finish(iterations); + } + + snap.Display("ABI Call"); + +#if false + ulong min = UInt64.MaxValue; + ulong max = UInt64.MinValue; + ulong beg = UInt64.MinValue; + snap.Start(); + try { + for (int i = 0; i < iterations; i++) { + // This ought to be approximately a minimal ABI call + // Thread.SpinWait(0); + // XXX Thread.SpinWait doesn't traverse ABI for the time + // being. + beg = Processor.CycleCount; + ProcessService.GetCyclesPerSecond(); + beg = Processor.CycleCount - beg; + if (max < beg) { + max = beg; + } + if (min > beg) { + min = beg; + } + if (i == 50) { + max = beg; + } + } + } + finally { + snap.Finish(iterations); + } + + snap.Display("ABI Call 2"); + Console.WriteLine("beg:{0,12:d}, min:{1,12:d}, max:{2,12:d}", + beg, min, max); +#endif + ProcessService.GetCyclesPerSecond(); + } + + /////////////////////////////////////////////////// DateTime.Now. + // + public static void DoDateTimeNow(int iterations) + { + PerfSnap snap = new PerfSnap(); + DateTime now = new DateTime(); + + snap.Start(); + for (int i = 0; i < iterations; i++) { + now = DateTime.Now; + } + snap.Finish(iterations); + snap.Display("DateTime.Now"); + + if (now.Ticks == 0) { + Console.WriteLine("It's the end of the world as we know it."); + } + } + + /////////////////////////////////////////////////// Thread Yield Test. + // + public static void DoYieldPerf(int iterations) + { + ulong before, after; + + PerfSnap snap = new PerfSnap(); + + snap.Start(); + try { + for (int i = 0; i < iterations; i++) { + Thread.Yield(); + } + } + finally { + snap.Finish(iterations); + } + + snap.Display("Yield"); + + Console.WriteLine("Measuring Thread.Yield() breakdown"); + for (int i = 0; i < iterations; i++) { + ProcessService.Waypoint0(); + Thread.Yield(); + ProcessService.WaypointDone(); + if (i == 512) { + ProcessService.WaypointDump(); + } + } + } + + /////////////////////////////////////////////////////// Wait/Set Test. + // + private static void WaitPerfThread() + { + int iterations = peerIterations; + peerReady.Set(); + + for (int i = 0; i < iterations; i++) { + waitPerfEvent1.WaitOne(); + //DebugStub.Break(); + waitPerfEvent2.Set(); + } + } + + public static void DoWaitPerf(int iterations) + { + int doit = iterations / 2; + peerIterations = doit; + waitPerfEvent1 = new AutoResetEvent(false); + waitPerfEvent2 = new AutoResetEvent(false); + + Thread peer = new Thread(new ThreadStart(WaitPerfThread)); + peer.Start(); + peerReady.WaitOne(); + + PerfSnap snap = new PerfSnap(); + + snap.Start(); + try { + for (int i = 0; i < doit; i++) { + //DebugStub.Break(); + waitPerfEvent1.Set(); + waitPerfEvent2.WaitOne(); + //DebugStub.Break(); + } + } + finally { + snap.Finish(iterations); + } + + peer.Join(); + snap.Display("Wait/Set"); + } + + /////////////////////////////////////////// Receive Performance Tests. + // + public contract ReceivePerfTest + { + in message Req(int x); + out message Resp(int x); + + state Start: Req? -> Resp! -> Start; + } + + private static TRef receivePerfEndpoint; + + private static void ReceivePerfThread() + { + ReceivePerfTest.Exp e1 = receivePerfEndpoint.Acquire(); + int arg; + + peerReady.Set(); + + for (;;) { + e1.RecvReq(out arg); + if (arg == -1) { + break; + } + e1.SendResp(arg); + } + + delete e1; + } + + public static void DoReceivePerf(int iterations) + { + int doit = iterations / 2; + + // Make a new channel. + ReceivePerfTest.Imp! e2; + ReceivePerfTest.Exp! e1; + ReceivePerfTest.NewChannel(out e2, out e1); + + // Transfer ownership of endpoint to peer thread. + receivePerfEndpoint = new TRef(e1); + + // Create our peer thread. + Thread peer = new Thread(new ThreadStart(ReceivePerfThread)); + peer.Start(); + peerReady.WaitOne(); + + PerfSnap snap = new PerfSnap(); + + snap.Start(); + + if (breakIn) { + DebugStub.Break(); + } + + try { + int arg; + for (int i = 0; i < doit; i++) { + arg = i; + e2.SendReq(arg); + e2.RecvResp(out arg); + } + } + finally { + snap.Finish(iterations); + } + + e2.SendReq(-1); + delete e2; + peer.Join(); + + snap.Display("Send/Recv"); + } + + ////////////////////////////// Receive Performance Tests with buffer + // + public contract ReceivePerf2Test + { + in message Req(int remain, byte[]! in ExHeap buffer); + out message Resp(byte[]! in ExHeap buffer); + + state Start: Req? -> Resp! -> Start; + } + + private static TRef receivePerf2Endpoint; + + private static void ReceivePerf2Thread() + { + ReceivePerf2Test.Exp e1 = receivePerf2Endpoint.Acquire(); + int arg; + byte[]! in ExHeap buffer; + + peerReady.Set(); + + for (;;) { + e1.RecvReq(out arg, out buffer); + e1.SendResp(buffer); + if (arg == 0) { + break; + } + } + + delete e1; + } + + public static void DoReceivePerf2(int iterations, int messageBytes) + { + // Make a new channel. + ReceivePerf2Test.Imp! e2; + ReceivePerf2Test.Exp! e1; + ReceivePerf2Test.NewChannel(out e2, out e1); + + // Transfer ownership of endpoint to peer thread. + receivePerf2Endpoint = new TRef(e1); + + // Create our peer thread. + Thread peer = new Thread(new ThreadStart(ReceivePerf2Thread)); + peer.Start(); + peerReady.WaitOne(); + + byte[]! in ExHeap buffer = new [ExHeap] byte[messageBytes]; + + PerfSnap snap = new PerfSnap(); + + snap.Start(); + + if (breakIn) { + DebugStub.Break(); + } + + try { + for (int i = 0; i < iterations; i++) { + e2.SendReq(iterations - i - 1, buffer); + e2.RecvResp(out buffer); + } + } + finally { + // Factor of two for one-sided send-receive only + snap.Finish(2 * iterations); + delete buffer; + } + + delete e2; + peer.Join(); + + if (messageBytes < 1024) { + snap.Display(String.Format("Send/RecvB-{0}", messageBytes)); + } + else { + snap.Display(String.Format("Send/RecvB-{0}K", + messageBytes / 1024)); + } + } + + /////////////////////////////////////////// Child-Receive performance tests + // + public static void DoChildReceivePerf(int iterations) + { + int doit = iterations / 2; + + // Make a new channel. + SendTestContract.Imp! childImp; + SendTestContract.Exp! childExp; + SendTestContract.NewChannel(out childImp, out childExp); + + // Start up our child + string[] args = new string[3]; + args[0] = "BenchChild.x86"; + args[1] = "-where"; + args[2] = "!"; + Process child = new Process(args, (Endpoint * in ExHeap)childExp); + + // set the where parameter to true + ParameterCode code; + code = child.SetStartupBoolArg(0, true); + if (code != ParameterCode.Success){ + Console.WriteLine("unable to set bool index 0. error={0}", code); + delete childImp; + return; + } + + child.Start(); + + childImp.RecvTestReady(); + + PerfSnap snap = new PerfSnap(); + + snap.Start(); + try { + int arg; + for (int i = 0; i < doit; i++) { + arg = i; + childImp.SendReq(arg); + childImp.RecvResp(out arg); + } + } + finally { + snap.Finish(iterations); + } + + childImp.SendReq(-1); + delete childImp; + child.Join(); + + snap.Display("CHILD S/R"); + } + + ////////////////////////////// Child send-receive performance test + // + public static void DoChildReceivePerf2(int iterations, int messageBytes) + { + // Make a new channel. + BufferTestContract.Imp! childImp; + BufferTestContract.Exp! childExp; + BufferTestContract.NewChannel(out childImp, out childExp); + + // Start up our child + string[] args = new string[2]; + args[0] = "BenchChild.x86"; + args[1] = "!"; + Process child = new Process(args, (Endpoint * in ExHeap)childExp); + child.Start(); + + childImp.RecvBufferReady(); + + byte[]! in ExHeap buffer = new [ExHeap] byte[messageBytes]; + + PerfSnap snap = new PerfSnap(); + + snap.Start(); + try { + for (int i = 0; i < iterations; i++) { + childImp.SendReq(iterations - i - 1, buffer); + childImp.RecvResp(out buffer); + } + } + finally { + // Factor of two for one-sided send-receive only + snap.Finish(2 * iterations); + delete buffer; + } + + delete childImp; + child.Join(); + + if (messageBytes < 1024) { + snap.Display(String.Format("Child S/RB-{0}", messageBytes)); + } + else { + snap.Display(String.Format("Child S/RB-{0}K", + messageBytes / 1024)); + } + } + + //////////////////////////////////////////// Switch Performance Tests. + // + public contract SwitchPerfTest + { + in message Req(int x); + out message Resp(int x); + + state Start: Req? -> Resp! -> Start; + } + + private static TRef switchPerfEndpoint; + + public static void SwitchPerfThread() + { + SwitchPerfTest.Exp e = switchPerfEndpoint.Acquire(); + ESet s = new ESet(); + s.Add(e); + + peerReady.Set(); + + for (int i = 0; i != -1;) { + switch receive + { + case ep.Req(arg) in s: + i = arg; + if (i != -1) { + ep.SendResp(i); + } + s.Add(ep); + break; + case ep.ChannelClosed() in s: + s.Add(ep); + break; + } + } + s.Dispose(); + } + + public static void DoSwitchPerf(int iterations) + { + int doit = iterations / 2; + + // Make a new channel. + SwitchPerfTest.Imp! e; + SwitchPerfTest.Exp! p; + SwitchPerfTest.NewChannel(out e, out p); + + // Transfer ownership of endpoint to peer thread. + switchPerfEndpoint = new TRef(p); + + // Create our peer thread. + Thread peer = new Thread(new ThreadStart(SwitchPerfThread)); + peer.Start(); + peerReady.WaitOne(); + + if (breakIn) { + DebugStub.Break(); + } + + PerfSnap snap = new PerfSnap(); + + snap.Start(); + + ESet s = new ESet(); + + try { + e.SendReq(0); + s.Add(e); + for (int i = 0; i < doit; i++) { + switch receive + { + case ep.Resp(arg) in s: + i = arg; + if (i == doit -1) { + ep.SendReq(-1); + } + else { + ep.SendReq(i + 1); + } + s.Add(ep); + break; + case ep.ChannelClosed() in s: + delete ep; + break; + } + } + } + finally { + snap.Finish(iterations); + s.Dispose(); + } + + peer.Join(); + + snap.Display("Send/Switch"); + } + + //////////////////////////////////////////// Create Directory Channel. + // + public static void DoPageAllocPerf(int iterations) + { + PerfSnap snap = new PerfSnap(); + + snap.Start(); + try { + for (int i = 0; i < iterations; i++) { + UIntPtr addr = PageTableService.Allocate(0x1000); + PageTableService.Free(addr, 0x1000); + } + } + finally { + snap.Finish(iterations); + } + + snap.Display("PageAlloc"); + } + + ////////////////////////////////////////////////////// Create Channel. + // + public static void DoChannelCreatePerf(int iterations) + { + // Make a new channel. + PerfSnap snap = new PerfSnap(); + + snap.Start(); + try { + for (int i = 0; i < iterations; i++) { + SwitchPerfTest.Imp! e2; + SwitchPerfTest.Exp! e1; + SwitchPerfTest.NewChannel(out e2, out e1); + delete e1; + delete e2; + } + } + finally { + snap.Finish(iterations); + } + + snap.Display("CreateChan"); + } + + //////////////////////////////////////////// Create Directory Channel. + // + public static void DoNamespaceChannelPerf(int iterations) + { + // Make a new channel. + PerfSnap snap = new PerfSnap(); + + snap.Start(); + try { + for (int i = 0; i < iterations; i++) { + // get NS endpoint + DirectoryServiceContract.Imp ns = DirectoryService.NewClientEndpoint(); + delete ns; + } + } + finally { + snap.Finish(iterations); + } + + snap.Display("NameChan"); + } + + /////////////////////////////////////////// Connect Through Directory. + // + public static void DoBindPerf(int iterations) + { + // Make a new channel. + PerfSnap snap = new PerfSnap(); + + // get NS endpoint + DirectoryServiceContract.Imp ns = DirectoryService.NewClientEndpoint(); + + snap.Start(); + try { + for (int i = 0; i < iterations; i++) { + MemoryContract.Exp! exp; + MemoryContract.Imp! imp; + MemoryContract.NewChannel(out imp, out exp); + ErrorCode error; + try { + SdsUtils.Bind(MemoryContract.ModuleName, ns, exp, out error); + } + finally { + } + delete imp; + } + } + finally { + delete ns; + snap.Finish(iterations); + } + snap.Display("NameBind"); + } + + /////////////////////////////////////////// TRef acquire/release test. + // + public static void DoTRefPerf(int iterations) + { + // Make a new channel. + PerfSnap snap = new PerfSnap(); + + // get NS endpoint + DirectoryServiceContract.Imp ns = DirectoryService.NewClientEndpoint(); + + TRef t = new TRef(ns); + snap.Start(); + try { + for (int i = 0; i < iterations; i++) { + DirectoryServiceContract.Imp n = t.Acquire(); + t.Release(n); + } + } + finally { + snap.Finish(iterations); + } + snap.Display("Acquire/rel"); + } + + ////////////////////////////////////////////////////////////////////// + + private contract SelectTest { + in message A(); + in message B(); + in message C(); + out message Ack(); + + state Start: one { + A? -> Ack! -> Start; + B? -> Ack! -> Start; + C? -> Ack! -> Start; + } + } + + private static TRef[] impEndpoints; + + const int NSELECT=99; // must be a multiple of 3 + const int SELECT_ITERATIONS = 1000; + + public static void SelectThread() + { + for (int i = 0; i < SELECT_ITERATIONS; i++) { + for (int j = 0; j < NSELECT; j+=3) { + SelectTest.Imp imp = ((!)impEndpoints[j]).Acquire(); + + imp.SendA(); + + ((!)impEndpoints[j]).Release(imp); + } + + for (int j = 1; j < NSELECT; j+=3) { + SelectTest.Imp imp = ((!)impEndpoints[j]).Acquire(); + + imp.SendB(); + + ((!)impEndpoints[j]).Release(imp); + } + + for (int j = 2; j < NSELECT; j+=3) { + SelectTest.Imp imp = ((!)impEndpoints[j]).Acquire(); + + imp.SendC(); + + ((!)impEndpoints[j]).Release(imp); + } + + for (int j = 0; j < NSELECT; j++) { + SelectTest.Imp imp = ((!)impEndpoints[j]).Acquire(); + + imp.RecvAck(); + + ((!)impEndpoints[j]).Release(imp); + } + } + + for (int i = 0; i < NSELECT; i++) { + SelectTest.Imp ep = ((!)impEndpoints[i]).Acquire(); + delete ep; + } + } + + private static void ActuallySelect(SelectTest.Exp! a, + SelectTest.Exp! b, + SelectTest.Exp! c, + int expect, + ref bool failed) + { + int got; + switch receive { + case c.RecvA(): + c.SendAck(); + got = 0; + break; + + case a.RecvB() && b.RecvC(): + a.SendAck(); + b.SendAck(); + got = 1; + break; + + case a.RecvA() && b.RecvC(): + a.SendAck(); + b.SendAck(); + got = 2; + break; + + case unsatisfiable: + got = -1; + break; + } + + //Console.WriteLine("[1] expected {0}, got {1}", expect, got); + if (expect != got) { + failed = true; + } + } + + public static int DoSelectB() + { + TRef[] expEndpoints = new TRef[NSELECT]; + impEndpoints = new TRef [NSELECT]; + + for (int i = 0; i < NSELECT; i++) { + SelectTest.Imp! imp; + SelectTest.Exp! exp; + SelectTest.NewChannel(out imp, out exp); + expEndpoints[i] = new TRef(exp); + impEndpoints[i] = new TRef(imp); + } + + Thread t1 = new Thread(new ThreadStart(SelectThread)); + t1.Start(); + + bool failed = false; + for (int i = 0; i < SELECT_ITERATIONS; i++) { + for(int j = 0; j < NSELECT-2; j++) { + SelectTest.Exp a = ((!)expEndpoints[j+0]).Acquire(); + SelectTest.Exp b = ((!)expEndpoints[j+1]).Acquire(); + SelectTest.Exp c = ((!)expEndpoints[j+2]).Acquire(); + + ActuallySelect(a, b, c, 0, ref failed); + + ((!)expEndpoints[j+0]).Release(a); + ((!)expEndpoints[j+1]).Release(b); + ((!)expEndpoints[j+2]).Release(c); + } + } + + if (failed) { + Console.WriteLine("[1] Done (FAILED)."); + return 1; + } + else { + Console.WriteLine("[1] Done (Success)."); + return 0; + } + } + + private static void ActuallySelect(ESet eset, + int expect, + ref bool failed) + { + if (eset == null) return; + + int got; + switch receive { + case a.RecvA() in eset: + got = 0; + a.SendAck(); + eset.Add(a); + break; + + case b.RecvB() in eset: + got = 1; + b.SendAck(); + eset.Add(b); + break; + + case c.RecvC() in eset: + got = 2; + c.SendAck(); + eset.Add(c); + break; + + case unsatisfiable: + got = -1; + break; + } + + // Console.WriteLine("[1] expected {0}, got {1}", expect, got); + if (expect != got) { + //Console.WriteLine("[1] expected {0}, got {1}", expect, got); + failed = true; + } + } + + public static int DoSelectSet() + { + int i; + + Console.WriteLine("Measuring performance of set select ..."); + + impEndpoints = new TRef [NSELECT]; + + ESet eset = new ESet(); + + for (i = 0; i < NSELECT; i++) { + SelectTest.Imp! imp; + SelectTest.Exp! exp; + SelectTest.NewChannel(out imp, out exp); + impEndpoints[i] = new TRef(imp); + + eset.Add(exp); + } + + Console.WriteLine(" Created set of {0} endpoints", NSELECT); + + Thread t1 = new Thread(new ThreadStart(SelectThread)); + + Console.WriteLine(" Starting client thread"); + t1.Start(); + + bool failed = false; + + Console.WriteLine(" Starting server loop - {0} iterations", SELECT_ITERATIONS); + for (i = 0 ; i < SELECT_ITERATIONS; i++) { + ActuallySelect(eset, 0, ref failed); + ActuallySelect(eset, 0, ref failed); + ActuallySelect(eset, 0, ref failed); + ActuallySelect(eset, 1, ref failed); + ActuallySelect(eset, 2, ref failed); + ActuallySelect(eset, 0, ref failed); + ActuallySelect(eset, 2, ref failed); + ActuallySelect(eset, 0, ref failed); + ActuallySelect(eset, 2, ref failed); + ActuallySelect(eset, 0, ref failed); + ActuallySelect(eset, 1, ref failed); + ActuallySelect(eset, 2, ref failed); + // ActuallySelect(eset, -1, ref failed); + } + eset.Dispose(); + if (failed) { + Console.WriteLine("[1] Done (FAILED)."); + return 1; + } + else { + Console.WriteLine("[1] Done (Success)."); + return 0; + } + } + + //////////////////////////////////////////// Switch Performance Tests. + // + public static void ChildThread() + { + } + + public static void DoThreadPerf(int iterations) + { + ThreadStart start = new ThreadStart(ChildThread); + + if (breakIn) { + DebugStub.Break(); + } + + PerfSnap snap = new PerfSnap(); + + snap.Start(); + try { + for (int i = 0; i < iterations; i++) { + Thread peer = new Thread(start); + peer.Start(); + peer.Join(); + } + } + finally { + snap.Finish(iterations); + } + snap.Display("CreateThread"); + } + + ///////////////////////////////////////////////// Process Create Test. + // + public static void DoCreateProcess(int iterations) + { + ulong baseline = 0; + ulong created = 0; + ulong started = 0; + ulong exited = 0; + Process[] process = new Process[iterations]; + + string[] args = new string[2]; + args[0] = "testpe.x86"; + args[1] = "!"; // Special flag to not notify debugger. + + PerfSnap snap = new PerfSnap(); + + snap.Start(); + try { + for (int i = 0; i < iterations; i++) { + baseline = Processor.CycleCount; + + // + // Time process creation. + // + process[i] = new Process(args); + created = Processor.CycleCount; + + // + // Time process start. + // + ((!)process[i]).Start(); + started = Processor.CycleCount; + + // + // Time process execution. + // + ((!)process[i]).Join(); + exited = Processor.CycleCount; + } + } + finally { + snap.Finish(iterations); + } + snap.Display("CreateProc"); + + for (int i = 0; i < iterations; i++) { + if (process[i] != null) { + ((!)process[i]).Dispose(true); + } + } + + // + // Tell the world. + // + DualWriteLine(String.Format(" Tested process: {0}", args[0])); + DualWriteLine(String.Format(" Create process: {0,15:d} cycles", created - baseline)); + DualWriteLine(String.Format(" Start process: {0,15:d} cycles", started - created)); + DualWriteLine(String.Format(" Run process: {0,15:d} cycles", exited - started)); + DualWriteLine(String.Format(" Total: {0,15:d} cycles", exited - baseline)); + DualWriteLine(String.Format(" Process.Create: {0,15:d} cycles", started - baseline)); + } + + ////////////////////////////////////////////////////////////////////// + // + public static int GetTrace() + { + Tracing.LogEntry * lstart; + Tracing.LogEntry * llimit; + Tracing.LogEntry ** lhead; + byte * tstart; + byte * tlimit; + byte ** thead; + + Tracing.GetTracingHeaders(out lstart, out llimit, out lhead, + out tstart, out tlimit, out thead); + Console.WriteLine("Log: {0:X} {1:X}, {2:X}, {3:X}", + (UIntPtr)lstart, (UIntPtr)llimit, (UIntPtr)lhead, (UIntPtr)(*lhead)); + Console.WriteLine("Text: {0:X} {1:X}, {2:X}, {3:X}", + (UIntPtr)tstart, (UIntPtr)tlimit, (UIntPtr)thead, (UIntPtr)(*thead)); + return 0; + } + + public static void ClearEnvironment(MemoryContract.Imp:ReadyState! imp) + { + if (allowGC) { +#if false + long nothing; + // We don't do this for now because we can't + // guarantee the concurrent GC running in the + // kernel has finished. + imp.SendCollectGarbage(); + imp.RecvMemory(out nothing); +#endif + GC.Collect(); + } + } + + public static void Pause() + { + if (pauseForKeys) { + Console.WriteLine("Press any key to continue."); + Console.Read(); + } + } + + internal static int AppMain(Parameters! config) + { + int iterations = (int) config.iterations; + + // Temporaries for command-line parsing + bool xmlOutput = config.xmlOutput; + allowGC = config.allowGC; + pauseForKeys = config.pauseForKeys; + breakIn = config.breakIn; + + if (Processor.AtKernelPrivilege()) { + atRing3 = false; + DualWriteLine("Singbench running at KERNEL privilege"); + } else { + atRing3 = true; + DualWriteLine("Singbench running at USER privilege"); + } + + peerReady = new AutoResetEvent(false); + peerBegin = new AutoResetEvent(false); + peerFinish = new AutoResetEvent(false); + + MemoryContract.Imp impMem = config.memoryRef.Acquire(); + if (impMem == null) { + throw new ApplicationException("Error: Unable to bind to " + + MemoryContract.ModuleName); + } + + impMem.RecvReady(); + + PerfSnap.SetOptions(atRing3, xmlOutput); + + GetTrace(); + + Console.WriteLine("Benchmarks: entered"); + + try { + ClearEnvironment(impMem); + DoGetCycleCountPerf(iterations); + Pause(); + + ClearEnvironment(impMem); + DoInterlockedIncrementPerf(iterations); + Pause(); + + ClearEnvironment(impMem); + DoInterlockedExchangeSucceedPerf(iterations); + Pause(); + + ClearEnvironment(impMem); + DoInterlockedExchangeFailPerf(iterations); + Pause(); + + ClearEnvironment(impMem); + DoDisableIrqPerf(iterations); + Pause(); + + ClearEnvironment(impMem); + DoAbiPerf(iterations); + Pause(); + + ClearEnvironment(impMem); + DoDateTimeNow(iterations); + Pause(); + + ClearEnvironment(impMem); + DoYieldPerf(iterations); + Pause(); + + ClearEnvironment(impMem); + DoWaitPerf(1000); + Pause(); + + ClearEnvironment(impMem); + DoReceivePerf(1000); + Pause(); + + for (int i = 1; i <= 65536; i *= 2) { + ClearEnvironment(impMem); + DoReceivePerf2(iterations, i); + Pause(); + } + + // Child-channel tests + ClearEnvironment(impMem); + DoChildReceivePerf(1000); + Pause(); + + + for (int i = 1; i <= 65536; i *= 2) { + ClearEnvironment(impMem); + DoChildReceivePerf2(iterations, i); + Pause(); + } + + ClearEnvironment(impMem); + DoSwitchPerf(1000); + Pause(); + + ClearEnvironment(impMem); + DoPageAllocPerf(1000); + Pause(); + + ClearEnvironment(impMem); + DoThreadPerf(100); + Pause(); + + ClearEnvironment(impMem); + DoChannelCreatePerf(1000); + Pause(); + + ClearEnvironment(impMem); + DoNamespaceChannelPerf(100); + Pause(); + + ClearEnvironment(impMem); + DoTRefPerf(iterations); + Pause(); + + ClearEnvironment(impMem); + DoBindPerf(1000); + Pause(); + + ClearEnvironment(impMem); + DoCreateProcess(10); + +#if false + Pause(); + // select receive code currently explodes with a null pattern + //DoChannelPerf(1000, false); + // Pause(); + + Console.WriteLine("Skipping select recv test"); + //DoChannelPerf(1000, true); + // Pause(); + Console.WriteLine("Skipping select recv / alloc test"); + + //DoSelectSet(); + // Pause(); + Console.WriteLine("Skipping select set test"); + + ClearEnvironment(impMem); + DoSelectB(); + Pause(); + + ClearEnvironment(impMem); + DoSelectSet(); +#endif + + } catch (Exception e) { + Console.WriteLine("Caught {0}", e.Message); + // How do I work out where an exception was thrown from these days? + //Console.WriteLine(e.StackTrace); + delete impMem; + return 1; + } + delete impMem; + return 0; + } + } +} diff --git a/base/Applications/Benchmarks/SingBench/SingBench/SingBenchApp.csproj b/base/Applications/Benchmarks/SingBench/SingBench/SingBenchApp.csproj new file mode 100644 index 0000000..d4dbf6a --- /dev/null +++ b/base/Applications/Benchmarks/SingBench/SingBench/SingBenchApp.csproj @@ -0,0 +1,30 @@ + + + + + + + Exe + singbench + true + + + + + + + + + + + + + diff --git a/base/Applications/Benchmarks/SpecWeb99/webfiles/README.txt b/base/Applications/Benchmarks/SpecWeb99/webfiles/README.txt new file mode 100644 index 0000000..ffe575c --- /dev/null +++ b/base/Applications/Benchmarks/SpecWeb99/webfiles/README.txt @@ -0,0 +1,29 @@ +From: Mark Aiken +Sent: Sunday, October 16, 2005 4:19 PM +To: Chris Hawblitzel +Subject: Running SPECweb + +Here is how to run webfiles: + +On Windows: +in Applications\Benchmarks\SpecWeb99\webfiles type +"msb" + +On Singularity: + +First run: +- "mkfs /dev/vol2" +- "fsmount /dev/vol2 /fs -n" [no caching] +- "wafgen99 -v 10 /fs" [Generates lots of files] +- "fsunmount" +- reboot to clear the log. + +Second boot: +- "fsmount /dev/vol2 /fs" +- "webfiles -r:60" + +Alternatively, to run an fixed benchmark size, use the -f:X, forced +iteration, parameter: +- "webfiles -f:20000" + + diff --git a/base/Applications/Benchmarks/SpecWeb99/webfiles/random.cs b/base/Applications/Benchmarks/SpecWeb99/webfiles/random.cs new file mode 100644 index 0000000..b386e31 --- /dev/null +++ b/base/Applications/Benchmarks/SpecWeb99/webfiles/random.cs @@ -0,0 +1,355 @@ +#define NO_ZIPF_SPIKE + +/* + * (C)1997 Standard Performance Evaluation Corporation (SPEC) + * + * This suite contains code acquired from several sources who + * understand and agree with SPEC's goal of creating fair and + * objective benchmarks to measure computer performance. + * + * This copyright notice is placed here only to protect SPEC in the + * event the source is misused in any manner that is contrary to + * the spirit, the goals and the intent of SPEC. + * + * The source code is provided to the user or company under the + * license agreement for the SPEC Benchmark Suite for this suite. + */ + +/***************************************************************** + * * + * Copyright 1991,1992 Legato Systems, Inc. * + * Copyright 1991,1992 Auspex Systems, Inc. * + * Copyright 1991,1992 Data General Corporation * + * Copyright 1991,1992 Digital Equipment Corporation * + * Copyright 1991,1992 Interphase Corporation * + * Copyright 1991,1992 Sun Microsystems, Inc. * + * * + *****************************************************************/ + +/* + * ---------------------- laddis_c_rnd.c --------------------- + * + * Random number generator. + * + *.Exported_routines + * double Spec_random (RandomState *theState); + * long Spec_nrandom (RandomState *theState); + * void Spec_srandom (RandomState *theState, int seed); + * + *.Local_routines + * None + * + *.Revision_History + * 06-Nov-05 Convert to Sing# + * 24-May-97 Chan-Nui Re-write to make thread-safe + * 28-Nov-91 Teelucksingh ANSI C + * 01-Aug-91 Wiryaman laddis_srandom() and laddis_random()whee + * now use spec_srand() and spec_rand() + * instead of srandom() and random(). + * 17-Apr-91 Wittle Created. + */ + +/* + * Here's the source for the random number generator that SPEC uses. + * The function to be called is "spec_rand" which returns an integer + * between 1 and MAX_INT-1. + * + */ + + +/***************************************************************************** + * UNIFORM Distribution * + *****************************************************************************/ +using System; +using Singularity.Application.SPECWeb99; + +//using Microsoft.Singularity.Math; +//using Microsoft.Singularity; +//using Microsoft.Singularity.Directory; +//using Microsoft.Singularity.V1.Services; +//using Microsoft.Singularity.Io; +#if SINGULARITY +using Microsoft.Contracts; +#endif + +namespace Singularity.Application.SPECWeb99.WebFiles +{ + public class Random + { + public const int A_MULTIPLIER = 16807; + public const int M_MODULUS = 2147483647; /* (2**31)-1 */ + public const int Q_QUOTIENT = 127773; /* 2147483647 / 16807 */ + public const int R_REMAINDER = 2836; /* 2147483647 % 16807 */ + /* + * Compute the next random number. + */ + public class RandomState + { + public int val; + + public RandomState(int val) + { + this.val = val; + } + } + + public class ZipfState + { + public RandomState rstate; + public int size; + public double []table; + +#if SINGULARITY + [NotDelayed] +#endif + public ZipfState (RandomState rstate, int size) + { + this.size = size; + this.rstate = rstate; + table= new double[size+1]; + if (table == null) { + Console.WriteLine("ZipfState constructor: can't create {0} entries for table", + size+1); + } + } + } // ZipfState + + +#if STATIC_NORMAL_DIST + public class NormalState { + public RandomState rstate; + public int size; + public int []table; + }; +#else + public class NormalState { + public RandomState rstate; + public double mean, stddev, y2; + public bool use_last; + }; +#endif + + public double Spec_random(RandomState /*!*/ theState) + /* See "Random Number Generators: Good Ones Are Hard To Find", */ + /* Park & Miller, CACM 31#10 October 1988 pages 1192-1201. */ + /***********************************************************/ + /* THIS IMPLEMENTATION REQUIRES AT LEAST 32 BIT INTEGERS ! */ + /***********************************************************/ + { + int lo; + int hi; + int test; + + hi = theState.val / Q_QUOTIENT; + lo = theState.val % Q_QUOTIENT; + test = A_MULTIPLIER * lo - R_REMAINDER * hi; + if (test > 0) { + theState.val = test; + } else { + theState.val = test + M_MODULUS; + } + return((float) theState.val / M_MODULUS); + } + + /* + * Seed the random number generator. + */ + public void Spec_srandom( RandomState /*!*/ theState, int seed ) { + theState.val = seed; + } + + /* + * Returns a random number. + */ + public int Spec_nrandom( RandomState/*!*/ theState ) { + Spec_random(theState); + return(theState.val); + } + + /***************************************************************************** + * ZIPF Distribution * + *****************************************************************************/ + + public ZipfState spec_zipf_setup(RandomState rstate, int size, double Z) + { + int i; + double zipf_sum; + + ZipfState theState = new ZipfState(rstate, size); + if (theState == null) return null; + + /* compute zipf values for samples 1-n */ + for (i = 1; i <= size; i++) { + theState.table[i] = Math.Pow(((double)1.0/((double)i)), Z); + //theState.table[i] = 1; // SPL TOTAL HACK until POW works!! + } + + /* sum the values so we can compute probabilities. */ + /* at the same time, make the values cumulative */ + zipf_sum = 0.0; + for (i = 1; i <= size; i++) { + zipf_sum += theState.table[i] ; + theState.table[i] = zipf_sum; + } + theState.table[size] = 0.0; + theState.table[0] = 0.0; + + /* compute probability values by dividing by the sum. */ + /* also reverse the table so we have values starting at 1.0 */ + /* and descending to 0.0 (this is what spec_zipf needs) */ + for (i = 0; i < size; i++) { + theState.table[i] = 1.0 - (theState.table[i]/zipf_sum); + } + + + return theState; + } + + private void spec_zipf_free( ZipfState/*!*/ theState) { + if (theState.table != null) { + theState.table = null; + } + } + + public int spec_zipf(ZipfState/*!*/ theState) { + double r; + int i; + +#if NO_ZIPF_SPIKE + do{ +#endif + r = Spec_random(theState.rstate); + i = 0; + while (r < theState.table[i]) { + i++; + } +#if NO_ZIPF_SPIKE + } while (i>theState.size); +#endif + return i-1; + } + + + + +#if STATIC_NORMAL_DIST +/* Right now, mean and stddev are ignored. If someone has a good function to + generate the cdf for normal distributions, let me know... */ +/* size=20, mean = 10, stddev = 3.5, will generate numbers from 0 to 20 */ +NormalState spec_normal_setup(, RandomState rstate, double mean, double stddev) { + +double normal_dist[] = { + 0.002137432, + 0.005064024, + 0.011135458, + 0.022750062, + 0.043238098, + 0.076563771, + 0.126549006, + 0.19568292, + 0.283854542, + 0.387548544, + 0.5, + 0.612451456, + 0.716145458, + 0.80431708, + 0.873450994, + 0.923436229, + 0.956761902, + 0.977249938, + 0.988864542, + 0.994935976, + 1 +}; + int i, index = 0; + + theState.size = 1000; + theState.rstate = rstate; + + theState.table=(int *)malloc(sizeof(int)*(theState.size+1)); + if (theState.table == NULL) { + fprintf(stderr, "spec_normal_setup: can't malloc %d bytes for table\n", + sizeof(double)*theState.size); + exit (1); + } + + for (i = 0; i < theState.size; i++) { + if ((double)i / (double)theState.size > normal_dist[index]) { + index++; + } + theState.table[i] = index; + } + + return theState; +} + +void spec_normal_free(NormalState theState) { + if (theState.table) { + free(theState.table); + } +} + +int spec_nnormal(NormalState theState) { + int rval = spec_nrandom(theState.rstate.val); + rval = rval % theState.size; + return theState.table[rval]; +} + +#else + +/* Guts of this routine are based on: */ +/* boxmuller.c Implements the Polar form of the Box-Muller + Transformation + + (c) Copyright 1994, Everett F. Carter Jr. + Permission is granted by the author to use + this software for any application provided this + copyright notice is preserved. + +*/ + + private NormalState spec_normal_setup(NormalState/*!*/ theState, + RandomState/*!*/ rstate, + double mean, + double stddev) + { + theState.mean = mean; + theState.stddev = stddev; + theState.rstate = rstate; + theState.use_last = false; + return null; + } + + void spec_normal_free(NormalState theState) + { + } + + private double Spec_normal(NormalState/*!*/ theState) + { + double x1, x2, w, y1; + + if (theState.use_last ) { /* use value from previous call */ + y1 = theState.y2; + } + else { + do { + x1 = 2.0 * Spec_random(theState.rstate) - 1.0; + x2 = 2.0 * Spec_random(theState.rstate) - 1.0; + w = x1 * x1 + x2 * x2; + } while ( w >= 1.0 ); + + w = Math.Sqrt( (-2.0 * Math.Log( w ) ) / w ); + y1 = x1 * w; + theState.y2 = x2 * w; + } + theState.use_last = !(theState.use_last); + return( theState.mean + y1 * theState.stddev ); + } + + private int spec_nnormal(NormalState/*!*/ theState) + { + return (int)(Spec_normal(theState)); + } +#endif + } //random +} //namespace diff --git a/base/Applications/Benchmarks/SpecWeb99/webfiles/urlcache.cs b/base/Applications/Benchmarks/SpecWeb99/webfiles/urlcache.cs new file mode 100644 index 0000000..eceaf47 --- /dev/null +++ b/base/Applications/Benchmarks/SpecWeb99/webfiles/urlcache.cs @@ -0,0 +1,99 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +/////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Collections; +using System.Text; + +namespace Singularity.Application.SPECWeb99.WebFiles +{ + class Cache { + private const bool verbose = false; + private UrlSet cache; + private UrlSet free; + private int size; + + public Cache(int cacheSize, int deckSize) + { + cache = new UrlSet(cacheSize); + free = new UrlSet(deckSize); + this.size = cacheSize; + } + + public FileSpec GetUrl(Client/*!*/ client, int id) { + // first check the local cache + // then see if anyone else is generating the global + + if (cache.pos > 0) { + return cache.urls[--cache.pos]; + } + + // return local free to global free pool + + client.globalLock.WaitOne(); + while (free.pos > 0) { + if (client.freeDeck.pos >= client.freeDeck.urls.Length) { + //Console.WriteLine(" too many free slots!"); + free.urls[--free.pos] = null; + //DebugStub.Break(); + free.pos--; + } + else { + client.freeDeck.urls[client.freeDeck.pos++] = + free.urls[--free.pos]; + } + } + + // now see if there are any urls available + // if not either wait on or generate the global deck + + while (client.urlDeck.pos == 0){ + if (client.generatingUrls == false) { + //Console.WriteLine("Generating cache"); + UrlSet temp = client.urlDeck; + client.urlDeck = client.spareDeck; + client.spareDeck = temp; + client.generatingUrls = true; + client.syncLock.WaitOne(); + client.globalLock.ReleaseMutex(); + client.GenerateFileSpecs(); + client.globalLock.WaitOne(); + client.generatingUrls = false; + client.syncLock.ReleaseMutex(); + } + else { + //Console.WriteLine("Waiting for cache"); + client.globalLock.ReleaseMutex(); + client.syncLock.WaitOne(); + client.syncLock.ReleaseMutex(); + client.globalLock.WaitOne(); + } + } + + // the global deck is ok -- prime our cache + + if (client.urlDeck.pos > 0 ) { + for (int i =0; i < cache.urls.Length && (client.urlDeck.pos > 0); i++) { + cache.urls[cache.pos++] = + client.urlDeck.urls[--client.urlDeck.pos]; + } + } + client.globalLock.ReleaseMutex(); + return cache.urls[--cache.pos]; + } + + public void FreeUrl(FileSpec url) { + if (free.pos+1 >= free.urls.Length) { + //Console.WriteLine("free cache full! de-allocating"); + url = null; + return; + } + free.urls[free.pos++] = url; + } + } +} diff --git a/base/Applications/Benchmarks/SpecWeb99/webfiles/webfiles.cs b/base/Applications/Benchmarks/SpecWeb99/webfiles/webfiles.cs new file mode 100644 index 0000000..d4ce537 --- /dev/null +++ b/base/Applications/Benchmarks/SpecWeb99/webfiles/webfiles.cs @@ -0,0 +1,1088 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +/////////////////////////////////////////////////////////////////////////////// + +//----------------------------------------------------------------------- +// Simulate the file reading portion of the specweb99 test suite +// randomly pick files from the content generated by wafgen99 +// read them from disk +//----------------------------------------------------------------------- + +using System; +using System.Text; +using System.Collections; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Threading; + +#if SINGULARITY +using Microsoft.Singularity; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.V1.Services; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Channels; +using Microsoft.SingSharp; +using FileSystem.Utils; +using Singularity.Application.SPECWeb99; +using Microsoft.Contracts; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +#endif + +namespace Singularity.Application.SPECWeb99.WebFiles +{ + class Defaults + { + internal const string Root = "/fs"; + internal const string RelativePath = "file_set"; + internal const int BlockSize = 16384; + internal const int Connections = 10; + internal const int RunSeconds = 10; + internal const int WarmUpSeconds = 2; + }; + +#if SINGULARITY + [ConsoleCategory(HelpMessage="Null Disk r/w performance test", DefaultAction=true)] + internal class Parameters + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [LongParameter( "b", Default=Defaults.BlockSize, HelpMessage="Block Size to be read.")] + internal long blockSize; + + [LongParameter( "c", Default=Defaults.Connections, HelpMessage="Set number of connections to simulate.")] + internal long connections; + + [LongParameter( "f", Default=0, HelpMessage="Forced iterations.")] + internal long forcedIterations; + + [LongParameter( "k", Default=-1, HelpMessage="Restrict files to this class number.")] + internal long classSizeNum; + + [LongParameter( "r", Default=Defaults.RunSeconds, HelpMessage="Run time in seconds.")] + internal long runTime; + + [LongParameter( "t", Default=1, HelpMessage="Number of threads to use/")] + internal long numThreads; + + [LongParameter( "v", Default=0, HelpMessage="Verbosity level")] + internal long verbose; + + [LongParameter( "w", Default=Defaults.WarmUpSeconds, HelpMessage="Warmup time in seconds.")] + internal long rampTime; + + [BoolParameter( "x", Default=false, HelpMessage="no read -- just bind")] + internal bool testMode; + + [StringParameter("directory", Mandatory=true, Position = 0, Default = Defaults.Root, HelpMessage="path to find wafgen99 data")] + internal string contentPrefix; + + reflective internal Parameters(); + + internal int AppMain() { + return SpecMain.AppMain(this); + } + } +#endif +#if !SINGULARITY + class FileReader { + //const uint FILE_FLAG_NO_BUFFERING = 0x20000000; + const uint FILE_FLAG_NO_BUFFERING = 0; + const uint GENERIC_READ = 0x80000000; + const uint OPEN_EXISTING = 3; + IntPtr handle; + + [DllImport("kernel32", SetLastError=true)] + private static extern unsafe IntPtr CreateFile( + string FileName, // file name + uint DesiredAccess, // access mode + uint ShareMode, // share mode + uint SecurityAttributes, // Security Attributes + uint CreationDisposition, // how to create + uint FlagsAndAttributes, // file attributes + int hTemplateFile // handle to template file + ); + + [DllImport("kernel32", SetLastError=true)] + private static extern unsafe bool ReadFile( + IntPtr hFile, // handle to file + void* pBuffer, // data buffer + int NumberOfBytesToRead, // number of bytes to read + int* pNumberOfBytesRead, // number of bytes read + int Overlapped // overlapped buffer + ); + + [DllImport("kernel32", SetLastError=true)] + private static extern unsafe bool CloseHandle( + IntPtr hObject // handle to object + ); + + [DllImport("kernel32", SetLastError=true)] + private static extern unsafe uint GetFileSize( + IntPtr hObject, // handle to object + uint *pFileSizeHigh // receives high 32-bits of file size. + ); + + public bool Open(string FileName) { + // open the existing file for reading + handle = CreateFile( + FileName, + GENERIC_READ, + 0, + 0, + OPEN_EXISTING, + FILE_FLAG_NO_BUFFERING, + 0); + + if (handle != IntPtr.Zero && handle != ((IntPtr) (-1)) ) { + return true; + } + else { + return false; + } + } + + public unsafe int Read(byte[] buffer, int index, int count) { + int n = 0; + fixed (byte* p = buffer) { + if (!ReadFile(handle, p + index, count, &n, 0)) { + return 0; + } + } + return n; + } + + public bool Close() { + // close file handle + return CloseHandle(handle); + } + + public unsafe int Size() { + return (int)GetFileSize(handle, null); + } + } +#endif + + public class FileSpec + { + public int dirNum, classNum, fileNum; + public long size; + } + + public class UrlSet + { + public int pos; + public FileSpec[] urls; + + public UrlSet(int size) + { + pos = 0; + urls = new FileSpec[size]; + } + } + + public class Client + { + ////////////////////////////////// + // Constants + private const int FILES_PER_CLASS = 9; + private const int MAX_PATH = 256; + private const int LINESIZE = 64; + private const int MARKER_FREQ = 4096; + private const int BUF_SIZE = 1024*1024; /* 1MB */ + private const int MAX_DECK = 1000; + ////////////////////////////////// + // Pseudo-constants + private static readonly int[] FILE_ORDER = {4,3,5,2,6,1,7,8,0}; + private static readonly int[] CLASS_BASE_SIZE = {1024, 10240, 102400, 1024000}; + private static readonly double[] CLASS_PROB = {0.35, 0.50, 0.14, 0.01}; + private static readonly int MAX_CLASS_COUNT = CLASS_BASE_SIZE.Length; + + ////////////////////////////////// + // static variables + public static string pathPrefix = ""; + public static int [] fileBucket; + + ////////////////////////////////// + // Instance variables + public Random.RandomState randomState; + public bool generatingUrls; + public Mutex globalLock; + public Mutex syncLock; + public UrlSet urlDeck; + public UrlSet freeDeck; + public UrlSet spareDeck; +#if SINGULARITY + public static TRef namespaceRootT; + private long fileCount = 0; + private long repeatCount = 0; + private bool dumpTable = false; +#else + /// + /// will not work for multiple threads!!! + /// + private static FileReader reader = new FileReader(); +#endif + private long dirCount = 0; + private static long blockSize = 0; + private long totalSize = 0; + private long fileSizeNum = 0; + private long classSizeNum = 0; + private long threadNum = 1; + private long verbose = 0; + private bool testMode = false; + private int runTime; + private int rampTime; + private int forcedIterations; + + private LocalState[] workerLocalStates; + private StringBuilder sb; + public static WorkerState currentState; + + Random.ZipfState zipfDir; + Random.ZipfState zipfFile; + Random rand; + + public enum WorkerState + { + Start = 0, + Rampup = 1, + Run = 2, + Done = 3, + } + + // per-thread state + private class LocalState + { + public WorkerState State; +#if SINGULARITY + public DateTime StartTime; +#endif + public long bindCount; + public TimeSpan bindTime; + public long readCount; + public TimeSpan readTime; + public TimeSpan totalTime; + public long bytesRead; + public int forcedIterations; + + public LocalState(int forcedIterations) + { + bytesRead = 0; + bindTime = new TimeSpan(0); + readTime = new TimeSpan(0); + totalTime = new TimeSpan(0); + + readCount = 0; + bindCount = 0; + this.forcedIterations = forcedIterations; + } + } + +#if SINGULARITY + [NotDelayed] +#endif + public Client(string/*!*/ prefix, long dir, + long bSize, long fSize, + long threads, long verbose, + long cSize, bool test, + int rampTime, int runTime, + int forcedIterations) + { + dirCount = dir; + pathPrefix = prefix; + fileSizeNum = fSize; + threadNum = threads; + classSizeNum = cSize; + blockSize = bSize; + this.verbose = verbose; + testMode = test; + this.rampTime = rampTime; + this.runTime = runTime; + this.forcedIterations = forcedIterations; + + globalLock = new Mutex(); + syncLock = new Mutex(); + urlDeck = new UrlSet(MAX_DECK); + freeDeck = new UrlSet(MAX_DECK); + spareDeck = new UrlSet(MAX_DECK); + fileBucket = new int [FILES_PER_CLASS]; + sb = new StringBuilder(512); + + if (sb == null) throw new Exception (" could not allocate memory for string builder"); +#if SINGULARITY + namespaceRootT = new TRef( + DirectoryService.NewClientEndpoint()); +#else +#endif + workerLocalStates = new LocalState[threads]; + + if (workerLocalStates == null) { + throw new Exception ("unable to alloc workerstats"); + } + } + + //------------------------------------------------------------------ + // ReadFile + // open and read its content of fileName + // throw the content away (no copying, no converting etc...) + //------------------------------------------------------------------ + + // FIXFIX way this is called is rather bizarre. + // a Client spawns LocalWorker objects that call back to this + // function. Should be moved into the LoadWorker class + + #if SINGULARITY + private byte[]/*!*/ in ExHeap ReadFile(string/*!*/ fileName, + [Claims] byte[]/*!*/ in ExHeap inBuf, + ref LocalState local + ) + { + if (local == null) { + Console.WriteLine("ReadFile: local state is null!"); + return inBuf; + } + + FileContract.Imp conn = null; + DateTime start; + DateTime beginTotal; + TimeSpan btime = new TimeSpan(0); + + beginTotal = DateTime.Now; + + // only perform timing while in the run state + + DirectoryServiceContract.Imp:Ready! ds = Client.namespaceRootT.Acquire(); + ErrorCode errorCode = ErrorCode.Unknown; + try { + if (currentState == WorkerState.Run) { + start = DateTime.Now; + conn = FileUtils.OpenFile(fileName, ds, out errorCode); + btime = DateTime.Now - start; + local.bindTime += btime; + local.bindCount++; + } else { + conn = FileUtils.OpenFile(fileName, ds, out errorCode); + } + } + finally { + Client.namespaceRootT.Release(ds); + } + + if (conn == null) { + Console.WriteLine("Failed to open file '{0}' code={1}",fileName, SdsUtils.ErrorCodeToString(errorCode)); + throw new Exception(" file missing"); + return inBuf; + } + + try { + int error = 0; + long filePos = 0; + long bytesRead = 0; + + start = DateTime.Now; + + while (!testMode) { + conn.SendRead(inBuf, 0, filePos, inBuf.Length); + conn.RecvAckRead(out inBuf, out bytesRead, out error); + local.readCount++; + if (error != 0) { + throw new Exception(" Encountered error while reading " + fileName); + break; + } + if (bytesRead == 0) break; + filePos += bytesRead; + } + + if (currentState == WorkerState.Run) { + local.bytesRead += filePos; + TimeSpan x = DateTime.Now - start; + local.readTime += x; + } + } + finally { + delete conn; + } + + if (currentState == WorkerState.Run) { + local.totalTime += DateTime.Now - beginTotal; + } + return inBuf; + } +#endif + + /// + /// generate a new "deck" of random files + /// + public void GenerateFileSpecs() + { + FileSpec fs; + + double totalProb = 0.0; + + + UrlSet fr = freeDeck; + UrlSet sp = spareDeck; + + // + // Ensure the spare deck is fully allocated + // if there are any elements in the free pool use them + // otherwise we need a new allocations + // + globalLock.WaitOne(); +#if verbose + Console.WriteLine("gendeck: {0} freed slots spare={1},", + fr.pos,sp.pos,urlDeck.pos); + //DebugStub.Break(); +#endif + // fill up the spare deck. Start with using + // items from the free deck. If none are available + // allocate them. + + // NOTE allocation should mostly happen during the initialization phase + + for (int i=0; i < fr.urls.Length; i++){ + if (fr.pos == 0 ) { + //if ( sp.urls[i] != null) DebugStub.Break(); + sp.urls[i] = new FileSpec(); + if (sp.urls[i] == null) { + throw new Exception ("no memory!"); + } + // spit out diagnostics if we are allocating during the run phase + if (currentState == WorkerState.Run) Console.Write(" @{0}",i); + } + else { + sp.urls[i] = fr.urls[--fr.pos]; + } + } + globalLock.ReleaseMutex(); + + // Now that we have a spare deck with the needed number of items + // fill in their values according to spec. + + // The loop immediately below will generate s set of files conforming to the + // requested probabilities but will not be random. + + for (int classNo = 0; classNo < MAX_CLASS_COUNT; classNo++) { + totalProb += CLASS_PROB[classNo]; + while (sp.pos < totalProb * sp.urls.Length) { + fs = sp.urls[sp.pos++]; + if (fs == null) { + throw new Exception(" spare[" + sp.pos + "] is null!"); + } + fs.classNum = classNo; + fs.fileNum = FILE_ORDER[rand.spec_zipf(zipfFile)]; + fs.dirNum = rand.spec_zipf(zipfDir); + + fs.size = CLASS_BASE_SIZE[fs.classNum] * (fs.fileNum +1) / 10; + + if (verbose > 4) { + sb.Length = 0; //reset the buffer + sb.Append(pathPrefix); + sb.Append("/dir"); + sb.Append(fs.dirNum.ToString("d05")); + sb.Append("/class"); + sb.Append(fs.classNum); + sb.Append("_"); + sb.Append(fs.fileNum); + Console.WriteLine("size {0} file={1}",fs.size,sb.ToString()); + } + } + if (verbose > 1) { + Console.WriteLine("Generating class[{0}] prob={1:f2} urlCount={2}", + classNo, CLASS_PROB[classNo], sp.pos); + } + } + + /* Randomize deck */ + for (int i = 0; i < sp.pos ; i++) { + int pos = rand.Spec_nrandom(randomState) % (sp.pos - i); + FileSpec obj = sp.urls[sp.pos- i - 1]; + sp.urls[sp.pos - i - 1] = sp.urls[pos]; + sp.urls[pos] = obj; + } + } + + //------------------------------------------------------------------ + // Generate Load + // creates the random list of files to be done every iteration + // Reads contents of entire file for every file in the list + // This list is generated so we can see if each loop has identical timings + //------------------------------------------------------------------ + private class LoadWorker + { + private Client hostClient; + private LocalState localState; +#if SINGULARITY + private readonly ArrayList fs; +#endif + private StringBuilder sb; + private int readSize; + private Cache cache; + private int id; // local thread index + + public LoadWorker(Client parent, ref LocalState localState, int readSize, int id) + { + hostClient = parent; + this.localState = localState; + sb = new StringBuilder(512); + this.readSize = readSize; + cache = new Cache(20, 20 *2); + this.id = id; + } +#if SINGULARITY + public byte []/*!*/ in ExHeap ProcessUrl( + FileSpec fileSpec, + [Claims] byte []/*!*/ in ExHeap buf) { +#else + public void ProcessUrl(FileSpec fileSpec, byte[] buf, ref LocalState local ) { +#endif + if (fileSpec == null) throw new Exception ("Attempting to read from null fileSpec"); +#if SINGULARITY + sb.Length = 0; //reset the buffer + sb.Append(pathPrefix); + sb.Append("/dir"); + sb.Append(fileSpec.dirNum.ToString("d05")); + sb.Append("/class"); + sb.Append(fileSpec.classNum); + sb.Append("_"); + sb.Append(fileSpec.fileNum); + string path = sb.ToString(); + + if (hostClient.verbose > 2) { + Console.WriteLine("reading {0}", path); + } + buf = hostClient.ReadFile(path, buf, ref localState); +#else + sb.Length = 0; //reset the buffer + sb.Append(pathPrefix); + sb.Append("\\dir"); + sb.Append(fileSpec.dirNum.ToString("d05")); + sb.Append("\\class"); + sb.Append(fileSpec.classNum); + sb.Append("_"); + sb.Append(fileSpec.fileNum); + string path = sb.ToString(); + + int error = 0; + //Console.Write("."); + DateTime beginTotal = DateTime.Now; + if (!reader.Open(path)) { + Console.WriteLine("open failed: {0}", path); + throw new Exception("open failure: "+path); + } + + DateTime beginRead = DateTime.Now; + for (long pos = 0; pos < fileSpec.size;) { + int bytes = reader.Read(buf, 0, buf.Length); + //Console.Write("."); + if (bytes == 0) { + Console.WriteLine("bytes read={0}, error={1} pos={2}", + bytes, error, pos); + break; + } + pos += bytes; + //if (pos != fileSpec.size) throw new Exception (" wrong size pos=" + pos + " bytes=" + bytes); + } + reader.Close(); + if (currentState == WorkerState.Run) { + DateTime end = DateTime.Now; + local.totalTime += end - beginTotal; + local.bindTime += beginRead - beginTotal; + local.readTime += end - beginRead ; + local.bytesRead += fileSpec.size; + } +#endif + Client.fileBucket[fileSpec.fileNum]++; + path = null; +#if SINGULARITY + return buf; +#endif + } + + public void RunLoad() + { +#if SINGULARITY + byte [] in ExHeap buf = new[ExHeap] byte[readSize]; +#else + // Allocate one one buffer for all operations + byte[] buf = new byte [blockSize]; +#endif + // if loop we've been told to quit, but run at least the forcedIterations. + for (int iterations = 0;; iterations++) { + if (iterations >= localState.forcedIterations && + localState.State == WorkerState.Done) { + break; + } + + FileSpec fs = cache.GetUrl(hostClient,id); +#if SINGULARITY + buf = ProcessUrl(fs, buf); +#else + ProcessUrl(fs,buf, ref localState); +#endif + cache.FreeUrl(fs); + } +#if SINGULARITY + delete buf; +#endif + } + } + + public void InitializeGlobalState() + { + // the following initialization is taken from specweb99/load_generate and client.c + rand = new Random(); + int first_seed = 2; + randomState = new Random.RandomState(first_seed); + zipfDir = rand.spec_zipf_setup(randomState, (int)dirCount, 1.0); + zipfFile = rand.spec_zipf_setup(randomState, FILES_PER_CLASS, 1.0); + generatingUrls = false; + } + + public long GatherStats(out long totalFiles) + { + long total = 0; + totalFiles = 0; + Console.WriteLine("Thread stats:"); + for (int i = 0; i < threadNum; i++) { + LocalState temp = workerLocalStates[i]; + if (temp != null) { + double t1 = (double)temp.totalTime.Ticks / TimeSpan.TicksPerSecond; + double t2 = (double)temp.bindTime.Ticks / TimeSpan.TicksPerSecond; + double t3 = (double)temp.readTime.Ticks / TimeSpan.TicksPerSecond; + string summ = String.Format( + " [{0}] Total: {1:f3} bind: {2:f3}, read: {3:f3} bytes: {4}", + i, t1, t2, t3, temp.bytesRead); + Console.WriteLine(summ); +#if SINGULARITY + DebugStub.Print(summ); +#endif // SINGULARITY + //Console.WriteLine(" bind count ={0}, read count ={1}",temp.bindCount, temp.readCount); + total += temp.bytesRead; + totalFiles += temp.bindCount; + } + } + return total; + } + + /// + /// Main load generation routine + /// manages Global state machine via timers etc. + public void GenerateLoad() + { + totalSize = 0; + double megaBytes; + InitializeGlobalState(); + + //if (testMode) return; + totalSize *= threadNum; + //megaBytes = ( (double) (totalSize) / (double) (1024*1024) ); + +#if SINGULARITY + long startIrqCount; + long startSwitchCount; + long startKernelGcCount; + int startGcCount; + long startGcMillis; + long startGcBytes; + long endGcMillis; + long endGcBytes; + TimeSpan startTime; + TimeSpan endTime; +#else + DateTime startTime; + DateTime endTime; +#endif + + //DateTime globalStartTime = ProcessService.GetUpTime(); + + // Create all the workers + LoadWorker[] workers = new LoadWorker[threadNum]; + Thread[] threads = new Thread[threadNum]; + + for (int i = 0; i < threadNum; i++) { + workerLocalStates[i] = new LocalState(forcedIterations); + workers[i] = new LoadWorker(this, ref workerLocalStates[i],(int) blockSize,i); + } + + // Create the threads + for (int i = 0; i < threadNum; i++) { + LocalState temp = workerLocalStates[i]; + if (temp != null) temp.State = WorkerState.Rampup; + threads[i] = new Thread(new ThreadStart(workers[i].RunLoad)); + } + + if (rampTime != 0) { + // ramp-up time isn't part of benchmark. + + Console.WriteLine("Entering Rampup state"); + // Run all the threads + currentState = WorkerState.Rampup; + for (int i = 0; i < threadNum; i++) { + Thread t = threads[i]; + /*^ assume t!= null; ^*/ + t.Start(); + } + + // sleep for some time and change states from Rampup to Run + Thread.Sleep(rampTime*1000); + Console.WriteLine("\nEntering Run state"); + globalLock.WaitOne(); + + // start perf counting after we have the lock +#if SINGULARITY + GC.PerformanceCounters(out startGcCount, + out startGcMillis, + out startGcBytes); + + startTime = ProcessService.GetUpTime(); + startIrqCount = ProcessService.GetKernelInterruptCount(); + startSwitchCount = ProcessService.GetContextSwitchCount(); + startKernelGcCount = ProcessService.GetKernelGcCount(); +#else + startTime = DateTime.Now; +#endif + } + else { + // ramp-up time is part of benchmark. +#if SINGULARITY + GC.PerformanceCounters(out startGcCount, + out startGcMillis, + out startGcBytes); + + startTime = ProcessService.GetUpTime(); + startIrqCount = ProcessService.GetKernelInterruptCount(); + startSwitchCount = ProcessService.GetContextSwitchCount(); + startKernelGcCount = ProcessService.GetKernelGcCount(); +#else + startTime = DateTime.Now; +#endif + + Console.WriteLine("Starting threads"); + // Run all the threads + currentState = WorkerState.Rampup; + for (int i = 0; i < threadNum; i++) { + Thread t = threads[i]; + /*^ assume t!= null; ^*/ + t.Start(); + } + + // sleep for some time and change states from Rampup to Run + Thread.Sleep(rampTime*1000); + Console.WriteLine("\nEntering Run state"); + globalLock.WaitOne(); + } + + // Workers are ready to run. + currentState = WorkerState.Run; + + for (int i = 0; i < threadNum; i++) { + LocalState temp = workerLocalStates[i]; + if (temp != null) temp.State = WorkerState.Run; + } + globalLock.ReleaseMutex(); + + + // sleep for some time and change states from Run to Done + Thread.Sleep(runTime*1000); + globalLock.WaitOne(); + currentState = WorkerState.Done; + for (int i = 0; i < threadNum; i++) { + LocalState temp = workerLocalStates[i]; + if (temp != null) temp.State = WorkerState.Done; + } + globalLock.ReleaseMutex(); + +#if SINGULARITY + bool wasActive = Monitoring.isActive(); + if (wasActive) Console.WriteLine("May want to reset Monitoring state -- was active"); + Monitoring.setActive(false); + // Wait for all the threads to complete + for (int i = 0 ; i < threadNum; i++) { + Thread t = threads[i]; + /*^ assume t!= null; ^*/ + t.Join(); + } +#endif + + // should stats happen before or after thread join? + long totalFiles; + long totalBytes = GatherStats(out totalFiles); + + megaBytes = ( (double) (totalBytes) / (double) (1024*1024) ); + +#if SINGULARITY + int endGcCount; + endTime = ProcessService.GetUpTime(); + GC.PerformanceCounters(out endGcCount, + out endGcMillis, + out endGcBytes); +#else + endTime = DateTime.Now; +#endif + + + TimeSpan elapsed = endTime - startTime; + double delta = (double)elapsed.Ticks / TimeSpan.TicksPerSecond; + string summ = + String.Format( + "Class:{0:d} Block:{1:d} Elapsed: {2:f2} MBps: {3:f3}, Files/s: {4:f3}", + classSizeNum, + blockSize, + delta, + (double)(megaBytes / delta), + (double)(totalFiles / delta)); + +#if SINGULARITY + string info = + String.Format( + "[AppGC:- cnt:{0} bytes:{1} Kern:- ints:{2} swi:{3} gcs:{4}]", + endGcCount - startGcCount, + endGcBytes - startGcBytes, + ProcessService.GetKernelInterruptCount() - startIrqCount, + ProcessService.GetContextSwitchCount() - startSwitchCount, + ProcessService.GetKernelGcCount() - startKernelGcCount); +#else + string info = "not implemented"; +#endif + if (verbose > 0 ) { + Console.WriteLine(); + Console.WriteLine(summ); + Console.WriteLine(info); + } + + + if (verbose > 1 ) { + long ftotal = 0; + for (int i=0; i < 9; i++) { + ftotal += fileBucket[i]; + } + + Console.WriteLine("Actual Zipf file distribution:"); + for (int i=0; i < 9; i++) { + double foo = (double) (fileBucket[i] * 100) / (double) ftotal; + Console.WriteLine(" FileBucket[{0}] = {1:d6}. %={2:f2}", + i, fileBucket[i], foo); + } + } +#if SINGULARITY + DebugStub.WriteLine(summ); + DebugStub.WriteLine(info); +#endif + } + } // client + + public class SpecMain + { + //-------------------------------------------------- + //-------------------------------------------------- + private static int ConnectionsToDirectories(int conns) + { + return ((int) (25 + (((400000.0 / 122000.0) * conns)/5.0))); + } + + static bool ParseNumber(string/*!*/ arg, + string/*!*/ name, + out long value) + { + // arg should look like "[-][A-z]:[0-9]*" + if (arg.Length >= 4) + { + try + { + value = Int64.Parse(arg.Substring(3)); + return true; + } + catch (FormatException) + {Console.WriteLine("format ex"); } + catch (OverflowException) + {Console.WriteLine("overflow ex");} + } + Console.WriteLine("Could not parse {0}, {1}", name,arg.Substring(3)); + value = 0; + return false; + } + + private static void Usage() + { + Console.WriteLine("Usage: specweb99 client [options] content-root"); + Console.WriteLine(" randomly read files generated by wafgen99"); + Console.WriteLine("Options:"); + Console.WriteLine( + " /b: Block Size to be read [{0}].", + Defaults.WarmUpSeconds + ); + Console.WriteLine( + " /c: Set number of connections to simulate [{0}].", + Defaults.Connections + ); + Console.WriteLine(" /k: Restrict files to this class number."); + Console.WriteLine(" /f: Forced iterations [0]."); + Console.WriteLine(" /r: run time in seconds [{0}].", + Defaults.RunSeconds); + Console.WriteLine(" /t: Number of threads to use [1]."); + Console.WriteLine(" /x no read -- just bind"); + Console.WriteLine(" /w: warmup time in seconds[5.]"); + } + +#if SINGULARITY + internal static int AppMain(Parameters! config) + { + + long dirCount = (long) (ConnectionsToDirectories((int)config.connections) -1 ); //zero based + long blockSize = config.blockSize; + long fileSizeNum = -1; + long classSizeNum = config.classSizeNum; + long verbose = config.verbose; + long numThreads = config.numThreads; + bool testMode = config.testMode; + long runTime = config.runTime; + long rampTime = config.rampTime; + long forcedIterations = config.forcedIterations; + string contentPrefix = config.contentPrefix + "/" + Defaults.RelativePath; + if (forcedIterations != 0) { + rampTime = 0; + runTime = 0; + } + Console.WriteLine(" args: content=" + contentPrefix +" dir=" + dirCount + " block size="+blockSize); + Console.WriteLine(" verbose="+verbose+" FileSizeNum="+fileSizeNum+" ClassSizeNum="+classSizeNum); + Console.WriteLine(" threads="+numThreads+" forcedIterations="+forcedIterations); + //DateTime start = DateTime.Now; + + Client c = new Client(contentPrefix, dirCount, blockSize, fileSizeNum, + numThreads, verbose, classSizeNum, + testMode, (int) rampTime, (int)runTime, + (int)forcedIterations); + + if (c != null ) { + c.GenerateLoad(); + } + + //TimeSpan elapsed = DateTime.Now - beginRunTime; + //Console.WriteLine("Elapsed time: "+elapsed); + return 0; + + } +#else + //-------------------------------------------------- + // Windows Main routine + //-------------------------------------------------- + public static int Main(string[]/*!*/ args) + { + string contentPrefix = Defaults.Root; + long dirCount = (long) (ConnectionsToDirectories(Defaults.Connections) -1); //zero based + long blockSize = Defaults.Connections; + long fileSizeNum = -1; + long classSizeNum = -1; + long verbose = 1; + long numThreads = 1; + bool testMode = false; + long runTime = Defaults.RunSeconds; + long rampTime = Defaults.WarmUpSeconds; + long forcedIterations = 0; + + // Temporaries for command-line parsing + bool needHelp = args.Length == 0; + + int i; + for (i = 1; i < args.Length; i++) + { + string/*!*/ arg = (string /*!*/) args[i]; + + if (arg.Length < 2 || (arg[0] != '-' && arg[0] != '/') ) + { + Console.WriteLine("Invalid argument: {0}", arg); + Usage(); + return -1; + } + + switch (Char.ToLower(arg[1])) + { + case '?': + case 'h': + needHelp = true; + break; + case 'b': + ParseNumber(arg, "block size", out blockSize); + break; + case 'c': + long connections; + ParseNumber(arg, "# of connections", out connections); + dirCount = (long) (ConnectionsToDirectories((int)connections) -1 ); //zero based + + break; + case 'f': + ParseNumber(arg, "# of forced iterations", out forcedIterations); + rampTime = 0; + runTime = 0; + break; + case 'k': + ParseNumber(arg, "class number (size) to be read", out classSizeNum); + break; + case 'r': + ParseNumber(arg, "Run time", out runTime); + break; + case 't': +#if SINGULARITY + ParseNumber(arg, "number of threads to use", out numThreads); +#else + Console.WriteLine("Multi-thread not spported on NT -- ignoring"); +#endif + break; + case 'v': + ParseNumber(arg, "verbosity level", out verbose); + break; + case 'w': + ParseNumber(arg, "Warmup time", out rampTime); + break; + case 'x': + testMode = true; + break; + default: + contentPrefix = arg; + break; + } + } // for args + + contentPrefix += "/" + Defaults.RelativePath; + + if (needHelp) { + Usage(); + return -1; + } + + Console.WriteLine(" args: content=" + contentPrefix +" dir=" + dirCount + " block size="+blockSize); + Console.WriteLine(" verbose="+verbose+" FileSizeNum="+fileSizeNum+" ClassSizeNum="+classSizeNum); + Console.WriteLine(" threads="+numThreads+" forcedIterations="+forcedIterations); + //DateTime start = DateTime.Now; + + Client c = new Client(contentPrefix, dirCount, blockSize, fileSizeNum, + numThreads, verbose, classSizeNum, + testMode, (int) rampTime, (int)runTime, + (int)forcedIterations); + + if (c != null ) { + c.GenerateLoad(); + } + + //TimeSpan elapsed = DateTime.Now - beginRunTime; + //Console.WriteLine("Elapsed time: "+elapsed); + return 0; + } // main +#endif + } //specmain class +} //namespace diff --git a/base/Applications/Benchmarks/SpecWeb99/webfiles/webfiles.csproj b/base/Applications/Benchmarks/SpecWeb99/webfiles/webfiles.csproj new file mode 100644 index 0000000..409751f --- /dev/null +++ b/base/Applications/Benchmarks/SpecWeb99/webfiles/webfiles.csproj @@ -0,0 +1,35 @@ + + + + + + + Exe + webfiles + true + + + + + + + + + + + + + + + + + + diff --git a/base/Applications/Benchmarks/SpecWeb99/webfiles/xwebfile.init.script b/base/Applications/Benchmarks/SpecWeb99/webfiles/xwebfile.init.script new file mode 100644 index 0000000..8d8b886 --- /dev/null +++ b/base/Applications/Benchmarks/SpecWeb99/webfiles/xwebfile.init.script @@ -0,0 +1,11 @@ +clear +mkfs '/dev/vol0.2' +fsmount '/dev/vol0.2' '/fs' '-n' +wafgen99 '-v' '60' '/fs' +clear +echo '==============================================================================' +echo 'When fsunmount says that the volume has been unmounted, initialization is +echo 'complete. You must manually reset the machine to start the xwebfile benchmark.' +echo '==============================================================================' +echo 'fsunmount:' +fsunmount diff --git a/base/Applications/Benchmarks/SpecWeb99/webfiles/xwebfile.script b/base/Applications/Benchmarks/SpecWeb99/webfiles/xwebfile.script new file mode 100644 index 0000000..c40fee9 --- /dev/null +++ b/base/Applications/Benchmarks/SpecWeb99/webfiles/xwebfile.script @@ -0,0 +1,5 @@ +clear +fsmount '/dev/vol0.2' '/fs' +perfcnt '-g' +webfiles '-f:50000' +perfcnt '-s' diff --git a/base/Applications/Benchmarks/bartok/Bartok.cs b/base/Applications/Benchmarks/bartok/Bartok.cs new file mode 100644 index 0000000..138bfff --- /dev/null +++ b/base/Applications/Benchmarks/bartok/Bartok.cs @@ -0,0 +1,1557 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// + +#define NONONNULLTYPECHECK // required on Singularity, no affect on other Windows. + +namespace Bartok { + + using System; + using System.IO; + using System.Text; + using System.Collections; + using Bartok.Utility; + using Bartok.Datatype; + using Bartok.CfgUtil; + using Bartok.Ir; + using Bartok.Lir; + using Bartok.Analysis; + using Bartok.Opt.IrCleanup; + using Bartok.Opt.Ir; + using Bartok.Opt.Lir; + using Bartok.Opt; + using Bartok.Regalloc; + using Bartok.Opt.Ssa; + using Bartok.Backend; + +#if ON_SINGULARITY + using Microsoft.Singularity; +#endif + + // + // Bartok.cs + // + // Main entry point for compiler + + // "public class Bartok {..}" breaks the namespace lookup of Bartok.* + // Is this a bug? + public class BartokClass { + + public static long CHECK_COUNT = 0; + public static long CHECK_COUNT_LOWER = 0; + + public static int Main(String[] args) { +#if ON_SINGULARITY + // AppRuntime.EnableGCVerify = true; + // DebugStub.WriteLine("Bartok: Enabled GC Verifier"); +#endif + Bartok.MSIL.MetaDataUtil.Configure(new MetaDataOutput()); + + try { + ProcessCmdLine(args); + if((fileNames.Count == 0) && (linkNames.Count == 0)) { + CHECK_COUNT++; + CHECK_COUNT_LOWER++; + + PrintUsage(); + Util.Error("\nno files to process...aborting."); + Util.Exit(-11); + } + + if(StageControl.AtomicSupport) { + StageControl.TryAllSupport = true; + } + + Util.Message(NoiseLevel.PerPhase, + "fileNames = " + + new CollectionFormatter(fileNames)); + Util.Message(NoiseLevel.PerPhase, + "refFileNames = " + + new CollectionFormatter(refFileNames)); + Util.Message(NoiseLevel.PerPhase, + "libDirNames = " + + new CollectionFormatter(libDirNames)); + Util.Message(NoiseLevel.PerPhase, + "outputDirName = " + outputDirName); + + if (overrideNames.Count > 0) { + Util.Message(NoiseLevel.PerPhase, + "overrideNames = " + + new CollectionFormatter(overrideNames)); + } + if (entryPoints.Count > 0) { + Util.Message(NoiseLevel.PerPhase, + "entryPoints = " + + new CollectionFormatter(entryPoints)); + } + + // Create helper data structures + DateTime startTime = Util.startTime; + bool fLoadDebugInfo = StageControl.SymbolicDebug; + StageControl.BartokLinkPhase = false; + if (StageControl.CompileOnly) { + // separate compilation + foreach (String fileName in fileNames) { + String outputName = + ComputeOutputName(fileName, outputDirName); + ArrayList loadFileNames = new ArrayList(1); + loadFileNames.Add(fileName); + String shortName = GetShortName(fileName).ToLower(); + + // we need to compile mscorlib.dll together with + // system.dll + bool fDefineOverride = shortName.Equals("mscorlib.dll"); + + TypeData typeData = new TypeData(); + CompileFile(typeData, loadFileNames, refFileNames, + overrideNames, overrideDefNames, + fDefineOverride, outputName, + startTime, fLoadDebugInfo); + } + } else { + // Create output root name. + if (outputRootName == null) { + outputRootName = (String) fileNames[0]; + } + + // strip off extension, if there is one. + int dotIndex = outputRootName.LastIndexOf('.'); + if (dotIndex != -1) { + String ext = outputRootName.Substring(dotIndex + 1); + if (ext.Equals("dll") || ext.Equals("obj") + || ext.Equals("exe")) { + outputRootName = + outputRootName.Substring(0, dotIndex); + } + } + + bool fDefineOverride = StageControl.WholeProgram; + TypeData typeData = new TypeData(); + String objFileName = + CompileFile(typeData, fileNames, refFileNames, + overrideNames, overrideDefNames, fDefineOverride, + outputRootName, startTime, fLoadDebugInfo); + linkNames.Add(objFileName); + + StageControl.BartokLinkPhase = true; +#if DO_LINK + BartokLinker bartokLinker = new BartokLinker(); + typeData = StageControl.WholeProgram ? typeData : null; + bartokLinker.Link(typeData, fileNames, linkNames, + refFileNames, overrideNames, overrideDefNames, + libDirNames, + entryPoints, initializerSkips, + outputRootName); +#endif + } + } catch(AbortException) { + // Abort code already dumped the stack + Util.Exit(-1); + } catch(Exception e) { + Util.Error("Internal uncaught {0} exception", e); + Util.Exit(-1); + } + Util.Message(NoiseLevel.PerPhase, + "STATIC COUNT IS: " + CHECK_COUNT); + Util.Message(NoiseLevel.PerPhase, + "STATIC LOWER IS: " + CHECK_COUNT_LOWER); + return 0; + } + + private static String CompileFile(TypeData typeData, + ArrayList fileNames, + ArrayList refFileNames, + ArrayList overrideNames, + ArrayList overrideDefNames, + bool fDefineOverride, + String outputName, + DateTime startTime, + bool fLoadDebugInfo) { + ConvertMsil2Ir(fileNames, refFileNames, overrideNames, + overrideDefNames, fDefineOverride, startTime, + fLoadDebugInfo, typeData); + + CHECK_COUNT++; + CHECK_COUNT_LOWER++; + + +#if SELF_PROFILING + System.GC.Collect(); + long memoryUsage = System.GC.GetTotalMemory(false); + Util.Message("memory usage: " + memoryUsage); +#endif + + if (entryPoints.Count > 0) { + Util.Message(NoiseLevel.PerPhase, + "entryPoints = " + + new CollectionFormatter(entryPoints)); + } + if(!StageControl.CompileOnly && (entryPoints.Count == 0)) { + Util.Abort("No entry points found"); + } + + typeData.ComputeEntryMethod(entryPoints); + Util.Assert(typeData.EntryPoints.Count == entryPoints.Count); + + // register all global analysis + AnalysisRegistry analysisRegistry = RegisterAnalysis(typeData); + + // Create a series of phases that are each applied to the + // whole program. + Bartok.Ir.PhaseList phases = new Bartok.Ir.PhaseList("ir"); + + CHECK_COUNT--; + CHECK_COUNT_LOWER--; + + AddPhases(phases, analysisRegistry, outputName, typeData); + + Util.Message(phases.ComponentPhases.ToString()); + if (StageControl.DumpContainers) { + phases.Add(new TypeDataPrettyPhase("After IR:")); + } + Bartok.Opt.IrCleanup.Statistics.Reset(typeData); + BartokList phaseNames = phases.ComponentPhases; + foreach(Object phaseObj in phaseNames) { + if(!(phaseObj is string)) { + Util.Warn("Not string: {0}X", + phaseObj.ToString()); + continue; + } + string phaseName = (string)phaseObj; + if(phaseName.IndexOf(' ') != -1) { + Util.Warn("Phase has a space in name: {0}", phaseName); + } + } + foreach(string phaseName in StageControl.disabledPhaseNames) { + if(phaseNames.Contains(phaseName)) { + continue; + } + if(StageControl.disabledPhaseNamesFound.Contains(phaseName)) { + continue; + } + Util.Abort("Couldn't find phase: " + phaseName); + } + phases.Go(typeData); + + Bartok.Opt.IrCleanup.Statistics.Summary(); + +#if SELF_PROFILING + memoryUsage = System.GC.GetTotalMemory(false); + Util.Message("memory usage: " + memoryUsage); +#endif + + // backend phases: + Util.Message("outputRootName = " + outputName); + + String objFileName = LirPhases.run(typeData, fileNames, outputName, + StageControl.GenObjFile); + System.GC.Collect(); + Util.Message("End of Bartok: " + GC.GetTotalMemory(false)); + return objFileName; + } + + private static void ConvertMsil2Ir(ArrayList fileNames, + ArrayList refFileNames, + ArrayList overrideNames, + ArrayList overrideDefNames, + bool fDefineOverride, + DateTime startTime, + bool fLoadDebugInfo, + TypeData typeData) { + // Remove redundant fileNames + // Remove refFileNames that are redundant with fileNames + for(int i=0; i= NoiseLevel.PerPhase; + + Bartok.MSIL.MetaDataResolver libResolver = + new Bartok.MSIL.MetaDataResolver(refFileNames, libDirNames, + startTime, fLoadDebugInfo, + fMsilMessages); + Bartok.MSIL.MetaDataResolver overrideResolver; + if (fDefineOverride) { + // load code + overrideResolver = + new Bartok.MSIL.MetaDataResolver(overrideNames, + startTime, + fLoadDebugInfo, + fTranslateTryAll, + fTranslateAtomic, + fMsilMessages); + } else { + // don't load code + overrideResolver = + new Bartok.MSIL.MetaDataResolver(overrideNames, + libDirNames, + startTime, fLoadDebugInfo, + fMsilMessages); + } + Bartok.MSIL.MetaDataResolver overrideDefResolver = + new Bartok.MSIL.MetaDataResolver(overrideDefNames, startTime, + fLoadDebugInfo, + fTranslateTryAll, + fTranslateAtomic, + fMsilMessages); + Bartok.MSIL.MetaDataResolver loadResolver = + new Bartok.MSIL.MetaDataResolver(fileNames, startTime, + fLoadDebugInfo, + fTranslateTryAll, + fTranslateAtomic, + fMsilMessages); + Bartok.MSIL.MetaDataResolver[] resolvers = + new Bartok.MSIL.MetaDataResolver[] { + libResolver, overrideResolver, overrideDefResolver, + loadResolver + }; + Bartok.MSIL.MetaDataResolver.ResolveCustomAttributes(resolvers); + MetaDataParser parser = + new MetaDataParser(entryPoints.Count == 0 ? entryPoints : null); + Util.TimestampMessage(NoiseLevel.PerPhase, + "translating from MSIL"); + parser.Parse(loadResolver, overrideResolver, + overrideDefResolver, libResolver, + typeData, fDefineOverride, false); + + Util.TimestampMessage(NoiseLevel.PerPhase, + "finished translating"); + } + + private static AnalysisRegistry RegisterAnalysis(TypeData typeData) { + AnalysisRegistry analysisRegistry = new AnalysisRegistry(typeData); + analysisRegistry.RegisterAnalysis(VirtualCallAnalysis.makeFactory()); + return analysisRegistry; + } + + private static void AddPhases(Bartok.Ir.PhaseList phases, + AnalysisRegistry analysisRegistry, + String outputName, + TypeData typeData) { + if (StageControl.PrintContainers) { + phases.Add(new TypeDataPrintPhase("After parse:")); + } + if (StageControl.DumpContainers) { + phases.Add(new TypeDataPrettyPhase("After parse:")); + } + if (StageControl.SingSharpTemplateRemover) { + phases.Add(new SingSharpTemplateRemover()); + } + if (StageControl.RuntimeMods) { + phases.Add(new RuntimeMods()); + } + if (StageControl.IrMultiPropSimple) { + phases.Add(new IrMultiPropSimple("System.GC")); + } + if (StageControl.IrDeadAssignmentSimple1) { + phases.Add(new IrDeadAssignmentSimplePhase("System.GC")); + } + if (StageControl.IrTreeShake) { + phases.Add(new IrTreeShake(typeData.EntryPoints, + dynamicLoads, + StageControl.WholeProgram, + analysisRegistry)); + } + + /* + phases.Add + (new DynamicCount + ("VirtualCallsStart", + new DynamicCount.OpcodeFilter + (Operator.OpCodes.CallVirtual, + Operator.OpCodes.InterfaceCall), + DynamicCount.Granularity.PerSite)); + */ + + /* + phases.Add + (new DynamicCount + ("ASCstart", + new DynamicCount.OpcodeFilter + (Operator.OpCodes.CheckArrayStore, + Operator.OpCodes.CheckVectorStore), + DynamicCount.Granularity.PerSite)); + */ + + if (StageControl.PtrAnalysis) { + phases.Add(PtrTypeSimpleSystem.CreateAnalysis()); + phases.Add(PtrTypeHierarchySystem.CreateAnalysis()); + phases.Add(PtrTypeSetSystem.CreateAnalysis()); + } + + // create wrapper that insert calls to leaveGCSafeState and + // enterGCSafeState. + phases.Add(new CreateEntryPointWrapper()); + + // trap ValueType.Equals and override it by compiler generated + // routines. + if (StageControl.IrOverrideValueTypeEquals) { + phases.Add(new Convert.ValueTypeEquals()); + } + + if (StageControl.LimitedReflection) { + phases.Add(new Convert.OverrideVTableInit()); + } + + if (StageControl.IrConvertSizeofPrimitive) { + Convert.ToMir.Mask mask = Convert.ToMir.Mask.SizeofPrimitive; + phases.Add(new Convert.ToMir(mask)); + } + + /* SPOONS: region related phases: + // A temporary pass that cleans up the scratch objects so that the + // DemandAnalysis is not confused by the randomness that the tree + // shaker leaves behind. + phases.Add(new CleanScratch()); + + // Build a "Foo_layout" for each class "Foo"; other setup required + // by DemandAnalysis. + phases.Add(new LayoutBuilder()); + + // Perform first- and last-use analysis; add explicit region + // variables and effects. + phases.Add(new DemandAnalysis()); + + // Print the code + phases.Add(new TypeDataPrettyPhase("After Demand:")); + */ + + // Perform first- and last-use analaysis; add explicit region + // variables and effects. + + // must happen after DemandAnalysis, but before any inlining / + // rearranging basic blocks or calls. +#if !VC + if(StageControl.TryAllSupport) { + phases.Add(new Bartok.Convert.PropagateLogging(analysisRegistry)); + phases.Add(new TypeDataDummyPhase()); + } +#endif + + if (StageControl.IrScanCallEffects) { + phases.Add(new IrScanCallEffects()); + } + + if(StageControl.DumpInheritance) { + phases.Add(new DumpInheritancePhase(StageControl.DumpInheritanceFile)); + } + +#if PHX_TODO + phases.Add(new TypeDataToPhoenix()); +#endif + phases.Add(new TypeInit(initializerSkips)); + + if (StageControl.InstrumentCalls) { + phases.Add(new InstrumentCalls()); + } + + if (StageControl.IrStoreChecks) { + phases.Add(new IrStoreCheckElim()); + } + if (StageControl.BuildC2Mods + && StageControl.UnmanagedStrings) { + phases.Add(new IrUnmanagedStrings()); + } + phases.Add(IrCleanup.Create()); + if (StageControl.BuildC2Mods + && StageControl.IdentifyAsMethods) { + phases.Add(new IrIdentifyAsMethods()); + } + + if (StageControl.WholeProgram + && StageControl.IrDeadAssignmentSimpleFormals + && StageControl.IrTreeShake) { + phases.Add(new IrDeadAssignmentSimpleFormalsPhase()); + phases.Add(new IrTreeShake(typeData.EntryPoints, + dynamicLoads, + StageControl.WholeProgram, + analysisRegistry)); + } + + phases.Add(new Convert.IrInsertDelegate()); + + IrFieldAnalysis fieldAnalysis = null; + if (StageControl.GCType == + StageControl.ReferenceCountingCollector && + StageControl.RCCollectorOptRCSubsumed && + StageControl.RCCollectorOptRCSubsumedByROFields) { + IrFieldAnalysis.FieldFilter filter = + new IrFieldAnalysis.RCAproposFieldFilter(); + fieldAnalysis = new IrFieldAnalysis(true, filter); + phases.Add(fieldAnalysis); + } + + if(StageControl.IrInlineConstructor) { + phases.Add(new Convert.ToMir(Convert.ToMir.Mask.Constructor)); + } + // When only one class implements an interface, replace the interface + // with the class. + if (StageControl.IrInterfaceElim && StageControl.WholeProgram) { + phases.Add(new InterfaceElim()); + } + + if (StageControl.IrSimpleInliner) { + phases.Add(new IrSimpleInliner(new IrInline(), false, false, false)); + } else if (StageControl.IrAttributeInliner) { + // inline methods that has [inline] attributes. + phases.Add(new IrSimpleInliner(new IrInline(), false, false)); + } + + if (StageControl.FailAfterInliner) { + phases.Add(new FailPhase()); + } + + if (StageControl.IrMultiPropSimple) { + phases.Add(new IrMultiPropSimple()); + } + if (StageControl.IrSuppressExnEdges) { + phases.Add(new IrSuppressExnEdges()); + } + if (StageControl.IrLoadStoreOpt) { + phases.Add(new IrLoadStoreOpt(analysisRegistry)); + } + if (StageControl.DevirtualizeCall) { + phases.Add(new IrDevirtualizeCall(analysisRegistry)); + } + + if (StageControl.IrSimpleInliner && + StageControl.IrInlinerDoIncreaseSize) { + phases.Add(new IrSimpleInliner(new IrInline(), true, false, false)); + } + + if (StageControl.LazyTypeInits) { + phases.Add(new TypeInit(initializerSkips, true)); + } + + // Eliminate unnecessary instanceOf/check casts. Only makes + // 2 passes by punting back edges. + if (StageControl.IrTypeTestElimPunt) { + phases.Add(new TypeTestElimPunt()); + } + + // Eliminate unnecessary instanceOf/check casts - full iterative + // analysis. More expensive than the above analysis, but yields + // little improvement in practice. + if (StageControl.IrTypeTestElim) { + phases.Add(new TypeTestElim()); + } + + // Deletes all CheckCasts and instanceOf IDisposable for sake of + // experimentation. Normally not enabled, as it is unsafe. + + if (StageControl.IrDeleteCheckCasts) { + phases.Add(new DeleteCheckCast()); + } + + if (StageControl.IrConvertOpt) { + phases.Add(new IrConvertOpt()); + phases.Add(new IrDeadAssignmentSimplePhase()); + phases.Add(new IrReverseCopyProp()); + } + + // Just do thread analysis once. + IrLockedFields locks = null; + if (StageControl.ExtendThreadFieldsABCD || + StageControl.SsaNullCheckGlobalThreaded) { + + if (StageControl.IrTreeShake) { + phases.Add(new IrTreeShake(typeData.EntryPoints, + dynamicLoads, + StageControl.WholeProgram, + analysisRegistry)); + } + + if(StageControl.OptimisticLocking) { + locks = new ClassIrLockedFields(analysisRegistry); + } else { + locks = new IrLockedFields(analysisRegistry); + } + phases.Add(locks); + } + + // Array bounds check elimination + if (StageControl.ABCD) { + phases.Add(new ABCD(analysisRegistry, locks)); + } + + if (StageControl.IrConvertArrayBounds) { + Convert.ToMir.Mask mask = Convert.ToMir.Mask.CheckVectorBounds; + phases.Add(new Convert.ToMir(mask)); + } + + if (StageControl.IrConvertInferface) { + Convert.ToMir.Mask mask = Convert.ToMir.Mask.InterfaceCall; + phases.Add(new Convert.ToMir(mask)); + } + + if (StageControl.IrConvertSimpleArrayAccess) { + Convert.ToMir.Mask mask = Convert.ToMir.Mask.SimpleArrayAccess; + phases.Add(new Convert.ToMir(mask)); + } + + if (StageControl.IrCloneLoopHeader) { + phases.Add(new IrCloneLoopHeader()); + phases.Add(new IrJumpElim()); + phases.Add(new IrMultiPropSimple()); + } + + if (StageControl.SsaOpts) { + if (StageControl.SsaNullCheckGlobalThreaded) { + phases.Add(SSAPhase.Create(analysisRegistry, locks)); + } else { + phases.Add(SSAPhase.Create()); + } + } + + if(locks != null) { + locks = null; + } + + // IrInsertStructCopy phase insert a StructCopy() method + // to each struct type, and lower struct Id operators + // to a call to StructCopy() method. + phases.Add(new Convert.IrInsertStructCopy()); + +#if !VC + if(StageControl.TryAllSupport) { + phases.Add(new IrInsertLogging()); + } + + if(StageControl.TryAllSupport && + StageControl.AtomicSupportUpdateEnlistOptFlow) { + // without the IrLoadStoreOpt here, EnlistIndirects + // generated by [Store]StructFields can't be moved. + phases.Add(new IrLoadStoreOpt(analysisRegistry)); + phases.Add(new IrInsertUpdateEnlistments()); + // otherwise CSE misses things that it should be eliminating + phases.Add(new IrMultiPropSimple()); + } + + if (StageControl.TryAllSupport && + StageControl.IrKeepManager) { + phases.Add(new IrKeepManager(analysisRegistry)); + } +#endif + + if(StageControl.IrStructVectorOperations) { + phases.Add(new IrStruct(true)); + } + + if (StageControl.IrLoadStoreOpt) { + phases.Add(new IrLoadStoreOpt(analysisRegistry)); + } + +#if !VC + if (StageControl.TryAllSupport && + StageControl.AtomicSupportUpdateEnlistOpt) { + phases.Add(new IrSimpleAvoidUpgrade()); + } +#endif + + if (StageControl.IrConvertComplexArrayAccess) { + Convert.ToMir.Mask mask = Convert.ToMir.Mask.ComplexArrayAccess; + phases.Add(new Convert.ToMir(mask)); + } + + if (StageControl.IrConvertExpandedArrayAccess) { + Convert.ToMir.Mask mask = Convert.ToMir.Mask.ExpandedArrayAccess; + phases.Add(new Convert.ToMir(mask)); + } + + if (StageControl.ArraySupportOptimizePass && StageControl.SsaOpts) { + phases.Add(SSAPhase.Create()); + } + +#if !VC + if (StageControl.TryAllSupport && + StageControl.TryAllSupportOptimizePass && + StageControl.SsaOpts) { + phases.Add(SSAPhase.Create()); + } +#endif + + if (StageControl.IrInitStaticField) { + phases.Add(new IrInitStaticField()); + } + + if (StageControl.LazyTypeInits + && StageControl.TypeInitRemoveEmptyCctors) { + phases.Add(new TypeInit(initializerSkips, true)); + } + + if (StageControl.GCType == + StageControl.ReferenceCountingCollector) { + phases.Add(new IrStructRCUpdate()); + } + + if (StageControl.GCType == + StageControl.DeferredReferenceCountingCollector) { + phases.Add(new IrStructDRCUpdate()); + } + + if (StageControl.IrTreeShake && StageControl.IrTreeShakeLate) { + phases.Add(new IrTreeShake(typeData.EntryPoints, + dynamicLoads, + StageControl.WholeProgram, + analysisRegistry)); + } + + if (StageControl.TypedReference) { + phases.Add(new Convert.ToMir(Convert.ToMir.Mask.Vararg1)); + + // All of vararg1 must finish before vararg2, so we wrap vararg2 + // in a typedata phase to enforce that. + phases.Add(new TypeDataMethodPhase + (new Convert.ToMir(Convert.ToMir.Mask.Vararg2))); + } + + /* + // We do not know where all of the calls will be because lowering can + // introduce calls. We make a best guess here. If we moved all + // call-generating lowering to HIR (via ToMir or equivalent), then + // this could be easily done. We are currently missing calls for the + // following: + // - pinvoke, stubs, etc + // - some arithmetic conversions + // - casts - can't add because not all are calls + // - RC, tryall, atomic + // - others? + phases.Add + (new DynamicCount + ("Calls", + new DynamicCount.OpcodeFilter + (Operator.OpCodes.Call, + Operator.OpCodes.CallIndirect, + Operator.OpCodes.CallVirtual, + Operator.OpCodes.InterfaceCall, + Operator.OpCodes.MonitorEnter, + Operator.OpCodes.MonitorExit, + Operator.OpCodes.IndirectToData, + Operator.OpCodes.CustomGetSize, + Operator.OpCodes.CheckVectorStore, + Operator.OpCodes.CheckVectorElementAddress, + Operator.OpCodes.InitVector, + Operator.OpCodes.CheckArrayStore, + Operator.OpCodes.CheckArrayElementAddress, + Operator.OpCodes.InitArray, + Operator.OpCodes.InitType, + Operator.OpCodes.GetITable, + Operator.OpCodes.NewObject, + Operator.OpCodes.NewVector, + Operator.OpCodes.NewArray), + DynamicCount.Granularity.Global)); + phases.Add(new TypeDataDummyPhase()); + phases.Add + (new DynamicCount + ("VirtualCallsEnd", + new DynamicCount.OpcodeFilter + (Operator.OpCodes.CallVirtual, + Operator.OpCodes.InterfaceCall), + DynamicCount.Granularity.PerSite)); + + phases.Add + (new DynamicCount + ("ASCend", + new DynamicCount.OpcodeFilter + (Operator.OpCodes.CheckArrayStore, + Operator.OpCodes.CheckVectorStore), + DynamicCount.Granularity.PerSite)); + phases.Add(new TypeDataDummyPhase()); + + phases.Add + (new DynamicCount + ("WB", + new DynamicCount.OpcodeFilter + (Operator.OpCodes.LocWriteBarrier), + DynamicCount.Granularity.Global)); + phases.Add(new TypeDataDummyPhase()); + */ + + if (StageControl.WholeProgram && StageControl.OptRuntimeData) { + phases.Add(new RuntimeData()); + } + + if (StageControl.IrConvertArrayOpt) { + phases.Add(new IrConvertArrayOpt()); + } + + // insert write barrier after chooserep so we know the size of + // of objects. This is needed because we try to remove write + // barrier when we store to the young generation, however, + // big objects are in the old generation even though it is + // newly created. Therefore, we need to know object size to + // know if it is a big object. + if (StageControl.InsertWriteBarrier) { + phases.Add(new IrWriteBarrier()); + phases.Add(new Convert.ToMir + (Convert.ToMir.Mask.ConvertWriteBarrier)); + } + + // convert type tests and sizeof effect to Mir + Convert.ToMir.Mask typeMask = Convert.ToMir.Mask.CheckCast + | Convert.ToMir.Mask.Sizeof; + if (!(StageControl.GCType == + StageControl.ReferenceCountingCollector || + StageControl.GCType == + StageControl.DeferredReferenceCountingCollector)) { + typeMask |= Convert.ToMir.Mask.GetCurrentThread; + } + if (StageControl.TypedReference) { + typeMask |= Convert.ToMir.Mask.TypedRef; + } + phases.Add(new Convert.ToMir(typeMask)); + + if (StageControl.IrSimpleInliner) { + phases.Add(new IrSimpleInliner(new IrInline(), false, true, + true, 0, 0, 0)); + } + + if(StageControl.TypeInitElim) { + phases.Add(new IrTypeInitElim(analysisRegistry)); + } + + if (StageControl.IrRemoveDoubleCmp) { + phases.Add(new IrCmpElim()); + } + + if (StageControl.IrArrayBaseLength) { + phases.Add(new IrArrayBaseLength()); + phases.Add(new IrDeadAssignmentSimplePhase()); + } + + if (StageControl.IrInitTypeInliner && + StageControl.LazyTypeInits) { + phases.Add(new IrInitTypeInliner(typeData, new IrInline())); + } + + if (StageControl.GCType == + StageControl.ReferenceCountingCollector) { + if (StageControl.RCCollectorShowStatistics) { + String message = "Before RC Update Injection"; + phases.Add(new IrBBStats(message)); + } + + phases.Add(new IrRCUpdate()); + + if (StageControl.RCCollectorShowStatistics) { + String message = "After RC Update Injection"; + phases.Add(new IrBBStats(message)); + } + if (StageControl.RCCollectorOptImmortals) { + phases.Add(new IrImmortalObjectRCUpdates()); + } + if (StageControl.RCCollectorOptRCSubsumed) { + IrSimpleThreadEscape threadLocalObjects = null; + if (StageControl.RCCollectorOptThreadLocalAnalysis) { + IrLockedFields threadSafeFields = null; + if (StageControl.WholeProgram && + StageControl. + RCCollectorOptRCSubsumedByTSFields) { + threadSafeFields = + new IrLockedFields(analysisRegistry); + phases.Add(threadSafeFields); + } + threadLocalObjects = + new IrSimpleThreadEscape(analysisRegistry, + threadSafeFields); + phases.Add(threadLocalObjects); + } + IrRCSubsumedRCUpdates rcSubsumption = + new IrRCSubsumedRCUpdates(analysisRegistry, + fieldAnalysis, + threadLocalObjects); + phases.Add(rcSubsumption); + } + if (StageControl.RCCollectorOptCoalescingUpdates) { + phases.Add(new IrBBLocalCoalesceRCUpdates()); + } + if (StageControl. + RCCollectorOptStaticAcyclicRefTypeUpdates) { + phases.Add(new IrAcyclicRefTypeRCUpdates()); + } + if (StageControl.RCCollectorOptNonNullRCUpdates) { + phases.Add(SSAPhase.NullCheckAnalysis()); + } + if (StageControl.RCCollectorShowStatistics) { + String message = "After RC Optimizations"; + phases.Add(new IrBBStats(message)); + } + + Convert.ToMir.Mask mask = Convert.ToMir.Mask.RCUpdate | + Convert.ToMir.Mask.GetCurrentThread; + phases.Add(new Convert.ToMir(mask)); + if (StageControl.RCCollectorOptInlineRCUpdates && + StageControl.IrSimpleInliner) { + phases.Add(new IrSimpleInliner(new IrInline(), + true, + false, + true)); + } + phases.Add(new TypeDataDummyPhase()); + } + + if (StageControl.GCType == + StageControl.DeferredReferenceCountingCollector) { + if (StageControl.RCCollectorShowStatistics) { + String message = "Before DRC Update Injection"; + phases.Add(new IrBBStats(message)); + } + + phases.Add(new IrDRCUpdate()); + + if (StageControl.RCCollectorShowStatistics) { + String message = "After DRC Update Injection"; + phases.Add(new IrBBStats(message)); + } + if (StageControl.RCCollectorOptImmortals) { + phases.Add(new IrImmortalObjectRCUpdates()); + } + if (StageControl.RCCollectorOptCoalescingUpdates) { + phases.Add(new IrBBLocalCoalesceRCUpdates()); + } + if (StageControl. + RCCollectorOptStaticAcyclicRefTypeUpdates) { + phases.Add(new IrAcyclicRefTypeRCUpdates()); + } + if (StageControl.RCCollectorOptNonNullRCUpdates) { + phases.Add(SSAPhase.NullCheckAnalysis()); + } + if (StageControl.RCCollectorShowStatistics) { + String message = "After DRC Optimizations"; + phases.Add(new IrBBStats(message)); + } + + Convert.ToMir.Mask mask = Convert.ToMir.Mask.RCUpdate | + Convert.ToMir.Mask.GetCurrentThread; + phases.Add(new Convert.ToMir(mask)); + if (StageControl.RCCollectorOptInlineRCUpdates && + StageControl.IrSimpleInliner) { + phases.Add(new IrSimpleInliner(new IrInline(), + true, + false, + true)); + } + phases.Add(new TypeDataDummyPhase()); + } + + +#if !VC + if(StageControl.TryAllSupport && + StageControl.TryAllDecomposeOpt) { + phases.Add(new IrDecomposeTransMemChecks(analysisRegistry)); + // IrDecomposeTransMemChecks emits GetCurrentThread ops + phases.Add(new IrLoadStoreOpt(analysisRegistry)); + Convert.ToMir.Mask mask = Convert.ToMir.Mask.GetCurrentThread; + phases.Add(new Convert.ToMir(mask)); + } + + if (StageControl.TryAllSupport && + StageControl.IrConvertTryAll) { + Convert.ToMir.Mask mask = Convert.ToMir.Mask.TryAll; + phases.Add(new Convert.ToMir(mask)); + if (StageControl.IrSimpleInliner) { + phases.Add(new IrSimpleInliner(new IrInline(), + true, + false)); + } + } +#endif + + // The inliners may inline some of the methods that handle special + // MSIL opcodes, adding in instructions like Id that we + // don't expect to see this late in the lowering. Add one more + // scan of the code to remove them. + phases.Add(new Convert.IrInsertStructCopy()); + + if (StageControl.IrTreeShake && StageControl.IrTreeShakeLate) { + phases.Add(new IrTreeShake(typeData.EntryPoints, + dynamicLoads, + StageControl.WholeProgram, + analysisRegistry)); + } + + if (StageControl.PtrAnalysis) { + phases.Add(PtrTypeSimpleSystem.CreateAnalysis()); + phases.Add(PtrTypeHierarchySystem.CreateAnalysis()); + phases.Add(PtrTypeSetSystem.CreateAnalysis()); + } + + if (StageControl.PrintContainers) { + phases.Add(new TypeDataPrintPhase("end of HIR:")); + } + } + + public static ArrayList fileNames; + public static ArrayList refFileNames; + public static ArrayList libDirNames; + private static ArrayList outputDirNames; + public static String outputDirName; + public static ArrayList overrideNames; + public static ArrayList overrideDefNames; + public static String outputRootName; + public static ArrayList entryPoints; + public static ArrayList linkNames; + private static ArrayList initializerSkips; + private static ArrayList dynamicLoads; + private static bool alreadyPrintedUsage = false; + + private static String StripName(String fileName) { + // strip off extension, if there is one. + int dotIndex = fileName.LastIndexOf('.'); + if (dotIndex != -1) { + String ext = fileName.Substring(dotIndex + 1); + if (ext.Equals("dll") || ext.Equals("obj") + || ext.Equals("exe")) { + fileName = fileName.Substring(0, dotIndex); + } + } + return fileName; + } + + private static String GetShortName(String fileName) { + int charindex = Math.Max(fileName.LastIndexOf('/'), + fileName.LastIndexOf('\\')); + String shortName = (charindex >= 0) + ? fileName.Substring(charindex + 1) + : fileName; + return shortName; + } + + private static String GetDirName(String fileName) { + int charindex = Math.Max(fileName.LastIndexOf('/'), + fileName.LastIndexOf('\\')); + String dirName = (charindex >= 0) + ? fileName.Substring(0, charindex + 1) + : ""; + return dirName; + } + + private static String ComputeOutputName(String inputFileName, + String outputDirName) { + String fileName = Path.GetFileNameWithoutExtension(inputFileName); + String outputName = outputDirName + '\\' + fileName; + return outputName; + } + + private static void ProcessCmdLine(String[] args) { + fileNames = new ArrayList(); + refFileNames = new ArrayList(); + libDirNames = new ArrayList(); + overrideNames = new ArrayList(); + overrideDefNames = new ArrayList(); + outputDirNames = new ArrayList(); + entryPoints = new ArrayList(); + initializerSkips = new ArrayList(); + linkNames = new ArrayList(); + dynamicLoads = new ArrayList(); + int index = 0; +#if ON_SINGULARITY + index = 1; +#endif + while (index < args.Length) { + String argument = args[index]; + if ((argument[0] == '-') || (argument[0] == '/')) { + String option = argument.Substring(1); + ProcessOption(argument, option, args, ref index); + } else { + index++; + fileNames.Add(argument); + } + } + switch (outputDirNames.Count) { + case 0: { + outputDirName = ".\\debug"; + break; + } + case 1: { + outputDirName = (String)outputDirNames[0]; + break; + } + default: { + Util.Error("Error: specified multiple output directories {0}", + new CollectionFormatter(outputDirNames)); + break; + } + } + + if((StageControl.GCType == StageControl.ReferenceCountingCollector) + && StageControl.StructInheritance) { + Util.Abort("Error: RC Collector code has not been updated to " + + "handle struct inheritance"); + } + if((StageControl.GCType == + StageControl.DeferredReferenceCountingCollector) + && StageControl.StructInheritance) { + Util.Abort("Error: Deferred RC Collector code has not been updated to " + + "handle struct inheritance"); + } + } + + private static void ProcessOption(String argument, String option, + String[] args, ref int index) { + String loweredOption = option.ToLower(); + String optionValue; + + if (IsOption(args, option, loweredOption, "entry:", + ref index, out optionValue)) { + AddSemicolonDelimitedNames(entryPoints, optionValue); + } else if (IsOption(args, option, loweredOption, "reference:", + ref index, out optionValue) + || IsOption(args, option, loweredOption, "r:", + ref index, out optionValue)) { + AddSemicolonDelimitedNames(refFileNames, optionValue); + } else if (IsOption(args, option, loweredOption, "bartoklink:", + ref index, out optionValue)) { + AddSemicolonDelimitedNames(linkNames, optionValue); + } else if (IsOption(args, option, loweredOption, "override:", + ref index, out optionValue)) { + AddSemicolonDelimitedNames(overrideNames, optionValue); + } else if (IsOption(args, option, loweredOption, "overridedef:", + ref index, out optionValue)) { + AddSemicolonDelimitedNames(overrideDefNames, optionValue); + } else if (IsOption(args, option, loweredOption, "lib:", + ref index, out optionValue)) { + AddSemicolonDelimitedNames(libDirNames, optionValue); + } else if (IsOption(args, option, loweredOption, "out:", + ref index, out optionValue)) { + outputRootName = optionValue; + } else if (IsOption(args, option, loweredOption, "outdir:", + ref index, out optionValue)) { + AddSemicolonDelimitedNames(outputDirNames, optionValue); + } else if (IsOption(args, option, loweredOption, "skip:", + ref index, out optionValue)) { + AddSemicolonDelimitedNames(initializerSkips, optionValue); + } else if (IsOption(args, option, loweredOption, "substitute:", + ref index, out optionValue)) { + StageControl.substituteString = optionValue; + } else if (IsOption(args, option, loweredOption, "disable:", + ref index, out optionValue)) { + StageControl.disabledPhaseNames.Add(optionValue); + } else if (IsOption(args, option, loweredOption, "dynamicload:", + ref index, out optionValue)) { + AddSemicolonDelimitedNames(dynamicLoads, optionValue); + } else if (IsOption(args, option, loweredOption, "features:", + ref index, out optionValue)) { + StageControl.mixinConditionals = + StageControl.mixinConditionals + "," + optionValue; + } else if (IsOption(args, option, loweredOption, "noisymethod:", + ref index, out optionValue)) { + StageControl.noisyMethodNames.Add(optionValue); + //Util.Message("noisyMethodNames=" + // + StageControl.noisyMethodNames); + } else if (IsOption(args, option, loweredOption, "debugmethod:", + ref index, out optionValue)) { + StageControl.debugMethodNames.Add(optionValue); + StageControl.noisyMethodNames.Add(optionValue); + //Util.Message("debugMethodNames=" + // + StageControl.debugMethodNames); + } else if (IsOption(args, option, loweredOption, "verbosity:", + ref index, out optionValue)) { + Verbosity.FromString(optionValue); + } else if (IsOption(args, option, loweredOption, "marksweepgc", + ref index, out optionValue)) { + StageControl.GCType = StageControl.MarkSweepCollector; + StageControl.GCLargeObjectSize = 2040; + StageControl.InlineSegregatedFreeList = true; + StageControl.InsertWriteBarrier = false; + } else if (IsOption(args, option, loweredOption, "semispacegc", + ref index, out optionValue)) { + StageControl.GCType = StageControl.SemispaceCollector; + StageControl.InsertWriteBarrier = true; + } else if (IsOption(args, option, loweredOption, "slidinggc", + ref index, out optionValue)) { + StageControl.GCType = StageControl.SlidingCollector; + StageControl.InsertWriteBarrier = true; + } else if (IsOption(args, option, loweredOption, "adaptivecopyinggc", + ref index, out optionValue)) { + StageControl.GCType = StageControl.AdaptiveCopyingCollector; + StageControl.InsertWriteBarrier = true; + } else if (IsOption(args, option, loweredOption, + "referencecountinggc", + ref index, out optionValue)) { + StageControl.GCType = StageControl.ReferenceCountingCollector; + StageControl.InsertWriteBarrier = false; + StageControl.GCInlineAllocations = false; + StageControl.mixinConditionals = + StageControl.mixinConditionals + ",ReferenceCountingGC"; + if (StageControl.RCCollectorVerifyRefCounts) { + StageControl.UseVTableBits = true; + StageControl.mixinConditionals = + StageControl.mixinConditionals + + ",ReferenceCountingGCVerification"; + } + } else if (IsOption + (args, option, loweredOption, "deferredreferencecountinggc", + ref index, out optionValue)) { + + StageControl.GCType = StageControl.DeferredReferenceCountingCollector; + StageControl.InsertWriteBarrier = false; + StageControl.GCInlineAllocations = false; + StageControl.mixinConditionals = + StageControl.mixinConditionals + ",DeferredReferenceCountingGC"; + if (StageControl.RCCollectorVerifyRefCounts) { + StageControl.UseVTableBits = true; + StageControl.mixinConditionals = + StageControl.mixinConditionals + + ",DeferredReferenceCountingGCVerification"; + } + } else if (IsOption(args, option, loweredOption, "concurrentmsgc", + ref index, out optionValue)) { + StageControl.GCType = StageControl.ConcurrentMSCollector; + StageControl.GCLargeObjectSize = 2040; + StageControl.Wb = StageControl.WbCMS; + StageControl.GCInlineAllocations = false; + StageControl.InlineSegregatedFreeList = true; + StageControl.PreWriteBarrier = true; + StageControl.InsertWriteBarrier = true; + StageControl.GCInlineWriteBarrier = false; + StageControl.GCWriteBarrierTracksStaticFields = true; + StageControl.mixinConditionals = + StageControl.mixinConditionals + ",ConcurrentMSGC"; + } else if (IsOption(args, option, loweredOption, "nullgc", + ref index, out optionValue)) { + StageControl.GCType = StageControl.NullCollector; + StageControl.InsertWriteBarrier = false; + } else if (IsOption(args, option, loweredOption, "atomicrcgc", + ref index, out optionValue)) { + StageControl.GCType = StageControl.AtomicRCCollector; + StageControl.GCLargeObjectSize = 2040; + StageControl.Wb = StageControl.WbARC; + StageControl.GCInlineAllocations = false; + StageControl.InlineSegregatedFreeList = true; + StageControl.InsertWriteBarrier = true; + StageControl.GCInlineWriteBarrier = false; + StageControl.GCWriteBarrierTracksStaticFields = true; + } else if (IsOption(args, option, loweredOption, "minopt", + ref index, out optionValue)) { + StageControl.SsaOpts = false; + StageControl.IrInterfaceElim = false; + StageControl.DevirtualizeCall = false; + StageControl.IrTypeTestElimPunt = false; + StageControl.IrTypeTestElim = false; + StageControl.IrSimpleInliner = false; + + // IR clean up optimizations + StageControl.IrDeadAssignmentSimple2 = false; + StageControl.IrCleanupStructOperations = false; + StageControl.IrShortCircuitBBlocks = false; + StageControl.IrTreeShakeLate = false; + StageControl.IrArrayLoadStoreOpt = false; + StageControl.IrConvertSimpleArrayAccess = false; + + // from the backend + StageControl.RegAllocCoalesce = false; + StageControl.RegAllocSpill = StageControl.SpillOptimizeSinglePass; + StageControl.OptLirCompactify = false; + StageControl.OptLirGlobalConstantProp = false; + StageControl.OptLirLocalConstantProp = true; + StageControl.OptLirImproveCC = false; + StageControl.OptLirPeephole = false; + StageControl.OptLirReverseCSE = false; + StageControl.OptLirGlobalCopyProp = false; + StageControl.OptLirLocalCopyProp = true; + StageControl.LayoutLoopHeaderLast = false; + + if (StageControl.SymbolicDebug) { + StageControl.OptimizeLocals = false; + } + } else if (IsOption(args, option, loweredOption, "nohiropt", + ref index, out optionValue)) { + StageControl.ABCD = false; + StageControl.DevirtualizeCall = false; + StageControl.IdentifyAsMethods = false; + StageControl.IrAttributeInliner = false; + StageControl.IrBBLocalCopyProp = false; + StageControl.IrCleanup = false; + StageControl.IrCleanupStructOperations = false; + StageControl.IrCloneLoopHeader = false; + StageControl.IrConvertOpt = false; + StageControl.IrDeadAssignmentSimple1 = false; + StageControl.IrDeadAssignmentSimple2 = false; + StageControl.IrInitStaticField = false; + StageControl.IrInterfaceElim = false; + StageControl.IrJumpElim = false; + StageControl.IrLoadStoreOpt = false; + StageControl.IrMultiPropSimple = false; + StageControl.IrPeepholeNull = false; + StageControl.IrRemoveDoubleCmp = false; + StageControl.IrReverseCopyProp = false; + StageControl.IrShortCircuitBBlocks = false; + StageControl.IrSimpleInliner = false; + StageControl.IrStoreChecks = false; + StageControl.IrTreeShakeLate = false; + StageControl.IrTypeTestElimPunt = false; + StageControl.SsaArraySimple = false; + StageControl.SsaDeadCode = false; + StageControl.SsaLoopInv = false; + StageControl.SsaNullCheck = false; + StageControl.SsaOpts = false; + StageControl.TypeInitRemoveEmptyCctors = false; + StageControl.UnmanagedStrings = false; + } else if (IsOption(args, option, loweredOption, "singularity", + ref index, out optionValue)) { + StageControl.SingSharpTemplateRemover = true; + StageControl.DisablePInvoke = true; + StageControl.StrictEcma = true; + StageControl.CustomAllocatorTypes = true; + StageControl.SurrogateBoxing = true; + StageControl.StructInheritance = true; + StageControl.IrTreeShakeCreatePointedToStructs = true; + StageControl.IrTreeShakeLate = false; // not tested + StageControl.TypeInitRemoveEmptyCctors = false; // not tested + StageControl.CheckNoHeapAllocation = true; + } else if (IsOption(args, option, loweredOption, "verbosehelp", + ref index, out optionValue)) { + PrintUsage(); + StageControl.PrintUsage(); + } else if (IsOption(args, option, loweredOption, "verbosehelpalpha", + ref index, out optionValue)) { + PrintUsage(); + StageControl.PrintUsageAlpha(); + } else if (IsOption(args, option, loweredOption, "x86", + ref index, out optionValue)) { + StageControl.TargetArch = StageControl.X86; + StageControl.Target64Bit = false; + } else if (IsOption(args, option, loweredOption, "x64", + ref index, out optionValue)) { + StageControl.TargetArch = StageControl.X64; + StageControl.Target64Bit = true; + } else if (IsOption(args, option, loweredOption, "help", + ref index, out optionValue) + || IsOption(args, option, loweredOption, "?", + ref index, out optionValue)) { + PrintUsage(); + } else if (IsOption + (args, option, loweredOption, "centralpt", + ref index, out optionValue)) { + StageControl.PTType = StageControl.CentralPT; + } else if (IsOption + (args, option, loweredOption, "centralpthimem", + ref index, out optionValue)) { + StageControl.PTType = StageControl.CentralPTHimem; + } else if (IsOption + (args, option, loweredOption, "flatdistributedpt", + ref index, out optionValue)) { + StageControl.PTType = StageControl.FlatDistributedPT; + } else if (IsOption + (args, option, loweredOption, "flatdistributedtestpt", + ref index, out optionValue)) { + StageControl.PTType = StageControl.FlatDistributedPTTest; + } else if (StageControl.SetOptionFromCommandLine(loweredOption)) { + index++; + } else if (loweredOption.StartsWith("stagecontrol")) { + Util.AbortUserCE("/stagecontrol no longer supported; " + + "use the option directly"); + } else { + Util.AbortUserCE("Unknown option: " + option); + } + } + + private static bool IsOption(String[] args, + String option, String loweredOption, + String possibleOptionName, + ref int index, out String optionValue) { + if(possibleOptionName.EndsWith(":")) { + if(loweredOption.StartsWith(possibleOptionName)) { + index++; + if(option.Length == possibleOptionName.Length) { + // case: "/option: value" + optionValue = args[index++]; + } else { + // case: "/option:value" + optionValue = option.Substring(possibleOptionName.Length); + } + return true; + } + } else { + if(loweredOption == possibleOptionName) { + index++; + optionValue = null; + return true; + } + } + + optionValue = null; + return false; + } + + private static void AddSemicolonDelimitedNames(ArrayList names, + String argument) { + int index = 0; + StringBuilder buf = new StringBuilder(); + while (index < argument.Length) { + if (argument[index] != ';') { + buf.Append(argument[index]); + index++; + } + else { + if (buf.Length > 0) { + names.Add(buf.ToString()); + buf = new StringBuilder(); + } + index++; + } + } + names.Add(buf.ToString()); + } + + public static void PrintUsage() { + if (alreadyPrintedUsage) { + return; + } + alreadyPrintedUsage = true; + Util.Message( +@"Usage: + bartok [options] files + +Bartok main options (case insensitive): + /entry: ;;... specify entry points + /reference: ;;... reference metadata from assembly files + /r: ;;... short form of /reference: + /bartoklink: ;;... reference precompiled object files + /override: ;;... files overriding /r: metadata + /lib: ;;... additional dirs to search for references + /out: output file name + /outdir: dir for output .exe, asm, obj, etc. + (defaults to .\\debug) + /skip: ;;... specify type initializers to disable + if building static ordering + /substitute:=, rename TypeRefs before performing lookup + =,... + /disable: disable a phase + /dynamicload: make type available for dynamic loading + /features: << TODO >> + /noisymethod: enable noisy output for meth + /debugmethod: enable debug+noisy output for meth + /verbosity: set output level {Silence,PerPhase, + PerClass,PerMethod,PerBlock, + PerInstruction} (defaults to PerPhase) + /marksweepgc compile for mark-sweep collector + /semispacegc compile for semispace collector + /slidinggc compile for sliding collector + /adaptivecopyinggc compile for semispace-sliding hybrid + collector + /referencecountinggc compile for reference counting collector + /deferredreferencecountinggc compile for deferred reference counting collector + /concurrentmsgc compile for concurrent mark-sweep + collector + /nullgc compile for no collector + /minopt disable most optimizations + /nohiropt disable all HIR optimizations + /singularity set default Singularity options + /verbosehelp help message including stage control + options by category + /verbosehelpalpha help message including stage control + options in alphabetical order + /help or /? help message"); + } + } + + internal class MetaDataOutput : Bartok.MSIL.IMetaDataOutput { + public TextWriter Log { get { return Util.Log; } } + public TextWriter ErrorOut { get { return Util.ErrorOut; } } + public TextWriter WarnOut { get { return Util.WarnOut; } } + + public void Error(string msg) + { + Util.Error(msg); + } + + public void Error(string format, params Object[] objs) + { + Util.Error(format, objs); + } + + public void ErrorDetail(string msg) + { + Util.ErrorDetail(msg); + } + + public void Warn(string msg) + { + Util.Warn(msg); + } + + public void Warn(string format, params Object[] objs) + { + Util.Warn(format, objs); + } + + public void WarnDetail(string msg) + { + Util.WarnDetail(msg); + } + + public void Message(string msg) + { + Util.Message(msg); + } + } +} diff --git a/base/Applications/Benchmarks/bartok/BartokBenchmark.csproj b/base/Applications/Benchmarks/bartok/BartokBenchmark.csproj new file mode 100644 index 0000000..9d610b7 --- /dev/null +++ b/base/Applications/Benchmarks/bartok/BartokBenchmark.csproj @@ -0,0 +1,62 @@ + + + + + + + + Bartok + Exe + ON_SINGULARITY + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/base/Applications/Benchmarks/bartok/kernel/Diagnostics.Contracts.dll b/base/Applications/Benchmarks/bartok/kernel/Diagnostics.Contracts.dll new file mode 100644 index 0000000..c110da3 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Diagnostics.Contracts.dll differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Diagnostics.Contracts.pdb b/base/Applications/Benchmarks/bartok/kernel/Diagnostics.Contracts.pdb new file mode 100644 index 0000000..955101f Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Diagnostics.Contracts.pdb differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Diagnostics.dll b/base/Applications/Benchmarks/bartok/kernel/Diagnostics.dll new file mode 100644 index 0000000..a324a15 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Diagnostics.dll differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Diagnostics.pdb b/base/Applications/Benchmarks/bartok/kernel/Diagnostics.pdb new file mode 100644 index 0000000..cbcd9d1 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Diagnostics.pdb differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Directory.Contracts.dll b/base/Applications/Benchmarks/bartok/kernel/Directory.Contracts.dll new file mode 100644 index 0000000..324e6d7 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Directory.Contracts.dll differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Directory.Contracts.pdb b/base/Applications/Benchmarks/bartok/kernel/Directory.Contracts.pdb new file mode 100644 index 0000000..39dc5df Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Directory.Contracts.pdb differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Directory.dll b/base/Applications/Benchmarks/bartok/kernel/Directory.dll new file mode 100644 index 0000000..6017ee2 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Directory.dll differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Directory.pdb b/base/Applications/Benchmarks/bartok/kernel/Directory.pdb new file mode 100644 index 0000000..c4515bd Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Directory.pdb differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Drivers.dll b/base/Applications/Benchmarks/bartok/kernel/Drivers.dll new file mode 100644 index 0000000..c37ac1d Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Drivers.dll differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Drivers.pdb b/base/Applications/Benchmarks/bartok/kernel/Drivers.pdb new file mode 100644 index 0000000..2a98a38 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Drivers.pdb differ diff --git a/base/Applications/Benchmarks/bartok/kernel/FileSystem.Contracts.dll b/base/Applications/Benchmarks/bartok/kernel/FileSystem.Contracts.dll new file mode 100644 index 0000000..b41267f Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/FileSystem.Contracts.dll differ diff --git a/base/Applications/Benchmarks/bartok/kernel/FileSystem.Contracts.pdb b/base/Applications/Benchmarks/bartok/kernel/FileSystem.Contracts.pdb new file mode 100644 index 0000000..68e7e6c Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/FileSystem.Contracts.pdb differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Hal.LegacyPC.dll b/base/Applications/Benchmarks/bartok/kernel/Hal.LegacyPC.dll new file mode 100644 index 0000000..34808a8 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Hal.LegacyPC.dll differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Hal.LegacyPC.pdb b/base/Applications/Benchmarks/bartok/kernel/Hal.LegacyPC.pdb new file mode 100644 index 0000000..1b8ed56 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Hal.LegacyPC.pdb differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Hypercall.Contracts.dll b/base/Applications/Benchmarks/bartok/kernel/Hypercall.Contracts.dll new file mode 100644 index 0000000..962406c Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Hypercall.Contracts.dll differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Hypercall.Contracts.pdb b/base/Applications/Benchmarks/bartok/kernel/Hypercall.Contracts.pdb new file mode 100644 index 0000000..aa3b935 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Hypercall.Contracts.pdb differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Hypercall.dll b/base/Applications/Benchmarks/bartok/kernel/Hypercall.dll new file mode 100644 index 0000000..69c79d6 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Hypercall.dll differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Hypercall.pdb b/base/Applications/Benchmarks/bartok/kernel/Hypercall.pdb new file mode 100644 index 0000000..add584c Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Hypercall.pdb differ diff --git a/base/Applications/Benchmarks/bartok/kernel/ILHelpers.dll b/base/Applications/Benchmarks/bartok/kernel/ILHelpers.dll new file mode 100644 index 0000000..853b9bc Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/ILHelpers.dll differ diff --git a/base/Applications/Benchmarks/bartok/kernel/ILHelpers.pdb b/base/Applications/Benchmarks/bartok/kernel/ILHelpers.pdb new file mode 100644 index 0000000..461e888 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/ILHelpers.pdb differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Io.Contracts.dll b/base/Applications/Benchmarks/bartok/kernel/Io.Contracts.dll new file mode 100644 index 0000000..34a285b Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Io.Contracts.dll differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Io.Contracts.pdb b/base/Applications/Benchmarks/bartok/kernel/Io.Contracts.pdb new file mode 100644 index 0000000..f529bdd Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Io.Contracts.pdb differ diff --git a/base/Applications/Benchmarks/bartok/kernel/IoSystem.dll b/base/Applications/Benchmarks/bartok/kernel/IoSystem.dll new file mode 100644 index 0000000..6278c92 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/IoSystem.dll differ diff --git a/base/Applications/Benchmarks/bartok/kernel/IoSystem.pdb b/base/Applications/Benchmarks/bartok/kernel/IoSystem.pdb new file mode 100644 index 0000000..e9cf95c Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/IoSystem.pdb differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Loader.dll b/base/Applications/Benchmarks/bartok/kernel/Loader.dll new file mode 100644 index 0000000..6091c42 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Loader.dll differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Loader.pdb b/base/Applications/Benchmarks/bartok/kernel/Loader.pdb new file mode 100644 index 0000000..3ac2c5a Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Loader.pdb differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Microsoft.SingSharp.Runtime.dll b/base/Applications/Benchmarks/bartok/kernel/Microsoft.SingSharp.Runtime.dll new file mode 100644 index 0000000..182dadc Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Microsoft.SingSharp.Runtime.dll differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Microsoft.SingSharp.Runtime.pdb b/base/Applications/Benchmarks/bartok/kernel/Microsoft.SingSharp.Runtime.pdb new file mode 100644 index 0000000..0661fd0 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Microsoft.SingSharp.Runtime.pdb differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Security.Contracts.dll b/base/Applications/Benchmarks/bartok/kernel/Security.Contracts.dll new file mode 100644 index 0000000..619e938 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Security.Contracts.dll differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Security.Contracts.pdb b/base/Applications/Benchmarks/bartok/kernel/Security.Contracts.pdb new file mode 100644 index 0000000..0d44de1 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Security.Contracts.pdb differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Security.dll b/base/Applications/Benchmarks/bartok/kernel/Security.dll new file mode 100644 index 0000000..b782740 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Security.dll differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Security.pdb b/base/Applications/Benchmarks/bartok/kernel/Security.pdb new file mode 100644 index 0000000..7c19321 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Security.pdb differ diff --git a/base/Applications/Benchmarks/bartok/kernel/SecurityService.dll b/base/Applications/Benchmarks/bartok/kernel/SecurityService.dll new file mode 100644 index 0000000..74efcab Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/SecurityService.dll differ diff --git a/base/Applications/Benchmarks/bartok/kernel/SecurityService.pdb b/base/Applications/Benchmarks/bartok/kernel/SecurityService.pdb new file mode 100644 index 0000000..e7119d9 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/SecurityService.pdb differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Stress.Contracts.dll b/base/Applications/Benchmarks/bartok/kernel/Stress.Contracts.dll new file mode 100644 index 0000000..4b61a18 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Stress.Contracts.dll differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Stress.Contracts.pdb b/base/Applications/Benchmarks/bartok/kernel/Stress.Contracts.pdb new file mode 100644 index 0000000..01b462e Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Stress.Contracts.pdb differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Stress.dll b/base/Applications/Benchmarks/bartok/kernel/Stress.dll new file mode 100644 index 0000000..cf32fbd Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Stress.dll differ diff --git a/base/Applications/Benchmarks/bartok/kernel/Stress.pdb b/base/Applications/Benchmarks/bartok/kernel/Stress.pdb new file mode 100644 index 0000000..6395486 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/Stress.pdb differ diff --git a/base/Applications/Benchmarks/bartok/kernel/System.Compiler.Runtime.dll b/base/Applications/Benchmarks/bartok/kernel/System.Compiler.Runtime.dll new file mode 100644 index 0000000..2e8511b Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/System.Compiler.Runtime.dll differ diff --git a/base/Applications/Benchmarks/bartok/kernel/System.Compiler.Runtime.pdb b/base/Applications/Benchmarks/bartok/kernel/System.Compiler.Runtime.pdb new file mode 100644 index 0000000..dd77d31 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/System.Compiler.Runtime.pdb differ diff --git a/base/Applications/Benchmarks/bartok/kernel/kernel.exe b/base/Applications/Benchmarks/bartok/kernel/kernel.exe new file mode 100644 index 0000000..6de7c18 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/kernel.exe differ diff --git a/base/Applications/Benchmarks/bartok/kernel/kernel.pdb b/base/Applications/Benchmarks/bartok/kernel/kernel.pdb new file mode 100644 index 0000000..3d37732 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/kernel/kernel.pdb differ diff --git a/base/Applications/Benchmarks/bartok/kernel/test.cmd b/base/Applications/Benchmarks/bartok/kernel/test.cmd new file mode 100644 index 0000000..c8bbd2d --- /dev/null +++ b/base/Applications/Benchmarks/bartok/kernel/test.cmd @@ -0,0 +1,5 @@ +@rmdir /q /s obj 2>nul +@mkdir obj +@del log 2>nul + +bartok.exe /Singularity /verbosity:silence /LinkedStacksRequireExternalBound=true /GCInlineAllocations=false /GCInlineWriteBarrier=false /UseSegmentRegister=true /OmitFramePointer=false /SymbolicDebug=true /DebugInline=true /IrSimpleInliner=false /UnnameTracedPtrs=true /Warnings=true /WholeProgram=true /GenCoffLineNumber=false /MarkSweepGC /minopt /IrSimpleInliner=false /out: obj\kernel.obj /outdir: obj kernel.exe Diagnostics.dll Hypercall.dll Loader.dll Directory.dll Stress.dll IoSystem.dll Hal.LegacyPC.dll System.Compiler.Runtime.dll ILHelpers.dll Microsoft.SingSharp.Runtime.dll Diagnostics.Contracts.dll Hypercall.Contracts.dll Directory.Contracts.dll FileSystem.Contracts.dll Io.Contracts.dll Stress.Contracts.dll Drivers.dll Security.Contracts.dll Security.dll SecurityService.dll diff --git a/base/Applications/Benchmarks/bartok/kernel/xbartok.script b/base/Applications/Benchmarks/bartok/kernel/xbartok.script new file mode 100644 index 0000000..d228631 --- /dev/null +++ b/base/Applications/Benchmarks/bartok/kernel/xbartok.script @@ -0,0 +1,4 @@ +clear +perfcnt '-g' +bartok '/Singularity' '/verbosity:PerPhase' '/LinkedStacksRequireExternalBound=true' '/LinkedStacksDumpBounds=true' '/BackEndComments=true' '/GCInlineAllocations=false' '/GCInlineWriteBarrier=false' '/LinkedStacks=true' '/UseSegmentRegister=true' '/OmitFramePointer=false' '/SymbolicDebug=true' '/DebugInline=true' '/UnnameTracedPtrs=true' '/Warnings=true' '/WholeProgram=true' '/GenCoffLineNumber=false' '/MarkSweepGC' '/minopt' '/IrSimpleInliner=false' '/DumpMethodSizes=false' '/LinkedStacksTrace=false' '/LinkedStacksDumpBounds=false' '/LinkedStacksDumpEntryPointBounds=false' '/out:' '\init\kernel.obj' '/outdir:' '\init' '\init\kernel.exe' '\init\Diagnostics.dll' '\init\Loader.dll' '\init\Directory.dll' '\init\Stress.dll' '\init\IoSystem.dll' '\init\Hal.LegacyPC.dll' '\init\System.Compiler.Runtime.dll' '\init\ILHelpers.dll' '\init\Microsoft.SingSharp.Runtime.dll' '\init\Diagnostics.Contracts.dll' '\init\Directory.Contracts.dll' '\init\FileSystem.Contracts.dll' '\init\Io.Contracts.dll' '\init\Stress.Contracts.dll' '\init\drivers.dll' '\init\Security.Contracts.dll' '\init\Security.dll' '\init\Security.Service.dll' +perfcnt diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Analysis.dll b/base/Applications/Benchmarks/bartok/msil/Bartok.Analysis.dll new file mode 100644 index 0000000..ad77e57 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Analysis.dll differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Analysis.pdb b/base/Applications/Benchmarks/bartok/msil/Bartok.Analysis.pdb new file mode 100644 index 0000000..91a6364 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Analysis.pdb differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Backend.dll b/base/Applications/Benchmarks/bartok/msil/Bartok.Backend.dll new file mode 100644 index 0000000..6c6b6a4 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Backend.dll differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Backend.pdb b/base/Applications/Benchmarks/bartok/msil/Bartok.Backend.pdb new file mode 100644 index 0000000..8290412 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Backend.pdb differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.CfgUtil.dll b/base/Applications/Benchmarks/bartok/msil/Bartok.CfgUtil.dll new file mode 100644 index 0000000..cbd7f2a Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.CfgUtil.dll differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.CfgUtil.pdb b/base/Applications/Benchmarks/bartok/msil/Bartok.CfgUtil.pdb new file mode 100644 index 0000000..afe07cd Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.CfgUtil.pdb differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Coff.dll b/base/Applications/Benchmarks/bartok/msil/Bartok.Coff.dll new file mode 100644 index 0000000..566f09d Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Coff.dll differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Coff.pdb b/base/Applications/Benchmarks/bartok/msil/Bartok.Coff.pdb new file mode 100644 index 0000000..db6145e Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Coff.pdb differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Convert.dll b/base/Applications/Benchmarks/bartok/msil/Bartok.Convert.dll new file mode 100644 index 0000000..0689e53 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Convert.dll differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Convert.pdb b/base/Applications/Benchmarks/bartok/msil/Bartok.Convert.pdb new file mode 100644 index 0000000..82714b2 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Convert.pdb differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Datatype.dll b/base/Applications/Benchmarks/bartok/msil/Bartok.Datatype.dll new file mode 100644 index 0000000..1f87802 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Datatype.dll differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Datatype.pdb b/base/Applications/Benchmarks/bartok/msil/Bartok.Datatype.pdb new file mode 100644 index 0000000..192a02d Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Datatype.pdb differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.DebugInfo.dll b/base/Applications/Benchmarks/bartok/msil/Bartok.DebugInfo.dll new file mode 100644 index 0000000..a90246e Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.DebugInfo.dll differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.DebugInfo.pdb b/base/Applications/Benchmarks/bartok/msil/Bartok.DebugInfo.pdb new file mode 100644 index 0000000..3dfa377 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.DebugInfo.pdb differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Encode.dll b/base/Applications/Benchmarks/bartok/msil/Bartok.Encode.dll new file mode 100644 index 0000000..2b2bb0d Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Encode.dll differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Encode.pdb b/base/Applications/Benchmarks/bartok/msil/Bartok.Encode.pdb new file mode 100644 index 0000000..8348722 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Encode.pdb differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Ir.dll b/base/Applications/Benchmarks/bartok/msil/Bartok.Ir.dll new file mode 100644 index 0000000..1302eb7 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Ir.dll differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Ir.pdb b/base/Applications/Benchmarks/bartok/msil/Bartok.Ir.pdb new file mode 100644 index 0000000..2a0b027 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Ir.pdb differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Lir.dll b/base/Applications/Benchmarks/bartok/msil/Bartok.Lir.dll new file mode 100644 index 0000000..3a76816 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Lir.dll differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Lir.pdb b/base/Applications/Benchmarks/bartok/msil/Bartok.Lir.pdb new file mode 100644 index 0000000..cefe573 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Lir.pdb differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.MSIL.dll b/base/Applications/Benchmarks/bartok/msil/Bartok.MSIL.dll new file mode 100644 index 0000000..14d3911 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.MSIL.dll differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.MSIL.pdb b/base/Applications/Benchmarks/bartok/msil/Bartok.MSIL.pdb new file mode 100644 index 0000000..ccc1973 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.MSIL.pdb differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Mangle.dll b/base/Applications/Benchmarks/bartok/msil/Bartok.Mangle.dll new file mode 100644 index 0000000..b24109d Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Mangle.dll differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Mangle.pdb b/base/Applications/Benchmarks/bartok/msil/Bartok.Mangle.pdb new file mode 100644 index 0000000..ee3587c Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Mangle.pdb differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Opt.dll b/base/Applications/Benchmarks/bartok/msil/Bartok.Opt.dll new file mode 100644 index 0000000..0832b85 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Opt.dll differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Opt.pdb b/base/Applications/Benchmarks/bartok/msil/Bartok.Opt.pdb new file mode 100644 index 0000000..4fe153f Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Opt.pdb differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Profile.dll b/base/Applications/Benchmarks/bartok/msil/Bartok.Profile.dll new file mode 100644 index 0000000..51c5ed5 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Profile.dll differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Profile.pdb b/base/Applications/Benchmarks/bartok/msil/Bartok.Profile.pdb new file mode 100644 index 0000000..2a85b46 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Profile.pdb differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Regalloc.dll b/base/Applications/Benchmarks/bartok/msil/Bartok.Regalloc.dll new file mode 100644 index 0000000..bd5059e Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Regalloc.dll differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Regalloc.pdb b/base/Applications/Benchmarks/bartok/msil/Bartok.Regalloc.pdb new file mode 100644 index 0000000..10fcc94 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Regalloc.pdb differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Runtime.dll b/base/Applications/Benchmarks/bartok/msil/Bartok.Runtime.dll new file mode 100644 index 0000000..8f0a1ae Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Runtime.dll differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Runtime.pdb b/base/Applications/Benchmarks/bartok/msil/Bartok.Runtime.pdb new file mode 100644 index 0000000..eaf779f Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Runtime.pdb differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.SystemExtension.dll b/base/Applications/Benchmarks/bartok/msil/Bartok.SystemExtension.dll new file mode 100644 index 0000000..a67e204 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.SystemExtension.dll differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.SystemExtension.pdb b/base/Applications/Benchmarks/bartok/msil/Bartok.SystemExtension.pdb new file mode 100644 index 0000000..e6f6105 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.SystemExtension.pdb differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Tables.dll b/base/Applications/Benchmarks/bartok/msil/Bartok.Tables.dll new file mode 100644 index 0000000..18bf6c9 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Tables.dll differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Tables.pdb b/base/Applications/Benchmarks/bartok/msil/Bartok.Tables.pdb new file mode 100644 index 0000000..10da284 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Tables.pdb differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Utility.dll b/base/Applications/Benchmarks/bartok/msil/Bartok.Utility.dll new file mode 100644 index 0000000..dcbdb4e Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Utility.dll differ diff --git a/base/Applications/Benchmarks/bartok/msil/Bartok.Utility.pdb b/base/Applications/Benchmarks/bartok/msil/Bartok.Utility.pdb new file mode 100644 index 0000000..f7c9950 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/Bartok.Utility.pdb differ diff --git a/base/Applications/Benchmarks/bartok/msil/bartok.exe b/base/Applications/Benchmarks/bartok/msil/bartok.exe new file mode 100644 index 0000000..e703037 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/bartok.exe differ diff --git a/base/Applications/Benchmarks/bartok/msil/bartok.pdb b/base/Applications/Benchmarks/bartok/msil/bartok.pdb new file mode 100644 index 0000000..6b2fdf8 Binary files /dev/null and b/base/Applications/Benchmarks/bartok/msil/bartok.pdb differ diff --git a/base/Applications/Benchmarks/diskreadperf/diskreadperf.csproj b/base/Applications/Benchmarks/diskreadperf/diskreadperf.csproj new file mode 100644 index 0000000..776bf4c --- /dev/null +++ b/base/Applications/Benchmarks/diskreadperf/diskreadperf.csproj @@ -0,0 +1,27 @@ + + + + + + + Exe + diskreadperf + true + + + + + + + + + + diff --git a/base/Applications/Benchmarks/diskreadperf/diskreadperf.sg b/base/Applications/Benchmarks/diskreadperf/diskreadperf.sg new file mode 100644 index 0000000..5846768 --- /dev/null +++ b/base/Applications/Benchmarks/diskreadperf/diskreadperf.sg @@ -0,0 +1,189 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: diskread.cs +// +// Note: +// +using System; +using System.Runtime.CompilerServices; +using System.Threading; + +using Microsoft.Singularity; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.V1.Services; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Channels; + +using Microsoft.Singularity.Channels; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications +{ + [ConsoleCategory(HelpMessage="Raw disk read performance test", DefaultAction=true)] + internal class Parameters + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef nsRef; + + [StringParameter( "device", Mandatory=true, Position=0 , HelpMessage="Raw device to read")] + internal string deviceName; + + [LongParameter( "mb", Default=10, HelpMessage="Megabytes to read.")] + internal long numMB; + + [LongParameter( "chunk", Default=65536, HelpMessage="Chunk size for each read.")] + internal long chunkSize; + + [LongParameter( "r", Default=1, HelpMessage="Repetition count.")] + internal long repetitions; + + reflective internal Parameters(); + + internal int AppMain() { + return DiskRead.AppMain(this); + } + } + + public class DiskRead + { + public static DiskDeviceContract.Imp:Ready OpenDevice(String! devname) + { + DiskDeviceContract.Exp! exp; + DiskDeviceContract.Imp! imp; + DiskDeviceContract.NewChannel(out imp, out exp); + DirectoryServiceContract.Imp ns; + + // get NS endpoint + ns = DirectoryService.NewClientEndpoint(); + bool success = false; + ErrorCode error; + success = SdsUtils.Bind(devname, ns, exp, out error); + if (!success) + { + Console.WriteLine("Bind of {0} failed\n", devname); + delete imp; + delete ns; + return null; + } + switch receive + { + case imp.Success(): + break; + case imp.ContractNotSupported(): + Console.WriteLine("{0} does not support DiskDevice", devname); + delete imp; + delete ns; + return null; + case imp.ChannelClosed(): + Console.WriteLine("DiskDevice channel to {0} closed unexpectedly", devname); + delete imp; + delete ns; + return null; + } + + delete ns; + return imp; + } + + public static bool StringToNumber(String! s, out ulong num) + { + char [] arr; + + if (s.Length == 0) + { + num = 0; + return false; + } + + arr = s.ToCharArray(); + foreach (char c in arr) + { + if (! Char.IsDigit(c)) + { + num = 0; + return false; + } + } + num = (ulong) int.Parse(s); + return true; + } + + + private static void DisplayPerf(long ticks, long cycles, ulong numMB, ulong chunkSize) + { + double elapsed = ticks / 10000000.0; + double opsPerSec = numMB * 1024 * 1024 / (elapsed * chunkSize); + double mbPerSec = numMB / elapsed; + Console.WriteLine("Ops/s: {0:f2} MB/s: {1:f2} Elapsed: {2:f2}", + opsPerSec, mbPerSec, elapsed); + } + + internal static int AppMain(Parameters! config) + { + long numMB = config.numMB; + long chunkSize = config.chunkSize; + long iters = config.repetitions; + + DiskDeviceContract.Imp imp; + string! devName = config.deviceName; + + imp = OpenDevice(devName); + if (null == imp) { + return 1; + } + + for (long i = 0; i < iters; i++) + { + long startIrqCount = ProcessService.GetKernelInterruptCount(); + long startSwitchCount = ProcessService.GetContextSwitchCount(); + long startKernelGcCount = ProcessService.GetKernelGcCount(); + int startGcCount; + long startGcMillis; + long startGcBytes; + GC.PerformanceCounters(out startGcCount, + out startGcMillis, + out startGcBytes); + + long cycles; + long ticks; + + imp.SendReadPerf( (int) numMB, (int) chunkSize); + imp.RecvAckReadPerf(out cycles, out ticks); + + + int endGcCount; + long endGcMillis; + long endGcBytes; + GC.PerformanceCounters(out endGcCount, + out endGcMillis, + out endGcBytes); + + DisplayPerf(ticks, cycles, (ulong) numMB, (ulong)chunkSize); + Console.WriteLine("[AppGC :- cnt {0} bytes {1} Kern: ints {2} swi {3} gcs {4}]", + endGcCount - startGcCount, + endGcBytes - startGcBytes, + ProcessService.GetKernelInterruptCount() - startIrqCount, + ProcessService.GetContextSwitchCount() - startSwitchCount, + ProcessService.GetKernelGcCount() - startKernelGcCount); + } + + delete imp; + return 0; + } + } +} diff --git a/base/Applications/Benchmarks/diskrw/diskrw.csproj b/base/Applications/Benchmarks/diskrw/diskrw.csproj new file mode 100644 index 0000000..e5c28e6 --- /dev/null +++ b/base/Applications/Benchmarks/diskrw/diskrw.csproj @@ -0,0 +1,28 @@ + + + + + + + Exe + diskrw + true + + + + + + + + + + + diff --git a/base/Applications/Benchmarks/diskrw/diskrw.sg b/base/Applications/Benchmarks/diskrw/diskrw.sg new file mode 100644 index 0000000..5912f83 --- /dev/null +++ b/base/Applications/Benchmarks/diskrw/diskrw.sg @@ -0,0 +1,376 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: diskrw.sg +// +// Note: +// + +using System; +using System.Runtime.CompilerServices; + +using Microsoft.Singularity; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.V1.Services; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Channels; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications.Benchmarks.DiskRW +{ + [ConsoleCategory(HelpMessage="Disk r/w performance test", DefaultAction=true)] + internal class Parameters + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [StringParameter( "device", Mandatory=true, Position=0 , HelpMessage="Device to read/write")] + internal string deviceName; + + [LongParameter( "b", Default=0, Mandatory=true, HelpMessage="Set block size to bytes.")] + internal long blockBytes; + + [LongParameter( "g", Default=1, HelpMessage="Repeat test n times.")] + internal long repeatCount; + + [LongParameter( "l", Default=0, HelpMessage="Fix disk size limit at megabytes.")] + internal long diskLimitMB; + + [LongParameter( "m", Default=0, HelpMessage="Perform test with megabytes of data.")] + internal long dataMB; + + [LongParameter( "n", Default=0, HelpMessage="Perform test with blocks of data.")] + internal long blockCount; + + [LongParameter( "p", Default=0, HelpMessage="Pause seconds between iterations")] + internal long pauseSecs; + + [BoolParameter( "r", Default=false, HelpMessage="Perform disk read test.")] + internal bool doRead ; + + [BoolParameter( "w", Default=false, HelpMessage="Perform disk write test.")] + internal bool doWrite; + + [BoolParameter( "x", Default=false, HelpMessage="Perform test with random I/O offsets.")] + internal bool randomIO; + + reflective internal Parameters(); + + internal int AppMain() { + return DiskBenchmark.AppMain(this); + } + } + + public class DiskBenchmark + { + private const uint BytesPerSector = 512; + private const uint SectorsPerMB = 1024 * 1024 / BytesPerSector; + + public static DiskDeviceContract.Imp:Ready OpenDevice(String! devname) + { + DiskDeviceContract.Exp! exp; + DiskDeviceContract.Imp! imp; + DiskDeviceContract.NewChannel(out imp, out exp); + DirectoryServiceContract.Imp ns; + + ErrorCode errorOut; + // get NS endpoint + ns = DirectoryService.NewClientEndpoint(); + bool success; + success = SdsUtils.Bind(devname,ns, exp, out errorOut); + if (!success) + { + Console.WriteLine("Bind of {0} failed. Reason:{1}\n", + devname, SdsUtils.ErrorCodeToString(errorOut)); + delete imp; + delete ns; + return null; + } + switch receive + { + case imp.Success(): + break; + case imp.ContractNotSupported(): + Console.WriteLine("{0} does not support DiskDevice", devname); + delete imp; + delete ns; + return null; + case imp.ChannelClosed(): + Console.WriteLine("DiskDevice channel to {0} closed unexpectedly", devname); + delete imp; + delete ns; + return null; + } + + delete ns; + return imp; + } + + private static ulong GetRandomOffset(SRandom! rng, + ulong diskSectorCount, + ulong blockBytes) + { + ulong maxBlock = diskSectorCount * 512 / blockBytes; + ulong offset = 0; + for (int i = 0; i < 64; i += 30) + { + offset ^= (ulong)(rng.Next() << i); + } + offset &= 0x7fffffffffffffff; + offset %= maxBlock; + return offset * blockBytes; + } + + private static void DisplayPerf(bool didRead, + bool didRandom, + TimeSpan elapsed, + ulong blockCount, + ulong blockBytes, + ulong nextOffset) + { + double delta = (double)elapsed.Ticks / TimeSpan.TicksPerSecond; + double ops = (double)blockCount / delta; + + string output = String.Format( + "{0}{1} {2} {3} Ops/s: {4:f2} MB/s: {5:f2} Elapsed: {6:f2} Check: {7:x}", + didRandom ? "R" : "S", + didRead ? "R" : "W", + blockBytes, + blockCount, + ops, + ops * blockBytes / (1024.0 * 1024.0), + delta, + nextOffset); + + Console.WriteLine(output); + DebugStub.WriteLine(output); + } + + public static int DoDevice(string! deviceName, + int runNumber, + ulong blockCount, + ulong blockBytes, + ulong diskLimitMB, + bool doRandom, + bool doRead) + { + // + // Open device + // + DiskDeviceContract.Imp imp = OpenDevice(deviceName); + if (null == imp) + { + Console.WriteLine("Could not open {0}", deviceName); + return 1; + } + + // + // Get disk size + // + ulong diskSectorCount; + + imp.SendGetSectorCount(); + switch receive + { + case imp.AckGetSectorCount(sectorCount): + diskSectorCount = sectorCount; + break; + case imp.ChannelClosed(): + Console.WriteLine("Channel closed unexpectedly"); + throw new Exception("Unexpected channel close"); + } + + // Constrain disk size if user requested + if (diskLimitMB != 0 && + diskSectorCount > diskLimitMB * SectorsPerMB) + { + diskSectorCount = diskLimitMB * SectorsPerMB; + } + diskLimitMB = diskSectorCount / SectorsPerMB; + + // Constrain block count if it overflows available blocks + if (blockCount * blockBytes > diskSectorCount * BytesPerSector) + { + blockCount = diskSectorCount * BytesPerSector / blockBytes; + } + + if (runNumber == 0) + { + Console.WriteLine("# Type: {0} {1}", + doRandom ? "Random" : "Sequential", + doRead ? "Read" : "Write"); + Console.WriteLine("# Disk: {0} MB", + diskSectorCount / SectorsPerMB); + Console.WriteLine("# Limit: {0} MB", diskLimitMB); + Console.WriteLine("# Work: {0:f2} MB", + blockCount * blockBytes / (1024.0 * 1024.0)); + Console.WriteLine("# Ops: {0}", blockCount); + } + + byte[] in ExHeap buffer = new [ExHeap] byte [blockBytes]; + + SRandom rng = new SRandom(); + + ulong diskPos = 0; + if (doRandom) + { + diskPos = GetRandomOffset(rng, diskSectorCount, blockBytes); + } + + long startIrqCount = ProcessService.GetKernelInterruptCount(); + long startSwitchCount = ProcessService.GetContextSwitchCount(); + long startKernelGcCount = ProcessService.GetKernelGcCount(); + int startGcCount; + long startGcMillis; + long startGcBytes; + GC.PerformanceCounters(out startGcCount, + out startGcMillis, + out startGcBytes); + + TimeSpan startTime = ProcessService.GetUpTime(); + + for (ulong i = 0; i < blockCount; i++) + { + ulong sector = diskPos / BytesPerSector; + + byte[]! in ExHeap outBuffer; + if (doRead) + { + imp.SendRead(buffer, 0, blockBytes, sector); + imp.RecvAckRead(out outBuffer); + } + else + { + imp.SendWrite(buffer, 0, blockBytes, sector); + imp.RecvAckWrite(out outBuffer); + } + buffer = outBuffer; + + if (doRandom) + { + diskPos = + GetRandomOffset(rng, diskSectorCount, blockBytes); + } + else + { + diskPos += blockBytes; + } + } + TimeSpan endTime = ProcessService.GetUpTime(); + + delete buffer; + delete imp; + + DisplayPerf(doRead, doRandom, endTime - startTime, + blockCount, blockBytes, diskPos); + + int endGcCount; + long endGcMillis; + long endGcBytes; + GC.PerformanceCounters(out endGcCount, + out endGcMillis, + out endGcBytes); + + Console.WriteLine("[AppGC :- cnt {0} bytes {1} Kern: ints {2} swi {3} gcs {4}]", + endGcCount - startGcCount, + endGcBytes - startGcBytes, + ProcessService.GetKernelInterruptCount() - startIrqCount, + ProcessService.GetContextSwitchCount() - startSwitchCount, + ProcessService.GetKernelGcCount() - startKernelGcCount); + + return 0; + } + + public static bool ParseNumber(string! arg, + string! name, + out ulong value) + { + // arg should look like "[-/][A-z]:[0-9]" + if (arg.Length >= 4) + { + try + { + value = UInt64.Parse(arg.Substring(3)); + return true; + } + catch (FormatException) + {} + catch (OverflowException) + {} + } + Console.WriteLine("Could not parse {0}", name); + value = 0; + return false; + } + + static void Usage() + { + } + + internal static int AppMain(Parameters! config) + { + string deviceName = config.deviceName; + ulong blockBytes = (ulong) config.blockBytes; + ulong blockCount = (ulong) config.blockCount; + ulong diskLimitMB = (ulong) config.diskLimitMB; + ulong repeatCount = (ulong) config.repeatCount; + ulong pauseSecs = (ulong) config.pauseSecs; + bool randomIO = config.randomIO; + bool diskReadTest = false; + bool doWrite = config.doWrite; + bool doRead = config.doRead; + ulong dataMB = (ulong) config.dataMB; + + if (blockBytes < 512 || (blockBytes & (blockBytes - 1)) != 0) + { + Console.WriteLine("Block size must be a power of two greater than or equal to 512."); + Usage(); + return -1; + } + + if (doRead == doWrite) + { + Console.WriteLine("Need to specify either read or write test."); + Usage(); + return -1; + } + else if (doRead) + { + diskReadTest = true; + } + + if (dataMB != 0) + { + blockCount = dataMB * 1024 * 1024 / blockBytes; + } + + for (int run = 0; run < (int)repeatCount; run++) + { + if (run != 0) + System.Threading.Thread.Sleep(1000 * (int)pauseSecs); + Tracing.Log(Tracing.Debug, "Starting diskrw run {0}", + (UIntPtr) run); + if (DoDevice(deviceName, run, blockCount, blockBytes, + diskLimitMB, randomIO, diskReadTest) != 0) + { + return -1; + } + Tracing.Log(Tracing.Debug, "Ending diskrw run {0}", + (UIntPtr) run); + } + return 0; + } + } +} diff --git a/base/Applications/Benchmarks/diskrw/srandom.sg b/base/Applications/Benchmarks/diskrw/srandom.sg new file mode 100644 index 0000000..8752efe --- /dev/null +++ b/base/Applications/Benchmarks/diskrw/srandom.sg @@ -0,0 +1,64 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// + + +using System; +using Microsoft.Contracts; + +namespace Microsoft.Singularity.Applications.Benchmarks.DiskRW +{ + /// + /// Low-cost Integer random number generator. The + /// implementation is based on the description of Park and + /// Miller's RNG on page 278 of Numerical Recipes in C, 2nd + /// Edition, by Press, Teukolsky, Vetterling, and Flannery. + /// + /// The same random number generator is used for our disk + /// benchmarks on other platforms. + /// + public class SRandom + { + public const int Maximum = 0x7fffffffu; + + const ulong m = 2147483647; + const ulong a = 16807; + const uint initialValue = 0x23456789; + uint last; + + public SRandom() + { + Reset(); + } + + [Delayed] + public void Reset() + { + last = initialValue; + } + + public int Next() + { + // Use 64-bit multiplication to preserve high bits. + ulong tmp = (a * last) % m; + last = (uint) tmp; + return (int)(last & Maximum); + } + + public static void Check() + { + const int test_iterations = 10000000; + SRandom r = new SRandom(); + int hash = 0; + for (int i = 0; i < test_iterations; i++) + { + int n = r.Next(); + System.Diagnostics.Debug.Assert(n != 0); + hash ^= n; + } + Console.Write("xor sum 1...{0} = {1}\n", test_iterations, hash); + System.Diagnostics.Debug.Assert(hash == 1080076236); + } + } +} diff --git a/base/Applications/Benchmarks/diskrwnull/diskrw.sg b/base/Applications/Benchmarks/diskrwnull/diskrw.sg new file mode 100644 index 0000000..78bb024 --- /dev/null +++ b/base/Applications/Benchmarks/diskrwnull/diskrw.sg @@ -0,0 +1,357 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: diskrw.sg +// +// Note: +// + +using System; +using System.Runtime.CompilerServices; + +using Microsoft.Singularity; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.V1.Services; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Channels; + +using System.Threading; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications.Benchmarks.DiskRWNull +{ + [ConsoleCategory(HelpMessage="Null Disk r/w performance test", DefaultAction=true)] + internal class Parameters + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [StringParameter( "device", Mandatory=true, Position=0 , HelpMessage="Device to read/write")] + internal string deviceName; + + [LongParameter( "b", Default=0, HelpMessage="Set block size to bytes.")] + internal long blockBytes; + + [LongParameter( "g", Default=1, HelpMessage="Repeat test n times.")] + internal long repeatCount; + + [LongParameter( "l", Default=0, HelpMessage="Fix disk size limit at megabytes.")] + internal long diskLimitMB; + + [LongParameter( "m", Default=0, HelpMessage="Perform test with megabytes of data.")] + internal long dataMB; + + [LongParameter( "n", Default=0, HelpMessage="Perform test with blocks of data.")] + internal long blockCount; + + [LongParameter( "p", Default=0, HelpMessage="Pause seconds between iterations")] + internal long pauseSecs; + + [BoolParameter( "r", Default=false, HelpMessage="Perform disk read test.")] + internal bool doRead ; + + [BoolParameter( "w", Default=false, HelpMessage="Perform disk write test.")] + internal bool doWrite; + + [BoolParameter( "x", Default=false, HelpMessage="Perform test with random I/O offsets.")] + internal bool randomIO; + + reflective internal Parameters(); + + internal int AppMain() { + return DiskBenchmark.AppMain(this); + } + } + contract Hack + { + message Hak(); + state HACK : one { Hak? -> Hak! -> HACK; } + } + + public class DiskBenchmark + { + static TRef himp; + static TRef hexp; + + private const uint BytesPerSector = 512; + private const uint SectorsPerMB = 1024 * 1024 / BytesPerSector; + + private static ulong GetRandomOffset(SRandom! rng, + ulong diskSectorCount, + ulong blockBytes) + { + ulong maxBlock = diskSectorCount * 512 / blockBytes; + ulong offset = 0; + for (int i = 0; i < 64; i += 30) + { + offset ^= (ulong)(rng.Next() << i); + } + offset &= 0x7fffffffffffffff; + offset %= maxBlock; + return offset * blockBytes; + } + + private static void DisplayPerf(bool didRead, + bool didRandom, + TimeSpan elapsed, + ulong blockCount, + ulong blockBytes, + ulong nextOffset) + { + double delta = (double)elapsed.Ticks / TimeSpan.TicksPerSecond; + double ops = (double)blockCount / delta; + + Console.Write("{0}{1}.{2} ", + didRandom ? "R" : "S", + didRead ? "R" : "W", + blockBytes); + + Console.WriteLine("Ops/s: {0:f2} MB/s: {1:f2} Elapsed: {2:f2} Check: {3:x}", + ops, ops * blockBytes / (1024.0 * 1024.0), + delta, nextOffset); + } + + public static int DoDevice(string! deviceName, + int runNumber, + ulong blockCount, + ulong blockBytes, + ulong diskLimitMB, + bool doRandom, + bool doRead) + { + + for(int i = 0; i < 4000; i++) + { + Hack.Imp! imp; + Hack.Exp! exp; + Hack.NewChannel(out imp, out exp); + delete imp; + delete exp; + } + ulong diskSectorCount = 4000000; + + // Constrain disk size if user requested + if (diskLimitMB != 0 && + diskSectorCount > diskLimitMB * SectorsPerMB) + { + diskSectorCount = diskLimitMB * SectorsPerMB; + } + diskLimitMB = diskSectorCount / SectorsPerMB; + + // Constrain block count if it overflows available blocks + if (blockCount * blockBytes > diskSectorCount * BytesPerSector) + { + blockCount = diskSectorCount * BytesPerSector / blockBytes; + } + + if (runNumber == 0) + { + Console.WriteLine("# Type: {0} {1}", + doRandom ? "Random" : "Sequential", + doRead ? "Read" : "Write"); + Console.WriteLine("# Disk: {0} MB", + diskSectorCount / SectorsPerMB); + Console.WriteLine("# Limit: {0} MB", diskLimitMB); + Console.WriteLine("# Work: {0:f2} MB", + blockCount * blockBytes / (1024.0 * 1024.0)); + Console.WriteLine("# Ops: {0}", blockCount); + } + + byte[] in ExHeap buffer = new [ExHeap] byte [blockBytes]; + + SRandom rng = new SRandom(); + + ulong diskPos = 0; + if (doRandom) + { + diskPos = GetRandomOffset(rng, diskSectorCount, blockBytes); + } + + long startIrqCount = ProcessService.GetKernelInterruptCount(); + long startSwitchCount = ProcessService.GetContextSwitchCount(); + long startKernelGcCount = ProcessService.GetKernelGcCount(); + int startGcCount; + long startGcMillis; + long startGcBytes; + GC.PerformanceCounters(out startGcCount, + out startGcMillis, + out startGcBytes); + + Hack.Imp! imph = himp.Acquire(); + Hack.Exp! exph = hexp.Acquire(); + + /***/ + ESet eset = new ESet(); + eset.Add(exph); + /***/ + + TimeSpan startTime = ProcessService.GetUpTime(); + + for (ulong i = 0; i < blockCount; i++) + { + byte[]! in ExHeap outBuffer; + if (doRead) + { + //ProcessService.GetUpTime(); + + //imph.SendHak(); + //switch receive { case exph.Hak(): exph.SendHak(); break; case unsatisfiable: throw new System.Exception(); } + //imph.RecvHak(); + + /***/ + imph.SendHak(); + switch receive { case ep.Hak() in eset: ep.SendHak(); eset.Add(ep); break; case unsatisfiable: throw new System.Exception(); } + imph.RecvHak(); + /***/ + + //imph.SendHak(); exph.RecvHak(); exph.SendHak(); imph.RecvHak(); + + outBuffer = buffer; + } + else + { + outBuffer = buffer; + } + buffer = outBuffer; + + if (doRandom) + { + diskPos = + GetRandomOffset(rng, diskSectorCount, blockBytes); + } + else + { + diskPos += blockBytes; + } + } + TimeSpan endTime = ProcessService.GetUpTime(); + + /***/ + imph.SendHak(); + switch receive { case ep.Hak() in eset: ep.SendHak(); hexp.Release(ep); break; case unsatisfiable: throw new System.Exception(); } + imph.RecvHak(); + himp.Release(imph); + eset.Dispose(); + /***/ + + //hexp.Release(exph); + //himp.Release(imph); + + delete buffer; + + DisplayPerf(doRead, doRandom, endTime - startTime, + blockCount, blockBytes, diskPos); + + int endGcCount; + long endGcMillis; + long endGcBytes; + GC.PerformanceCounters(out endGcCount, + out endGcMillis, + out endGcBytes); + + Console.WriteLine("[AppGC :- cnt {0} bytes {1} Kern: ints {2} swi {3} gcs {4}/{5}]", + endGcCount - startGcCount, + endGcBytes - startGcBytes, + ProcessService.GetKernelInterruptCount() - startIrqCount, + ProcessService.GetContextSwitchCount() - startSwitchCount, + ProcessService.GetKernelGcCount() - startKernelGcCount, + ProcessService.GetKernelGcCount()); + + return 0; + } + + public static bool ParseNumber(string! arg, + string! name, + out ulong value) + { + // arg should look like "[-/][A-z]:[0-9]" + if (arg.Length >= 4) + { + try + { + value = UInt64.Parse(arg.Substring(3)); + return true; + } + catch (FormatException) + {} + catch (OverflowException) + {} + } + Console.WriteLine("Could not parse {0}", name); + value = 0; + return false; + } + + internal static int AppMain(Parameters! config) + { + string deviceName = config.deviceName; + ulong blockBytes = (ulong) config.blockBytes; + ulong blockCount = (ulong) config.blockCount; + ulong diskLimitMB = (ulong) config.diskLimitMB; + ulong repeatCount = (ulong) config.repeatCount; + ulong pauseSecs = (ulong) config.pauseSecs; + ulong dataMB = (ulong) config.dataMB; + bool doWrite = config.doRead; + bool doRead = config.doWrite; + bool randomIO = config.randomIO; + + bool diskReadTest = false; + + Hack.Imp! imp; + Hack.Exp! exp; + Hack.NewChannel(out imp, out exp); + himp = new TRef(imp); + hexp = new TRef(exp); + + + if (blockBytes < 512 || (blockBytes & (blockBytes - 1)) != 0) + { + Console.WriteLine("Block size must be a power of two greater than or equal to 512."); + return -1; + } + + if (doRead == doWrite) + { + Console.WriteLine("Need to specify either read or write test."); + return -1; + } + else if (doRead) + { + diskReadTest = true; + } + + if (dataMB != 0) + { + blockCount = dataMB * 1024 * 1024 / blockBytes; + } + + for (int run = 0; run < (int)repeatCount; run++) + { + if (run != 0) + System.Threading.Thread.Sleep(1000 * (int)pauseSecs); + Tracing.Log(Tracing.Debug, "Starting diskrw run {0}", + (UIntPtr) run); + if (DoDevice(deviceName, run, blockCount, blockBytes, + diskLimitMB, randomIO, diskReadTest) != 0) + { + return -1; + } + Tracing.Log(Tracing.Debug, "Ending diskrw run {0}", + (UIntPtr) run); + } + return 0; + } + } +} diff --git a/base/Applications/Benchmarks/diskrwnull/diskrwnull.csproj b/base/Applications/Benchmarks/diskrwnull/diskrwnull.csproj new file mode 100644 index 0000000..43dd557 --- /dev/null +++ b/base/Applications/Benchmarks/diskrwnull/diskrwnull.csproj @@ -0,0 +1,28 @@ + + + + + + + Exe + diskrwnull + true + + + + + + + + + + + diff --git a/base/Applications/Benchmarks/diskrwnull/srandom.sg b/base/Applications/Benchmarks/diskrwnull/srandom.sg new file mode 100644 index 0000000..eb09ac7 --- /dev/null +++ b/base/Applications/Benchmarks/diskrwnull/srandom.sg @@ -0,0 +1,64 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// + + +using System; +using Microsoft.Contracts; + +namespace Microsoft.Singularity.Applications.Benchmarks.DiskRWNull +{ + /// + /// Low-cost Integer random number generator. The + /// implementation is based on the description of Park and + /// Miller's RNG on page 278 of Numerical Recipes in C, 2nd + /// Edition, by Press, Teukolsky, Vetterling, and Flannery. + /// + /// The same random number generator is used for our disk + /// benchmarks on other platforms. + /// + public class SRandom + { + public const int Maximum = 0x7fffffffu; + + const ulong m = 2147483647; + const ulong a = 16807; + const uint initialValue = 0x23456789; + uint last; + + public SRandom() + { + Reset(); + } + + [Delayed] + public void Reset() + { + last = initialValue; + } + + public int Next() + { + // Use 64-bit multiplication to preserve high bits. + ulong tmp = (a * last) % m; + last = (uint) tmp; + return (int)(last & Maximum); + } + + public static void Check() + { + const int test_iterations = 10000000; + SRandom r = new SRandom(); + int hash = 0; + for (int i = 0; i < test_iterations; i++) + { + int n = r.Next(); + System.Diagnostics.Debug.Assert(n != 0); + hash ^= n; + } + Console.Write("xor sum 1...{0} = {1}\n", test_iterations, hash); + System.Diagnostics.Debug.Assert(hash == 1080076236); + } + } +} diff --git a/base/Applications/Benchmarks/perfcnt/perfcnt.csproj b/base/Applications/Benchmarks/perfcnt/perfcnt.csproj new file mode 100644 index 0000000..c95bc4a --- /dev/null +++ b/base/Applications/Benchmarks/perfcnt/perfcnt.csproj @@ -0,0 +1,27 @@ + + + + + + + Exe + perfcnt + + + + + + + + + + + diff --git a/base/Applications/Benchmarks/perfcnt/perfcnt.sg b/base/Applications/Benchmarks/perfcnt/perfcnt.sg new file mode 100644 index 0000000..55a5abe --- /dev/null +++ b/base/Applications/Benchmarks/perfcnt/perfcnt.sg @@ -0,0 +1,439 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Perfcnt.cs +// + +using Microsoft.Singularity.Processor; +using System; +using System.Runtime.CompilerServices; +using System.Globalization; +using System.Threading; + +using Microsoft.Singularity.Channels; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications +{ + [ConsoleCategory(HelpMessage="HW performance counter utility", DefaultAction=true)] + internal class Parameters + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [BoolParameter( "k", Default=false, HelpMessage="Configure for kompute-bound counting.")] + internal bool doComputeBound; + + [BoolParameter( "g", Default=false, HelpMessage="Configure for general counting.")] + internal bool doGeneral; + + [BoolParameter( "i", Default=false, HelpMessage="Configure for I/O counting.")] + internal bool doIO; + + [BoolParameter( "t", Default=false, HelpMessage="Configure for TLB counting.")] + internal bool doTLB; + + [BoolParameter( "d", Default=false, HelpMessage="Configure for Data Cache counting.")] + internal bool doCache; + + [BoolParameter( ".", Default=false, HelpMessage="Simple test.")] + internal bool doDot; + + [BoolParameter( ",", Default=false, HelpMessage="Simple test.")] + internal bool doComma; + + [BoolParameter( "z", Default=false, HelpMessage="Simple test.")] + internal bool doZ; + + [BoolParameter( "s", Default=false, HelpMessage="Show counters.")] + internal bool doShow; + + [BoolParameter( "b", Default=false, HelpMessage="Configure for branch counting.")] + internal bool doBranch; + + [LongParameter( "e", Default=-1, HelpMessage="Configure performance counter 'n'.")] + internal long eventCounter; + + [LongParameter( "ev", Default=-1, HelpMessage="Configure event value 'v'.")] + internal long eventValue; + + [LongParameter( "p", Default=-1, HelpMessage="Read performance counter 'n'.")] + internal long counterReg; + + [LongParameter( "c", Default=-1, HelpMessage="Read CPUID function 'n'.")] + internal long cpuidReg; + + [LongParameter( "w", Default=-1, HelpMessage="Write 'v' to MSR 'n'.")] + internal long writeReg; + + [LongParameter( "wv", Default=-1, HelpMessage="Write 'v' to MSR 'n'.")] + internal long writeValue; + + [LongParameter( "r", Default=-1, HelpMessage="Read MSR 'n'.")] + internal long msrReg; + + reflective internal Parameters(); + + internal int AppMain() { + return Perfcnt.AppMain(this); + } + } + + [CLSCompliant(false)] + public struct PerfEvtSel + { + // Bits and Flags + public const uint CNT_MASK = 0xff000000; + public const uint INV = 0x00800000; + public const uint EN = 0x00400000; + public const uint INT = 0x00100000; + public const uint PC = 0x00080000; + public const uint E = 0x00040000; + public const uint OS = 0x00020000; + public const uint USR = 0x00010000; + public const uint UNIT_MASK = 0x0000ff00; + public const uint SELECTOR = 0x000000ff; + + // Common setting: Count all, but don't interrupt, + public const uint COUNT = (EN | PC | OS | USR); + // public const uint COUNT = (EN | PC | E | OS | USR); + + // Selector values. + public const uint DCacheRefillFromL2OrSys = 0x42; // Speculative + public const uint DCacheRefillFromSystem = 0x43; // Speculative + public const uint DtlbL1MissL2Hit = 0x45; // Speculative + public const uint DtlbL1MissL2Miss = 0x46; // Speculative + public const uint CyclesNotHalted = 0x76; // No E + public const uint RequestsToL2Cache = 0x7d; + public const uint L2CacheMiss = 0x7e; + public const uint ItlbL1MissL2Hit = 0x84; + public const uint ItlbL1MissL2Miss = 0x85; + public const uint RetiredInstructions = 0xc0; // No E + public const uint RetiredBranchInstructions = 0xc2; // No E + public const uint RetiredBranchesMispredicted = 0xc3; // No E + public const uint RetiredBranchesTaken = 0xc4; // No E + public const uint CyclesInterruptsMasked = 0xcd; // No E + public const uint CyclesInterruptsBlocked = 0xce; // No E + } + + public class Perfcnt + { + public static bool IsIntel; + public static bool IsAmd; + + public static ulong Parse(string! value) + { + if (value.StartsWith("0x") || value.StartsWith("0X")) { + return System.UInt64.Parse(value, NumberStyles.AllowHexSpecifier); + } + else { + return System.UInt64.Parse(value); + } + } + + public static void Reset(uint pmc, ulong value) + { + if (IsAmd) { + // Clear the event selector. + Processor.WriteMsr(0xc0010000 + pmc, 0); + // Clear the performance counter. + Processor.WriteMsr(0xc0010004 + pmc, 0); + // Enable the event selector. + Processor.WriteMsr(0xc0010000 + pmc, value); + } + } + + public static void ResetGlobalPerfCounters() + { + DebugStub.WritePerfCounter(0, 0); + DebugStub.WritePerfCounter(1, 0); + DebugStub.WritePerfCounter(2, 0); + DebugStub.WritePerfCounter(3, 0); + } + + public static void Clear() + { + Console.WriteLine("Clearing counters to zero."); + ResetGlobalPerfCounters(); + if (IsAmd) { + for (uint pmc = 0; pmc < 4; pmc++) { + Processor.WriteMsr(0xc0010004 + pmc, 0); + } + } + DebugStub.WritePerfCounter(7, Processor.GetCycleCount()); + } + + public static string EvtSelToString(ulong value) + { + switch (value & 0xff) { + case PerfEvtSel.DCacheRefillFromL2OrSys: return "DCache_Refill_L2"; + case PerfEvtSel.DCacheRefillFromSystem: return "DCache_Refill_Sys"; + case PerfEvtSel.DtlbL1MissL2Hit: return "DTLB_L2_Hit"; + case PerfEvtSel.DtlbL1MissL2Miss: return "DTBL_L2_Miss"; + case PerfEvtSel.CyclesNotHalted: return "CyclesNotHalted"; + case PerfEvtSel.RequestsToL2Cache: + if ((value & 0x400) != 0) { + return "TLB_L2_Requests"; + } + return "Req_L2_Cache"; + case PerfEvtSel.L2CacheMiss: + if ((value & 0x400) != 0) { + return "TLB_L2_Miss"; + } + return "L2_Cache_Miss"; + case PerfEvtSel.ItlbL1MissL2Hit: return "ITLB_L2_Hit"; + case PerfEvtSel.ItlbL1MissL2Miss: return "ITLB_L2_Miss"; + case PerfEvtSel.RetiredInstructions: return "Retired_Inst."; + case PerfEvtSel.RetiredBranchInstructions: return "Branches"; + case PerfEvtSel.RetiredBranchesMispredicted:return "Br_Mispredicted"; + case PerfEvtSel.RetiredBranchesTaken: return "Br_Taken"; + case PerfEvtSel.CyclesInterruptsMasked: return "Ints_Masked (cyc)"; + case PerfEvtSel.CyclesInterruptsBlocked: return "Ints_Blocked (cyc)"; + default: + return String.Format("{0:x16}", value); + } + } + + public static void DumpNow(bool config) + { + ulong b0 = DebugStub.ReadPerfCounter(7); + ulong t0 = Processor.GetCycleCount(); + ulong e0 = Processor.ReadMsr(0xc0010000); + ulong e1 = Processor.ReadMsr(0xc0010001); + ulong e2 = Processor.ReadMsr(0xc0010002); + ulong e3 = Processor.ReadMsr(0xc0010003); + ulong p0 = Processor.ReadPmc(0); + ulong p1 = Processor.ReadPmc(1); + ulong p2 = Processor.ReadPmc(2); + ulong p3 = Processor.ReadPmc(3); + ulong z0 = DebugStub.ReadPerfCounter(0); + ulong z1 = DebugStub.ReadPerfCounter(1); + ulong z2 = DebugStub.ReadPerfCounter(2); + ulong z3 = DebugStub.ReadPerfCounter(3); + + + t0 = t0 - b0; + + if (config) { + Console.WriteLine("evt: {0:x16} {1:x16} {2:x16} {3:x16}", e0, e1, e2, e3); + } + + Console.WriteLine("evt: {0,16} {1,16} {2,16} {3,16}", + EvtSelToString(e0), + EvtSelToString(e1), + EvtSelToString(e2), + EvtSelToString(e3)); + Console.WriteLine("pmc: {0:d16} {1:d16} {2:d16} {3:d16}", + p0, p1, p2, p3); + Console.WriteLine("pfc: {0:d16} {1:d16} {2:d16} {3:d16}", + z0, z1, z2, z3); + + DebugStub.WriteLine("evt: {0,16} {1,16} {2,16} {3,16} {4,16}", + __arglist("Cycles", + EvtSelToString(e0), + EvtSelToString(e1), + EvtSelToString(e2), + EvtSelToString(e3))); + DebugStub.WriteLine("pmc: {0:d16} {1:d16} {2:d16} {3:d16} {4:d16}", + __arglist(t0, p0, p1, p2, p3)); + DebugStub.WriteLine("pfc: {0:d16} {1:d16} {2:d16} {3:d16} {4:d16}", + __arglist(z0 + z1 + z2 + z3, z0, z1, z2, z3)); + } + + internal static int AppMain(Parameters! config) + { + // Temporaries for command-line parsing + uint eax; + uint ebx; + uint ecx; + uint edx; + + Processor.ReadCpuid(0, out eax, out ebx, out ecx, out edx); + if (ebx == 0x756e6547 && ecx == 0x6c65746e && edx == 0x49656e69) { + IsIntel = true; + } + else if (ebx == 0x68747541 && ecx == 0x444d4163 && edx == 0x69746e65) { + IsAmd = true; + } + + uint reg; + ulong val; + + if (config.eventCounter != -1) { // program event selector N. + reg = (uint) config.eventCounter; + val = (ulong) config.eventValue; + if (config.eventValue == -1) { + Console.WriteLine("Must specify both -en and -ev to configure an event."); + return -1; + } + Reset(reg, val); + Console.WriteLine("Reset pmc{0}:{1:x16}", reg, val); + } + + + if (config.counterReg != -1) { // read performance counter. + reg = (uint)config.counterReg; + val = Processor.ReadPmc(reg); + Console.WriteLine("read pmc{0}:{1:x16}", reg, val); + } + + if (config.doBranch) { // configure for branch evaluation. + ResetGlobalPerfCounters(); + Reset(0, PerfEvtSel.COUNT | PerfEvtSel.RetiredInstructions); + Reset(1, PerfEvtSel.COUNT | PerfEvtSel.RetiredBranchInstructions); + Reset(2, PerfEvtSel.COUNT | PerfEvtSel.RetiredBranchesMispredicted); + Reset(3, PerfEvtSel.COUNT | PerfEvtSel.RetiredBranchesTaken); + DebugStub.WritePerfCounter(7, Processor.GetCycleCount()); + } + + + if (config.doComputeBound) { // configure for compute-bound tasks. + ResetGlobalPerfCounters(); + Reset(0, PerfEvtSel.COUNT | PerfEvtSel.RetiredInstructions); + Reset(1, PerfEvtSel.COUNT | PerfEvtSel.RetiredBranchInstructions); + Reset(2, PerfEvtSel.COUNT | PerfEvtSel.RequestsToL2Cache | 0x400); + Reset(3, PerfEvtSel.COUNT | PerfEvtSel.L2CacheMiss | 0x300); + DebugStub.WritePerfCounter(7, Processor.GetCycleCount()); + } + + if (config.doGeneral) { // configure for General evaluation. + ResetGlobalPerfCounters(); + Reset(0, PerfEvtSel.COUNT | PerfEvtSel.CyclesNotHalted); + Reset(1, PerfEvtSel.COUNT | PerfEvtSel.RetiredInstructions); + Reset(2, PerfEvtSel.COUNT | PerfEvtSel.CyclesInterruptsMasked); + Reset(3, PerfEvtSel.COUNT | PerfEvtSel.RequestsToL2Cache | 0x400); + DebugStub.WritePerfCounter(7, Processor.GetCycleCount()); + } + + if (config.doIO) { // configure for I/O counting. + ResetGlobalPerfCounters(); + Reset(0, PerfEvtSel.COUNT | PerfEvtSel.CyclesNotHalted); + Reset(1, PerfEvtSel.COUNT | PerfEvtSel.RetiredInstructions); + Reset(2, PerfEvtSel.COUNT | PerfEvtSel.CyclesInterruptsMasked); + Reset(3, PerfEvtSel.COUNT | PerfEvtSel.CyclesInterruptsBlocked); + DebugStub.WritePerfCounter(7, Processor.GetCycleCount()); + } + + if (config.doTLB) { // configure for TLB counting. + // Just count TLB page walks on L2 Cache. + ResetGlobalPerfCounters(); + Reset(0, PerfEvtSel.COUNT | PerfEvtSel.RequestsToL2Cache | 0x400); + Reset(1, PerfEvtSel.COUNT | PerfEvtSel.L2CacheMiss | 0x400); + Reset(2, PerfEvtSel.COUNT | PerfEvtSel.DtlbL1MissL2Hit); + Reset(3, PerfEvtSel.COUNT | PerfEvtSel.DtlbL1MissL2Miss); + DebugStub.WritePerfCounter(7, Processor.GetCycleCount()); + } + + if (config.doCache) { // Data Cache + // Just count TLB page walks on L2 Cache. + ResetGlobalPerfCounters(); + Reset(0, PerfEvtSel.COUNT | PerfEvtSel.RequestsToL2Cache | 0x300); + Reset(1, PerfEvtSel.COUNT | PerfEvtSel.L2CacheMiss | 0x300); + Reset(2, PerfEvtSel.COUNT | PerfEvtSel.DCacheRefillFromSystem | 0x1f00); + Reset(3, PerfEvtSel.COUNT | PerfEvtSel.DCacheRefillFromL2OrSys); + DebugStub.WritePerfCounter(7, Processor.GetCycleCount()); + } + + if (config.cpuidReg != -1) { // read cpuid. + reg = (uint)config.cpuidReg; + uint v0; + uint v1; + uint v2; + uint v3; + Processor.ReadCpuid(reg, out v0, out v1, out v2, out v3); + Console.WriteLine("read cpuid{0:x8}:{1:x8}.{2:x8}.{3:x8}.{4:x8}", + reg, v0, v1, v2, v3); + } + + if (config.msrReg != -1) { // read msr. + reg = (uint)config.msrReg; + if (reg == 0) { + Console.WriteLine("Invalid read msr: {0}", reg); + } + else { + val = Processor.ReadMsr(reg); + Console.WriteLine("read msr{0:x8}:{1:x16}", reg, val); + } + } + + if (config.writeReg != -1 ) { // write msr. + if (config.writeValue == -1) { + Console.WriteLine("Invalid write msr: reg={0:x}, value{1:x}", config.writeReg, config.writeValue); + return -1; + } + reg = (uint)config.writeReg; + val = (ulong) config.writeValue; + Console.WriteLine("write msr{0:x8}:{1:x16}", reg, val); + Processor.WriteMsr(reg, val); + } + + if (config.doDot) { //Simple test. + Clear(); + int yy = 0; + int sign = 0; + for (int zz = 0; zz < 100000; zz++) { + sign *= -1; + yy = yy + sign; + } + DumpNow(true); + } + + if (config.doComma) { //Simple test. + Clear(); + int yy = 0; + int sign = 0; + for (int zz = 0; zz < 100000; zz++) { + sign *= -1; + yy = yy + sign; + } + Thread.Sleep(2); + DumpNow(true); + } + + if (config.doZ) { //Simplest test. + // Clear the event selectors. + Processor.WriteMsr(0xc0010000, 0); + Processor.WriteMsr(0xc0010001, 0); + // Clear the performance counters. + Processor.WriteMsr(0xc0010004, 0); + Processor.WriteMsr(0xc0010005, 0); + // Enable the event selectors. + Processor.WriteMsr(0xc0010000, 0x4f00c0); + Processor.WriteMsr(0xc0010001, 0x4f00c2); + + int yy = 0; + int sign = 1; + for (int zz = 0; zz < 100000; zz++) { + sign *= -1; + yy = yy + sign; + } + + ulong p0 = Processor.ReadPmc(0); + ulong p1 = Processor.ReadPmc(1); + Console.WriteLine("retired instrcts: {0}", p0); + Console.WriteLine("retired branches: {0}", p1); + } + + if (false /* FIXFIX need a really long check here */) { + DumpNow(false); + } + + if (config.doShow /* FIXFIX need a really long check here */) { + DumpNow(false); + } + + return 0; + } + } +} diff --git a/base/Applications/Benchmarks/sharpSAT/AssemblyInfo.cs b/base/Applications/Benchmarks/sharpSAT/AssemblyInfo.cs new file mode 100644 index 0000000..f2358ca --- /dev/null +++ b/base/Applications/Benchmarks/sharpSAT/AssemblyInfo.cs @@ -0,0 +1,58 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +// +[assembly: AssemblyTitle("")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("Copyright (c) Microsoft Corporation. All rights reserved.")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: + +[assembly: AssemblyVersion("1.0.*")] + +// +// In order to sign your assembly you must specify a key to use. Refer to the +// Microsoft .NET Framework documentation for more information on assembly signing. +// +// Use the attributes below to control which key is used for signing. +// +// Notes: +// (*) If no key is specified, the assembly is not signed. +// (*) KeyName refers to a key that has been installed in the Crypto Service +// Provider (CSP) on your machine. KeyFile refers to a file which contains +// a key. +// (*) If the KeyFile and the KeyName values are both specified, the +// following processing occurs: +// (1) If the KeyName can be found in the CSP, that key is used. +// (2) If the KeyName does not exist and the KeyFile does exist, the key +// in the KeyFile is installed into the CSP and used. +// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility. +// When specifying the KeyFile, the location of the KeyFile should be +// relative to the project output directory which is +// %Project Directory%\obj\. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] diff --git a/base/Applications/Benchmarks/sharpSAT/base_solver.cs b/base/Applications/Benchmarks/sharpSAT/base_solver.cs new file mode 100644 index 0000000..f2ef7f8 --- /dev/null +++ b/base/Applications/Benchmarks/sharpSAT/base_solver.cs @@ -0,0 +1,7855 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +/////////////////////////////////////////////////////////////////////////////// + +//#define CHECK +#define GEN_RESOLVE_TRACE + +using System; +using System.IO; +using System.Collections; +using System.Diagnostics; + +//using Microsoft.Zap; +namespace SharpSAT +{ + /// + /// Summary description for Class1. + /// + + public class SharpSATSolver : SATCommon + { + public SolverStats stats; + internal SATHook hook; + internal SolverParams parameters; + + private int unique_id; //the unique id seen so far for the nodes + private IntVector active_area; + + //private Process currentProcess = Process.GetCurrentProcess(); + internal VarVector variables = new VarVector(4); + internal ClsVector clauses = new ClsVector(4); + private ObjVector watched_clauses = new ObjVector(4); + private IntVector free_clauses = new IntVector(4); + + internal IntVector original_clauses= new IntVector(4); + + private NodeHashMap node_hash = new NodeHashMap(); + private FreeList free_nodes; + private IntVector zero_ref_nodes = new IntVector(4); + private int constant_one; + + private MyHashtable node_to_pi_hash = new MyHashtable(); + internal IntVector primary_inputs = new IntVector(4); + + private ObjVector asgn_stack = new ObjVector(4); + private int dlevel = 0; + private Queue implication_queue = new Queue(); + private IntVector conflict_array = new IntVector(4); + private IntVector learned_clause = new IntVector(4); + + private IntVector conflict_clauses= new IntVector(128); + private IntVector ordered_vars = new IntVector(4); + private int max_score_pos = 0; + + private IntVector temporary_clauses= new IntVector(16); + private ResolutionTrace rtrace = null; + + [Microsoft.Contracts.NotDelayed] + internal SharpSATSolver() + { + stats = new SolverStats(true); + parameters = new SolverParams(true); + rtrace = new ResolutionTrace(this); + variables = new VarVector(4); + asgn_stack = new ObjVector(4); + watched_clauses = new ObjVector(4); + free_nodes = new FreeList(variables); + //create Variable Num. 0: Constant 1 + int s = new_node(NodeType.CONSTANT, INVALID, INVALID); + sharp_assert (s == 0); + asgn_stack.push_back (new IntVector(4)); //for decision level 0 + constant_one = s; + primary_inputs = new IntVector(4); + + stats.num_free_branch_vars = 0; //i.e. signal 0 doesn't count; + stats.num_free_variables = 0; + stats.next_restart = parameters.first_restart; + stats.next_gc = parameters.gc_period; + stats.next_decay = parameters.decay_period; + + active_area = new IntVector(128); + reasoning_flag = alloc_flag(); + marked_flag = alloc_flag(); + branchable_flag = alloc_flag(); + in_cl_flag = alloc_flag(); + in_cl_sign_flag = alloc_flag(); + active_flag = alloc_flag(); + } + + int canonical(int s) + { + bool invert = false; + int r; + for (r = s; variable(NODE_ID(r)).canonical != INVALID; r = variable(NODE_ID(r)).canonical) + if (IS_NEGATED(s)) + invert = !invert; + if (invert) + return NEGATE (r) ; + else + return r; + } + + internal int var_value (int i) { return variable(i).varValue; } + internal void var_set_value (int i, short v) { variable(i).varValue = v; } + internal int var_dlevel (int i) { return variable(i).dlevel; } + internal Variable variable (int i ) { return /*(Variable)*/ variables[i]; } + internal Variable node (int sig) { return variable(VID(sig)); } + internal int num_variables() { return variables.size() - 1; } + internal int lit_value (int s) { return var_value(VID(s)) ^ SIGN(s);} + internal Clause clause(int idx) { return /*(Clause)*/ clauses[idx]; } + internal IntVector watched_by(int svar ) { return (IntVector) watched_clauses[svar]; } + internal IntVector assignment_stack (int l) { return (IntVector) asgn_stack[l]; } + internal ObjVector assignment_stack(){ return asgn_stack; } + internal int num_pi() { return primary_inputs.size(); } + internal int pi(int n) { return primary_inputs[n]; } + internal bool is_pi (int n) { return node(n).is_pi(); } + internal bool is_gate (int n) { return node(n).is_gate(); } + internal int one() { return constant_one; } + internal int zero() { return NEGATE(constant_one); } + internal int signal_of(int vid) { return vid + vid; } + internal int node_to_pi(int s) { return (int) node_to_pi_hash[NON_NEGATED(s)]; } + internal NodeType node_type (int s) { return node(s).type; } + internal int pi_var_value(int k) { return variable(pi(k)).varValue; } + internal bool is_pure_clause_based() { return num_variables() == stats.num_cls_vars; } + internal int d_level() { return dlevel; } + + internal double session_cpu_time() { return get_cpu_time() - stats.start_cpu_time; } + internal double total_cpu_time() { return stats.total_cpu_time; } + + internal void enable_rtrace(bool e) { rtrace.enable_trace(e); } + + #region GID_MANAGEMENT + + private int allocated_gid; + + internal int volatile_gid() { return 0; } + + internal int alloc_gid () + { + for (ushort i=1; i<= WORD_WIDTH; ++i) + if (is_gid_allocated(i) == false) + { + allocated_gid |= (ushort) (1 << (i-1)); + return i; + } + fatal(); + return volatile_gid(); + } + + internal void free_gid (int gid) + { + sharp_assert (gid > 0 && gid <= WORD_WIDTH); + if (is_gid_allocated(gid)==false) + { + fatal(); + } + allocated_gid &= (~(1<< (gid-1))); + } + + internal bool is_gid_allocated(int gid) + { + if (gid==volatile_gid()) + return true; + sharp_assert (gid<= WORD_WIDTH && gid > 0); + if ((allocated_gid & (1 << (gid -1))) != 0) + return true; + return false; + } + + #endregion + + #region VAR_FLAG_MANAGEMENT + + private int allocated_flag = 0; + + internal int alloc_flag() + { + for (int i=0; i< WORD_WIDTH; ++i) + { + if ((allocated_flag & (1 << i)) == 0) + { + allocated_flag |= (1< 1) + { + int max_idx = -1, max2_idx = -1, max_dl = -1, max2_dl = -1; + for (int i=0; i< cl.num_lits; ++i) + { + int dl = var_dlevel(cl.literal(i) >> 1); + if (dl < 0 || (lit_value(cl.literal(i)) == 1) ) //non-0 variable, so make it the highest possible dl + dl = num_variables() + 1; + if (dl > max_dl) + { + max2_idx = max_idx; + max_idx = i; + max2_dl = max_dl; + max_dl = dl; + } + else if (dl > max2_dl) + { + max2_idx = i; + max2_dl = dl; + } + } + //the invariance: Literal 0 and 1 are watched + int temp = cl.literal(0); + cl.literals[0] = cl.literal(max_idx); + cl.literals[max_idx] = temp; + int svar = cl.literal(0); + watched_by(svar).push_back ( cl_id + cl_id ); + if (max2_idx == 0) + max2_idx = max_idx; + temp = cl.literal(1); + cl.literals[1] = cl.literal(max2_idx); + cl.literals[max2_idx] = temp; + svar = cl.literal(1); + watched_by(svar).push_back ( cl_id + cl_id + 1); + } + } + + void remove_cl_from_reasoning (int cl_id) + { + Clause cl = clause(cl_id); + sharp_assert (cl.num_lits > 1); + for (int k=0; k < 2; ++k) + { //two watched + int lit = cl.literal(k); + IntVector watch = watched_by(lit); + int i, sz; + for (i=0, sz = watch.size(); i < sz; ++i) + { + if (( watch[i] >> 1) == cl_id) + { //found it + watch[i] = watch.back; + watch.pop_back(); + break; + } + } + } + } + + private void incr_lits_count (int lit) + { + if ((lit & 1) == 1) + ++ variable (VID(lit)).lits_count_1; + else + ++ variable (VID(lit)).lits_count_0; + } + + private void decr_lits_count (int lit) + { + if ((lit & 1) == 1) + -- variable (VID(lit)).lits_count_1; + else + -- variable (VID(lit)).lits_count_0; + } + + private int get_free_clause_id() + { + int cl_id; + if (!free_clauses.empty()) + { + cl_id = free_clauses.back; + free_clauses.pop_back(); + clauses[cl_id] = new Clause(); + } + else + { + cl_id = clauses.size(); + clauses.push_back (new Clause()); + } + return cl_id; + } + + private int add_clause_to_db (int [] lits, ClType tp, ushort gflag) + { + sharp_assert (lits.Length > 0); + int cl_id = get_free_clause_id(); + Clause cl = clause(cl_id); + cl.init( tp, lits, gflag, unique_id ++); + +// Console.Write("{0} :", cl_id); +// for (int i=0; i< lits.Length; ++i) +// Console.Write ("{0} ", lits[i]); +// Console.WriteLine (""); + + for (int i=0; i< cl.num_lits; ++i ) + { + incr_lits_count (cl.literal(i)); + reference (cl.literal(i)); + } + + if (tp == ClType.ORIGINAL) + { + ++ stats.num_orig_clauses; + original_clauses.push_back(cl_id); + stats.num_orig_literals += lits.Length; + } + else if (tp == ClType.CONFLICT) + { + ++ stats.num_learned_clauses; + conflict_clauses.push_back (cl_id); + stats.num_learned_literals += lits.Length; + } + include_cl_in_reasoning (cl_id); + + return cl_id; + } + + internal int add_new_implication (int [] reasons, int implied_lit) + { + if (reasons == null) + { + reasons = new int[dlevel]; + for (int i=0; i< reasons.Length; ++i) + reasons[i] = (assignment_stack(i+1)[0]^1); + } + + for (int i =0; i< reasons.Length; ++i) + sharp_assert (lit_value(reasons[i]) == 0); + sharp_assert (var_value(VID(implied_lit)) == UNKNOWN); + + int cl_id = get_free_clause_id(); + + Clause cl = clause(cl_id); + int [] lits = new int [1 + reasons.Length]; + Array.Copy(reasons,lits,reasons.Length); + lits[reasons.Length] = implied_lit; + + cl.init( ClType.TEMP, lits, 0, unique_id ++); + temporary_clauses.push_back(cl_id); + + queue_implication(implied_lit, cl_id, ImpType.CLAUSE); + return cl_id; + } + + internal int merge_clause_group(int g2, int g1) + { + for (int i=0, sz=clauses.size(); i 1) +// remove_cl_from_reasoning (cl_id); +// +// +// for (int i=0; i< cl.num_lits; ++i) +// -- variable(cl.literal(i)>> 1).lits_count[cl.literal(i) & 1]; +// +// ++stats.num_deleted_clauses; +// stats.num_deleted_literals += cl.num_lits; +// if (cl.type == ClType.ORIGINAL) +// { +// --stats.num_orig_clauses; +// stats.num_orig_literals -= cl.num_lits; +// // for (int j=0, n = clause(cl_id).num_lits; j < n ; ++j) +// // deref (clause(cl_id).literal(j)); +// } +// else +// { +// sharp_assert (cl.type == ClType.CONFLICT); +// --stats.num_learned_clauses; +// stats.num_learned_literals -= cl.num_lits; +// } +// //cl.type = ClType.DELETED; +// clauses[cl_id] = null; +// free_clauses.push_back(cl_id); +// } + + void clean_up() + { + reset(); + bool [] remove = new bool [clauses.size()]; + for (int i=0; i< clauses.size(); ++i) + { + Clause cl = clause(i); + if (cl != null && cl.type == ClType.CONFLICT) + remove[i] = true; //to be deleted + else + remove[i] = false; + } + delete_clauses(remove, false); + rtrace.reset(); + } + + //convert all variables to primary inputs + internal void convert_vars_to_pi () + { + for (int i=0; i< variables.size(); ++i) + { + if (variable(i).type == NodeType.VARIABLE) + { + int id = num_pi(); + int s = i + i; + node(s).type = NodeType.PI; + primary_inputs.push_back(s); + node_to_pi_hash[s] = id; + } + } + } + + void delete_clauses(bool [] removes) + { + delete_clauses(removes, true); +// Console.Write ("Remove : "); +// for (int i=0; i< removes.Length; ++i) +// if (removes[i]) +// Console.Write("{0} ", i); +// Console.WriteLine(""); + } + + void delete_clauses(bool[] removes, bool delete_original) + { + for (int i=1; i< variables.size(); ++i) + { + //Variable var = variable(i); + for (int k=0; k< 2; ++k) + { + IntVector w = watched_by(i + i + k); + for (int j=0; j< w.size(); ++j) + if ( removes[(w[j] >> 1)]) + { + w[j] = w.back; + w.pop_back(); + --j; + } + } + } + + for (int i=0; i< temporary_clauses.size(); ++i) + { + int cl_id = temporary_clauses[i]; + bool can_delete = true; + foreach (int lit in clause(cl_id).literals) + { + if (variable(VID(lit)).antecedent.type == ImpType.CLAUSE && + variable(VID(lit)).antecedent.index == cl_id) + { + can_delete = false; + break; + } + } + if (can_delete) + { + clauses[cl_id] = null; + temporary_clauses[i] = temporary_clauses.back; + temporary_clauses.pop_back(); + --i; + } + } + + for (int i=0; i< removes.Length; ++i) + { + Clause cl = clause(i); + if (cl == null || removes[i] == false) + continue; + + ++ stats.num_deleted_clauses; + stats.num_deleted_literals += cl.num_lits; + + for (int j=0; j< cl.num_lits; ++j) + { + decr_lits_count(cl.literal(j)); + deref ( cl.literal(j)); + } + + if (cl.type == ClType.ORIGINAL) + { + --stats.num_orig_clauses; + stats.num_orig_literals -= cl.num_lits; + } + else if (cl.type == ClType.CONFLICT) + { + --stats.num_learned_clauses; + stats.num_learned_literals -= cl.num_lits; + } + //cl.type = ClType.DELETED; + clauses[i] = null; + free_clauses.push_back(i); + } + + IntVector temp = new IntVector(128); + for (int i=0; i< conflict_clauses.size(); ++i) + { + int cl_id = conflict_clauses[i]; + if (clause(cl_id) != null) + { + sharp_assert (clause(cl_id).type == ClType.CONFLICT); + temp.push_back (cl_id); + } + } + conflict_clauses = temp; + + if (delete_original) + { + stats.active_area_changed = true; + IntVector temp1 = new IntVector(16); + for (int i=0; i< original_clauses.size(); ++i) + { + int cl_id = original_clauses[i]; + if (!removes[cl_id]) + temp1.push_back(cl_id); + } + original_clauses = temp1; + } + } + + + internal int constraint (int sig) + { + if (sig == one()) //don't constraint constants + return 0; + else if (sig == zero()) + { + stats.constraint_zero ++; + return -1; + } + int gid = alloc_gid(); + int[] cls = new int[1]; + cls[0] = sig; + add_clause(cls, gid, false); + return gid; + } + + internal void release_constraint (int gid) + { + if (gid <= 0) + { + if (gid < 0) + stats.constraint_zero --; + return; + } + sharp_assert (is_gid_allocated(gid)); + int orig = stats.num_orig_clauses; + delete_clause_group (gid); + sharp_assert (orig == stats.num_orig_clauses + 1); + } + + int find_max_dl(int cl_id) { return find_max_dl (clause(cl_id)); } + + int find_max_dl (Clause cl) + { + int max_dl = 0; + + for (int i=0; i< cl.num_lits; ++i) + { + int lit = cl.literal(i); + if (variable(lit>>1).dlevel > max_dl) + max_dl = variable(lit>>1).dlevel; + } + return max_dl; + } + + int find_unit_lit(int cl_id) { return find_unit_lit (clause(cl_id)); } + int find_unit_lit (Clause cl) + { + if (cl == null) + throw new Exception ("Null Clause"); + if (!is_unit(cl)) + return 0; + int v1 = var_value(cl.literal(0)>>1); + if (v1 == UNKNOWN) + return cl.literal(0); + else + return cl.literal(1); + } + + bool is_conflicting (int cl_id) { return is_conflicting (clause(cl_id)); } + + bool is_conflicting(Clause cl) + { + if (lit_value(cl.literal(0)) == 0 && + ( cl.num_lits == 1 || lit_value(cl.literal(1)) == 0) ) + return true; + return false; + } + + bool is_satisfied (int cl_id ) { return is_satisfied (clause(cl_id)); } + + bool is_satisfied(Clause cl) + { + for (int i=0; i< cl.num_lits; ++i) + if (lit_value(cl.literal(i)) == 1) + return true; + return false; + } + + bool is_unit (int cl_id) { return is_unit(clause(cl_id)); } + + bool is_unit(Clause cl) + { + if (cl.num_lits == 1) + { + if (var_value(cl.literal(0)>>1) == UNKNOWN) + return true; + else + return false; + } + else + { + int v1 = var_value(cl.literal(0)>>1); + int l1 = lit_value(cl.literal(0)); + int v2 = var_value(cl.literal(1)>>1); + int l2 = lit_value(cl.literal(1)); + if ((v1 == UNKNOWN && l2 == 0) || + (v2 == UNKNOWN && l1 == 0)) + return true; + else + return false; + } + } + + int find_free_node_index(int i1, int i2) + { + //find a free node index that is larger than the index of i1 and i2 + int at_least; + if (i1 == INVALID || i2 == INVALID) + { + sharp_assert (i1 == INVALID && i2 == INVALID); + at_least = -1; + } + else + at_least = (i1>i2)? (i1>> 1): (i2>> 1); + + int idx = free_nodes.find_greater_than (at_least); + int vid; + if (idx < 0) + { + //can't find it, so enlarge the node array + variables.push_back(new Variable()); + watched_clauses.push_back (new IntVector(4)); + watched_clauses.push_back (new IntVector(4)); + vid = variables.size() - 1; + } + else + vid = idx; + sharp_assert (vid > at_least); + return vid; + } + + internal int add_variable() + { + ++ stats.num_cls_vars; + int sig = new_node (NodeType.VARIABLE, INVALID, INVALID); + return VID(sig); + } + + internal void set_num_variables(int k) + { + while ( num_variables() < k) + add_variable(); + } + + void sort_var_score () + { + int nvar = ordered_vars.size(); + int [] scores = new int [nvar]; + int [] ordered = new int [nvar]; + for (int i=0; i< ordered_vars.size(); ++i) + { + scores[i] = variable(ordered_vars[i]).score(); + ordered[i] = ordered_vars[i]; + } + + Array.Sort(scores, ordered); + for (int i=0; i< nvar; ++i) //reverse it + ordered_vars[i] = ordered[nvar - i - 1]; + + for (int i=0; i< nvar; ++i) + { + int vid = ordered_vars[i]; + variable(vid).ordered_pos = i; + } + max_score_pos = 0; + for (int i=1; i< ordered_vars.size(); ++i) + sharp_assert (variable(ordered_vars[i]).score() <= variable(ordered_vars[i-1]).score()); + } + + void incr_score (int svar) + { + if (SIGN(svar) == 0) + ++ variable(VID(svar)).score_0; + else + ++ variable(VID(svar)).score_1; + } + + void incr_var_score( int svar) + { + int vid = VID(svar); + //int sign = SIGN(svar); + int old_score = variable(vid).score(); + incr_score (svar); + int new_score = variable(vid).score(); + if (old_score == new_score) + return; + + int pos = variable(vid).ordered_pos; + int orig_pos = pos; + sharp_assert (ordered_vars[pos] == vid); + int bubble_step = 0x400; + for (pos = orig_pos - bubble_step; pos >= 0; pos -= bubble_step) + if (variable(ordered_vars[pos]).score() >= new_score) + break; + pos += bubble_step; + for ( bubble_step = (bubble_step >> 1); bubble_step > 0; bubble_step = (bubble_step >> 1)) + { + if ( pos - bubble_step >= 0) + { + if (variable(ordered_vars[pos - bubble_step]).score() < new_score) + pos -= bubble_step; + } + } + //now found the position, do a swap + ordered_vars[orig_pos] = ordered_vars[pos]; + variable(ordered_vars[orig_pos]).ordered_pos = orig_pos; + + ordered_vars[pos] = vid; + variable(ordered_vars[pos]).ordered_pos = pos; +#if CHECK + for (int i=0; i< ordered_vars.size(); ++i) + { + sharp_assert (i==0 || variable(ordered_vars[i]).score() <= variable(ordered_vars[i - 1]).score()); + sharp_assert (variable(ordered_vars[i]).ordered_pos == i); + } +#endif + } + + int new_node(NodeType tp, int i1, int i2) + { + int vid = find_free_node_index(i1, i2); + Variable n = variable(vid); + + n.clear_all_flag(); + n.clear_all_gid(); + + clear_marked(n); + n.set_flag(branchable_flag); + n.clear_flag(in_cl_flag); + n.clear_flag(in_cl_sign_flag); + n.clear_flag(reasoning_flag); + + n.type = tp; + n.left = i1; + n.right = i2; + n.canonical = INVALID; + n.ref_count = 0; + n.lits_count_0 = 0; + n.lits_count_1 = 0; + n.uid = unique_id ++; + + n.score_0 = 0; + n.score_1 = 0; + n.asgn_pos = -1; + + n.varValue = UNKNOWN; + n.antecedent = -1; + n.dlevel = -1; + n.outputs.clear(); + + ++ stats.num_free_variables; + ++ stats.num_free_branch_vars; + + if (tp == NodeType.AND || tp == NodeType.XOR) + { + set_reasoning(n); + make_node_consistent(vid + vid); + if (tp == NodeType.AND) + { + n.score_0 += 1; + n.score_1 += 2; + ++node(i1).score_0; + ++node(i1).score_1; + ++node(i2).score_0; + ++node(i2).score_1; + } + else + { + sharp_assert (tp == NodeType.XOR); + n.score_0 += 2; + n.score_1 += 2; + node(i1).score_0 += 2; + node(i1).score_1 += 2; + node(i2).score_0 += 2; + node(i2).score_1 += 2; + } + } + return vid + vid; + } + + int [] remove_dup_literals(int [] orig_lits) + { + bool redundant = false; + IntVector literals = new IntVector(4); + for (int i=0; i< orig_lits.Length; ++i) + { + int l = orig_lits[i]; + if (l == 0) //i.e. constant 1 + { + redundant = true; + break; + } + else if ( l == 1) //i.e. constant 0 + continue; + + Variable var = variable(l >>1); + if (var.flag(in_cl_flag) == false) //never occurred + { + var.set_flag(in_cl_flag); + if (IS_NEGATED(l)) + var.set_flag(in_cl_sign_flag); + else + var.clear_flag(in_cl_sign_flag); + literals.push_back(l); + } + else if (var.flag(in_cl_sign_flag) == IS_NEGATED(l)) //same phase + continue; + else + redundant = true; + } + //reset back + for (int i=0; i< orig_lits.Length; ++i) + { + variable(VID(orig_lits[i])).clear_flag(in_cl_flag); + variable(VID(orig_lits[i])).clear_flag(in_cl_sign_flag); + } + if (redundant) + return null; + return literals.ToArray(); + } + + int add_clause_do_implication ( int [] lits, ClType tp, ushort gflag) + { + int cl_id = add_clause_to_db( lits, tp, gflag); + + if (stats.been_reset == false) // may cause implication + { + Clause cl = clause(cl_id); + if (is_conflicting(cl)) + { + int dl = find_max_dl(cl); + backtrack(dl-1); + } + if (dlevel >= 0) + { + int unit = find_unit_lit(cl); + if (unit != 0) + { + int l = find_max_dl(cl); + if (l < dlevel) + backtrack(l); + queue_implication(unit, cl_id, ImpType.CLAUSE); + } + } + else + stats.outcome = SATStatus.UNSATISFIABLE; + } + return cl_id; + } + + int add_clause_with_gflag ( int[] orig_lits, ClType tp, ushort gflag, bool do_check ) + { + sharp_assert (conflict_array.empty()); + + int[] lits; + if (do_check) + lits = remove_dup_literals(orig_lits); + else + lits = orig_lits; + + if (lits == null) + throw new Exception (" A clause contain a literal and its negation"); + else if (lits.Length == 0) + throw new Exception("An empty clause occurred in the original clauses"); + + int cl_id = add_clause_do_implication ( lits, tp, gflag); + return cl_id; + } + + int add_blocking_clause (int [] lits, int gid) + { + ushort gflag = 0; + if (gid > 0) + gflag = (ushort)(1<<(gid-1)); + foreach(int lit in lits) + sharp_assert (is_active(node(lit))); + return add_clause_with_gflag (lits, ClType.BLOCKING, gflag, true); + } + + internal int add_clause (int [] lits) + { + return add_clause (lits, 0, true); + } + + internal int add_clause (int [] lits, int gid) + { + return add_clause (lits, gid, true) ; + } + + internal int add_clause (int [] lits, int gid, bool do_check) + { + ushort gflag = 0; + if (gid > 0) + gflag = (ushort)(1<<(gid-1)); + foreach(int lit in lits) + { + if (!is_active(node(lit))) + { + stats.active_area_changed = true; + break; + } + } + return add_clause_with_gflag (lits, ClType.ORIGINAL, gflag, do_check); + } + + int add_learned_clause(int[] lits, ushort gflag) + { + int cl_id = add_clause_to_db( lits, ClType.CONFLICT, gflag); + rtrace_record_resolve_process (clause(cl_id).uid); + return cl_id; + } + + internal void set_branchable(int vid, bool br) + { + sharp_assert ( !stats.is_solving ); + Variable var = variable(vid); + if (br && !is_branchable(var)) + { + set_branchable(var); + if (var_value(vid) == UNKNOWN) + ++ stats.num_free_branch_vars; + } + else if ( !br && is_branchable(var)) + { + clear_branchable(var); + if (var_value(vid) == UNKNOWN) + -- stats.num_free_branch_vars; + } + } + + internal void restart() + { + conflict_array.clear(); + implication_queue.Clear(); + if (dlevel > 0) + backtrack(0); + ++stats.num_restarts; + } + + void run_garbage_collection() + { + bool[] remove = new bool [clauses.size()]; + for (int i=0; i< remove.Length; ++i) + remove[i] = false; + + int headcount = conflict_clauses.size() / parameters.gc_head_tail_ratio; + for (int i=0; i< headcount; ++i) + { + int cl_id = conflict_clauses[i]; + Clause cl = clause(cl_id); + sharp_assert (cl.type == ClType.CONFLICT); + if (cl.activity > parameters.gc_head_threshold) + continue; + int num_0 = 0; + for (int j=0; j< cl.num_lits; ++j) + if (lit_value(cl.literal(j)) == 0) + ++ num_0; + if (cl.num_lits - num_0 < parameters.gc_head_length) + continue; + remove[cl_id] = true; + } + for (int i=headcount; i< conflict_clauses.size(); ++i) + { + int cl_id = conflict_clauses[i]; + Clause cl = clause(cl_id); + sharp_assert (cl.type == ClType.CONFLICT); + if (cl.activity > parameters.gc_tail_threshold) + continue; + int num_0 = 0; + for (int j=0; j< cl.num_lits; ++j) + if (lit_value(cl.literal(j)) == 0) + ++ num_0; + if (cl.num_lits - num_0 < parameters.gc_tail_length) + continue; + remove[cl_id] = true; + } + + delete_clauses(remove, false); + ++ stats.num_garbage_collections; + } + + void decay_variable_score() + { + for(int i=1, sz = variables.size(); i> 1); + var.score_1 = (short)(var.score_1 >> 1); + } + } + + void run_periodic_functions() + { + //a. restart + if (parameters.enable_restart && stats.num_backtracks > stats.next_restart) + { + //System.Console.Write ("-"); + stats.next_restart = stats.num_backtracks + parameters.restart_period; + restart(); + } + //b. delete clauses + if (parameters.enable_gc && stats.num_backtracks > stats.next_gc) + { + //System.Console.Write ("*"); + stats.next_gc = stats.num_backtracks + parameters.gc_period; + run_garbage_collection(); + } + //c. decay variable score + if (stats.num_backtracks > stats.next_decay) + { + stats.next_decay = stats.num_backtracks + parameters.decay_period; + decay_variable_score(); + } + } + + internal void make_decision (int svar) + { + sharp_assert(implication_queue.Count == 0); + sharp_assert (svar > 0 && var_value(svar>>1) == UNKNOWN); + ++ dlevel; + + sharp_assert (stats.max_dlevel == asgn_stack.size() - 1); + if (dlevel > stats.max_dlevel) + stats.max_dlevel = dlevel; + if (asgn_stack.size() <= dlevel) + asgn_stack.push_back (new IntVector(32) ); + + queue_implication(svar, -1, ImpType.NONE); + ++ stats.num_decisions; + } + + bool make_branch_decision() + { + if (implication_queue.Count != 0) + return ((( Implication)(implication_queue.Peek())).lit > 1 ); + + if (stats.num_free_branch_vars == 0) + return false; + + int svar = 0; + + for ( ; max_score_pos < ordered_vars.size(); ++ max_score_pos ) + { + int vid = ordered_vars[max_score_pos]; + if (variable(vid).varValue == UNKNOWN && is_branchable(variable(vid))) + { + if (variable(vid).score_0 > variable(vid).score_1) + svar = vid + vid; + else + svar = vid + vid + 1; + break; + } + } + if (svar == 0) //even if still free branch, if all clauses are satisfied, then ok. + return false; + + if (hook != null) + hook.OnCaseSplit(svar); + + sharp_assert (is_active(node(svar))); + make_decision(svar); + return true; + } + + + void real_solve() + { + stats.outcome = SATStatus.UNDETERMINED; + + while (true) + { + if (get_cpu_time() - stats.start_cpu_time > parameters.time_limit) + { + stats.outcome = SATStatus.TIME_OUT; + return; + } + if (stats.is_mem_out) + { + stats.outcome = SATStatus.MEM_OUT; + return; + } + + run_periodic_functions(); + + bool can_branch = make_branch_decision(); + if (!can_branch) + { + stats.outcome = SATStatus.SATISFIABLE; + return; + } + + while(deduce() == false) + resolve_conflicts(); + + //after above loop, the solver will stabilize in a decision level + //with no conflict and implication. If this level is -1 then unsat + if (dlevel < 0) + { + stats.outcome = SATStatus.UNSATISFIABLE; + return; + } + if (hook != null) + hook.OnBCP (); + } + } + + internal void reset () + { + if ( stats.been_reset == false) + { + if (dlevel >= 0) + backtrack( -1 ); + dlevel = 0; + stats.outcome = SATStatus.UNDETERMINED; + stats.been_reset = true; + } + } + + double get_cpu_time () + { + /* + currentProcess.Refresh(); + TimeSpan cputime = currentProcess.TotalProcessorTime; + return cputime.Hours * 3600 + cputime.Seconds + cputime.Milliseconds / 1000.0; + */ + return DateTime.Now.Ticks / 1e7; + } + + void init () + { + if (!stats.active_area_changed) + return; + //so, we need to figure out new active area + for (int i=0; i< active_area.size(); ++i) + { + Variable var = node(active_area[i]); + var.clear_flag(reasoning_flag); + clear_active(var); + } + active_area.clear(); + + for (int i=0; i< original_clauses.size(); ++i) + { + int cl_id = original_clauses[i]; + Clause cl = clause(cl_id); + foreach (int lit in cl.literals) + { + if (!node(lit).flag(active_flag)) + { + active_area.push_back(NON_NEGATED(lit)); + set_active(node(lit)); + } + } + } + mark_transitive_fanins(active_area, active_flag); + + ordered_vars.clear(); + for (int i=0; i< active_area.size(); ++i) + { + int vid = VID(active_area[i]); + Variable var = variable(vid); + sharp_assert (var.flag(active_flag)); + if (is_branchable(var)) //add it into vars for branching + { + var.score_0 = variable(i).lits_count_0; + var.score_1 = variable(i).lits_count_1; + var.ordered_pos = ordered_vars.size(); + ordered_vars.push_back(vid); + } + if (var.is_gate()) + var.set_flag(reasoning_flag); + else + var.clear_flag(reasoning_flag); + } + } + + internal SATStatus solve() + { + if (stats.constraint_zero > 0) + { + stats.outcome = SATStatus.UNSATISFIABLE; + return stats.outcome; + } + + stats.start_cpu_time = get_cpu_time(); + + init(); + + //enable_rtrace(true); + sharp_assert (stats.is_solving == false); + stats.is_solving = true; + + if (stats.been_reset == true) + preprocess(); + + stats.been_reset = false; + + if (dlevel < 0) + stats.outcome = SATStatus.UNSATISFIABLE; + else + real_solve(); + + stats.finish_cpu_time = get_cpu_time(); + stats.total_cpu_time += stats.finish_cpu_time - stats.start_cpu_time; + ++ stats.num_rounds; + stats.is_solving = false; + + //rtrace.dump_trace("trace"); + //if (stats.outcome == SATStatus.UNSATISFIABLE) + // dump_unsat_core("core.cnf"); + return stats.outcome; + } + + void preprocess() + { + sharp_assert (dlevel == 0); + for (int i=0; i< clauses.size(); ++i) + { + Clause cl = clause(i); + if (cl == null) + continue; + if (is_conflicting(cl)) + queue_conflict(i, ImpType.CLAUSE); + else + { + int unit = find_unit_lit(cl); + if (unit != 0) + queue_implication(unit, i, ImpType.CLAUSE); + } + } + + if (deduce() == false) + { + resolve_conflicts(); + sharp_assert ( dlevel < 0); + stats.outcome = SATStatus.UNSATISFIABLE; + } + } + + + void mark_involved_var(int vid) + { + Variable var = variable(vid); + if (is_marked(var) == false) + { + set_marked(var); + if (var.dlevel == dlevel) + ++ stats.marked_current_dl; + else + learned_clause.push_back(vid + vid + var_value(vid)); + } + } + + void rtrace_add_resolvent(int uid) + { +#if GEN_RESOLVE_TRACE + rtrace.add_reason(uid); +#endif + } + + void rtrace_add_resolvent(int uid, int r) + { +#if GEN_RESOLVE_TRACE + rtrace.add_reason(uid + (r << UIDSHIFT)); +#endif + } + + void rtrace_record_resolve_process (int uid) + { +#if GEN_RESOLVE_TRACE + rtrace.set_resolvent (uid); +#endif + } + + void rtrace_gen_empty_clause(Antecedent conf) + { +#if GEN_RESOLVE_TRACE + sharp_assert ( stats.marked_current_dl == 0); + sharp_assert (dlevel == 0); + + mark_conflict(conf) ; + IntVector assignments = assignment_stack(dlevel); + for (int i = assignments.size() - 1; i >= 0; --i) + { + int lit = assignments[i]; + int vid = (lit >> 1); + Variable var = variable(vid); + if (is_marked(var)) + { + mark_reason (vid); + clear_marked(var); + -- stats.marked_current_dl; + } + } + sharp_assert ( stats.marked_current_dl == 0); + sharp_assert ( learned_clause.size() == 0); + + //now record the generation process + rtrace.set_empty_resolvents(); +#endif + } + + + ushort mark_conflict(Antecedent conf) + { + // return the group flag of id of type + switch(conf.type) + { + case ImpType.CLAUSE: //implied by a clause + { + Clause cl = clause(conf.index); + for (int i=0; i< cl.num_lits; ++i) + mark_involved_var(VID(cl.literal(i))); + + rtrace_add_resolvent (cl.uid); + ++cl.activity; + return cl.gflag; + } + case ImpType.PB: //implied by a pseudo boolean constraint + { + fatal(); + break; + } + case ImpType.NODE: //implied by a combinational gate + { + int r = node_mark_conflict(conf.index); + Variable nd = variable(conf.index); + rtrace_add_resolvent (nd.uid, r); + return nd.gflag; + } + default: + sharp_assert(false); + break; + } + return 0; + } + + ushort mark_reason(int vid) + { + Variable var = variable(vid); + Antecedent ante = var.antecedent; + switch(ante.type) + { + case ImpType.CLAUSE: //implied by a clause + { + Clause cl = clause(ante.index); + + for (int i=0; i< cl.num_lits; ++i) + if ((cl.literal(i)>>1) != vid) + mark_involved_var(cl.literal(i) >> 1); + rtrace_add_resolvent (cl.uid); + ++cl.activity; + return cl.gflag; + } + case ImpType.PB: //implied by a pseudo boolean constraint + { + fatal(); + break; + } + case ImpType.NODE: //implied by a combinational gate + { + int r = node_mark_reason(vid); + Variable nd = variable(ante.index); + rtrace_add_resolvent (nd.uid, r); + return nd.gflag; + } + default: + sharp_assert(false); + break; + } + fatal(); + return 0; + } + + /* + * return value: which clause is responsible + * a == i0, b == i1, c == out + * for AND + * 1: (a + c') + * 2: (b + c') + * 3: (a' + b' + c) + * for XOR + * 4: (a' + b + c) + * 5: (a + b' + c) + * 6: (a + b + c') + * 7: (a' + b' + c') + */ + int node_mark_conflict(int vid) + { + Variable n = variable(vid); + sharp_assert (var_value(vid) != UNKNOWN); + mark_involved_var( vid ); + + int r = 0; + int i0 = n.left; + int vid0 = NODE_ID(i0); + int i1 = n.right; + int vid1 = NODE_ID(i1); + if (n.type == NodeType.AND) + { + if (var_value(vid) == 0) + { + sharp_assert (lit_value(i0) == 1); + sharp_assert (lit_value(i1) == 1); + mark_involved_var( vid0 ); + mark_involved_var( vid1 ); + r = 3; + } + else + { //var value == 1 + sharp_assert (lit_value(i0) == 0 || lit_value(i1) == 0); + if (lit_value(i0) != 0) + { + mark_involved_var( vid1 ); + r = 2; + } + else if (lit_value(i1) != 0) + { + mark_involved_var( vid0 ); + r = 1; + } + else + { + sharp_assert (variable(vid0).dlevel == variable(vid1).dlevel); + if (variable(vid0).asgn_pos < variable(vid1).asgn_pos) + { + mark_involved_var( vid0 ); + r = 1; + } + else + { + mark_involved_var( vid1 ); + r = 2; + } + } + } + } + else + { + sharp_assert (n.type == NodeType.XOR); + sharp_assert (lit_value(i0) == 0 || lit_value(i0) == 1); + sharp_assert (lit_value(i1) == 0 || lit_value(i1) == 1); + sharp_assert ((lit_value(i0) ^ lit_value(i1)) != var_value(vid)); + mark_involved_var( vid0 ); + mark_involved_var( vid1 ); +#if GEN_RESOLVE_TRACE + int va = lit_value(i0); + int vb = lit_value(i1); + int vc = var_value(vid); + if (va == 1 && vb == 0 && vc == 0) + r = 4; + else if (va == 0 && vb == 1 && vc == 0) + r = 5; + else if (va == 0 && vb == 0 && vc == 1) + r = 6; + else + { + sharp_assert (va == 1 && vb == 1 && vc == 1); + r = 7; + } +#endif + } + return r; + } + + int node_mark_reason(int vid) + { + sharp_assert (variable(vid).antecedent.type == ImpType.NODE); + int ante = variable(vid).antecedent.index; + + int r = 0; + Variable n = variable(ante); + int i0 = n.input(0); + int vid0 = NODE_ID(i0); + int i1 = n.input(1); + int vid1 = NODE_ID(i1); + + if (n.type == NodeType.AND) + { + if (vid == ante) + { //by itself, so it's propagation, the reason is it's input + if (var_value(vid) == 1) + { + sharp_assert (lit_value(i0) == 1); + sharp_assert (lit_value(i1) == 1); + mark_involved_var( vid0 ); + mark_involved_var( vid1 ); + r = 3; + } + else + { + sharp_assert (lit_value(i0) == 0 || lit_value(i1) == 0); + if (lit_value(i0) != 0) + { + mark_involved_var( vid1 ); + r = 2; + } + else if (lit_value(i1) != 0) + { + mark_involved_var( vid0 ); + r = 1; + } + else + { + sharp_assert (var_dlevel(vid0) == var_dlevel(vid1)); + if (variable(vid0).asgn_pos < variable(vid1).asgn_pos) + { + mark_involved_var( vid0 ); + r = 1; + } + else + { + mark_involved_var( vid1 ); + r = 2; + } + } + } + } + else + { //it's justification, the reason is it's output (ante), and maybe the other input of ante + int other_vid; + int other_input; + int self_input; + + sharp_assert (vid0 == vid || vid1 == vid); + if (vid0 == vid) + { + other_vid = vid1; + other_input = i1; + self_input = i0; + r = 1; + } + else + { + other_vid = vid0; + other_input = i0; + self_input = i1; + r = 2; + } + if (lit_value(self_input) == 1) + { + sharp_assert (var_value(ante) == 1); + mark_involved_var( ante ); + } + else + { + sharp_assert (var_value(ante) == 0); + sharp_assert (lit_value(other_input) == 1); + mark_involved_var( ante ); + mark_involved_var( other_vid ); + r = 3; + } + } + } + else + { + sharp_assert (n.type == NodeType.XOR); + if (ante == vid) + { + mark_involved_var( vid0 ); + mark_involved_var( vid1 ); +#if GEN_RESOLVE_TRACE + int va = lit_value(i0); + int vb = lit_value(i1); + int vc = var_value(ante); + if (vc == 1) + { + if (va == 1 && vb == 0) + r = 4; + else + { + sharp_assert (va == 0 && vb == 1); + r = 5; + } + } + else + { + if (va == 0 && vb == 0) + r = 6; + else + { + sharp_assert (va == 1 && vb == 1); + r = 7; + } + } +#endif + } + else + { + mark_involved_var( ante ); + sharp_assert (vid0 == vid || vid1 == vid); + if (vid0 == vid) + mark_involved_var( vid1 ); + else + mark_involved_var( vid0 ); +#if GEN_RESOLVE_TRACE + int va = lit_value(i0); + //int vb = lit_value(i1); + int vc = var_value(ante); + if (vc == 0) + { + if (va == 0) + r = 4; + else + r = 5; + } + else + { + if (va == 0) + r = 6; + else + r = 7; + } +#endif + } + } + return r; + } + + void resolve_conflicts() + { + sharp_assert (!conflict_array.empty()); + sharp_assert (implication_queue.Count == 0); + sharp_assert ( stats.marked_current_dl == 0 ); + sharp_assert ( learned_clause.empty() ); + + ++ stats.num_conflicts; + + if (dlevel == 0) + { + rtrace_gen_empty_clause(conflict_array[0]); + backtrack(-1); + conflict_array.clear(); + return; + } + + ushort gflag = 0; + + Antecedent conf = (Antecedent) conflict_array[0]; + + for (int i=1, sz = conflict_array.size(); i< sz; ++i) + { + if ( ((Antecedent)conflict_array[i]).type == ImpType.NODE) + { + conf = (Antecedent) conflict_array[i]; + break; + } + } + + gflag |= mark_conflict(conf); + + sharp_assert (stats.marked_current_dl > 1); + + IntVector assignments = assignment_stack(dlevel); + for (int i = assignments.size() - 1; i >= 0; --i) + { + int lit = assignments[i]; + int vid = (lit >> 1); + Variable var = variable(vid); + + if (!is_marked(var)) + continue; + + if (stats.marked_current_dl == 1) + { + learned_clause.push_back(lit^1); + break; + } + else + { + gflag |= mark_reason (vid); + clear_marked(var); + -- stats.marked_current_dl; + } + } + sharp_assert ( stats.marked_current_dl == 1); + + int sharp_assert_level = 0; + int sharp_assert_lit = learned_clause.back; + sharp_assert (lit_value(sharp_assert_lit) == 0); + clear_marked(node(sharp_assert_lit)); + -- stats.marked_current_dl; + + for (int i = 0; i < learned_clause.size() - 1; ++i) + { + int lit = learned_clause[i]; + incr_var_score (lit); + sharp_assert (lit_value(lit) == 0); + + Variable var = variable(lit>>1); + sharp_assert (is_marked(var)); + clear_marked(var); + if (var.dlevel > sharp_assert_level) + sharp_assert_level = var.dlevel; + } + backtrack(sharp_assert_level); + + int cl_id = add_learned_clause(learned_clause.ToArray(), gflag); + learned_clause.clear(); + sharp_assert (is_unit(cl_id)); + queue_implication(sharp_assert_lit, cl_id, ImpType.CLAUSE); + conflict_array.clear(); + } + + + void queue_conflict (int ante, ImpType type) + { + Antecedent antecedent = new Antecedent(type, ante); + conflict_array.push_back ((int) antecedent); + } + + void queue_implication(int lit, int ante, ImpType type) + { + if (is_active(node(lit))) //it is in the active area + { + Implication imp = new Implication(); + imp.lit = lit; + imp.ante.type = type; + imp.ante.index = ante; + implication_queue.Enqueue (imp); + } + } + + bool deduce() + { + while (implication_queue.Count != 0 && conflict_array.empty()) + { + Implication imp = (Implication) implication_queue.Dequeue(); + int lit = imp.lit; + int vid = lit>> 1; + if(var_value(vid) == UNKNOWN) + { + propagate_implication ( imp ); + variable(vid).asgn_pos = assignment_stack(dlevel).size(); + assignment_stack(dlevel).push_back(lit); + } + else + { + if (lit_value(lit) == 0) //conflict + queue_conflict(imp.ante.index, imp.ante.type); + } +#if CHECK + for (int i=0; i< clauses.size(); ++i) + { + Clause cl = clause(i); + if (cl != null && is_conflicting(i)) + sharp_assert (!conflict_array.empty()); + } +#endif + } + if (!conflict_array.empty()) + { + implication_queue.Clear(); + return false; + } + return true; + } + + void propagate_implication (Implication imp) + { + int vid = imp.lit>> 1; + + Variable var = variable(vid); + sharp_assert (var_value(vid) == UNKNOWN); + + var.dlevel = dlevel; + var.antecedent = imp.ante; + + var_set_value (vid, (short) (1 - (imp.lit&1))); + + set_svar_value(imp.lit); + + ++ stats.num_implications ; + -- stats.num_free_variables; + if (is_branchable(var)) + -- stats.num_free_branch_vars; + } + + void unset_variable(int v) + { + if (v == 0) return; + Variable var = variable(v); + var.dlevel = -1; + var.antecedent = -1; + var.asgn_pos = -1; + var_set_value (v, UNKNOWN); + ++ stats.num_free_variables; + if (is_branchable(var)) + { + ++ stats.num_free_branch_vars; + if (var.ordered_pos < max_score_pos) + max_score_pos = var.ordered_pos; + } + } + + void backtrack(int blevel) + { + sharp_assert(blevel < dlevel); + implication_queue.Clear(); + + for (int i= dlevel; i> blevel; --i) + { + IntVector assignments = assignment_stack(i); + for (int j=assignments.size()-1 ; j>=0; --j) + unset_variable (assignments[j]>>1); + assignment_stack(i).clear(); + } + + dlevel = blevel; + ++ stats.num_backtracks; + + if (hook != null) + hook.OnBacktrack(blevel); + } + + void set_svar_value(int s) + { + //Implication On the Network + Variable var = variable(VID(s)); + //propagate forward + for (int i=0; i< var.outputs.size(); ++i) + make_node_consistent(var.output(i)); + //justify backward + make_node_consistent(s); + + //Implication On the clauses + IntVector watched = watched_by (s ^ 1); //the neg watched + for (int i=0; i< watched.size(); ++i) + { + int cl_idx = (watched[i] >> 1); + int w_idx = (watched[i] & 1); + Clause cl = clause(cl_idx); + int[] lits = cl.literals; + sharp_assert (lits[w_idx] == (s ^ 1)); + int other_watch_lit = lits[1 - w_idx]; + int other_value = lit_value(other_watch_lit); + if (other_value == 0) + { + sharp_assert (variable(other_watch_lit>> 1).dlevel == dlevel); + queue_conflict(cl_idx, ImpType.CLAUSE); + } + else if (other_value != 1) + { + int j; + for (j=2; j< cl.num_lits; ++j) + if (lit_value(lits[j]) != 0) + break; + if (j < cl.num_lits) + { //found another non-0 lit + int temp = lits[j]; + lits[j] = lits[w_idx]; + lits[w_idx] = temp; + watched_by(temp).push_back(cl_idx + cl_idx + w_idx); + watched[i] = watched.back; + watched.pop_back(); + -- i; + } + else + queue_implication(other_watch_lit, cl_idx, ImpType.CLAUSE); + } + } + } + + internal int new_pi() + { + int s = new_node( NodeType.PI, INVALID, INVALID); + primary_inputs.push_back(s); + node_to_pi_hash[s] = primary_inputs.size() - 1; + return s; + } + + internal int nth_pi(int n) + { + while (num_pi() <= n) + new_pi(); + return pi(n); + } + + + internal int left_child (int s) { return node(s).left; } + internal int right_child (int s){ return node(s).right; } + + internal int band (int i1, int i2) + { + int l = canonical (i1); + int r = canonical (i2); + int result = create( NodeType.AND, l, r ); + // dump_file.WriteLine ("{0} = AND {1} {2}", result, i1, i2); + return result; + } + + internal int bxor (int i1, int i2) + { + int l = canonical (i1); + int r = canonical (i2); + int result = create( NodeType.XOR, l, r ); + // dump_file.WriteLine ("{0} = XOR {1} {2}", result, i1, i2); + return result; + } + + internal int bor (int i1, int i2) { return NEGATE( band( NEGATE(i1), NEGATE(i2)) );} + internal int bequ (int i1, int i2) { return NEGATE( bxor( i1, i2 ));} + internal int bimp (int i1, int i2) { return bor (NEGATE(i1), i2);} + internal int bnot (int i) { return NEGATE(i); } + + /* + Create a node. Don't do recursive optimization. But do lookup and simplification + if possible. + */ + int create_op_node(NodeType op, int i1, int i2) + { + if (op == NodeType.AND) + { + if (i1 == zero() || i2 == zero() || i1 == NEGATE(i2)) + return zero(); + if (i1 == one()) + return i2; + if (i2 == one()) + return i1; + if (i1 == i2) + return i1; + } + else + { + sharp_assert (op == NodeType.XOR); + if (i1 == zero()) + return i2; + if (i1 == one()) + return NEGATE(i2); + if (i2 == zero()) + return i1; + if (i2 == one()) + return NEGATE(i1); + if (i1 == i2) + return zero(); + if (i1 == NEGATE(i2)) + return one(); + } + + int r = node_hash.lookup(op, i1, i2); + if (r != INVALID) + return r; + + r = create_op_node2(op, i1, i2); + + return r; + } + + /* + create an op node, Do recursive optimization and other possible optimizations + */ + int create (NodeType op, int i1, int i2) + { + if (op == NodeType.AND) + { + if (i1 == zero() || i2 == zero() || i1 == NEGATE(i2)) + return zero(); + if (i1 == one()) + return i2; + if (i2 == one()) + return i1; + if (i1 == i2) + return i1; + } + else + { + sharp_assert (op == NodeType.XOR); + if (i1 == zero()) + return i2; + if (i1 == one()) + return NEGATE(i2); + if (i2 == zero()) + return i1; + if (i2 == one()) + return NEGATE(i1); + if (i1 == i2) + return zero(); + if (i1 == NEGATE(i2)) + return one(); + } + + int r = node_hash.lookup(op, i1, i2); + + if (r != INVALID) + return r; + + // r = create_op_node2(op, i1, i2); + if ( is_pi(i1) && is_pi(i2)) + r = create_op_node2(op, i1, i2); + else if (is_pi(i1) || is_pi(i2)) + r = create_op_node3(op, i1, i2); + else + r = create_op_node4(op, i1, i2); + + return r; + } + + int get_signature4(NodeType op, int l, int r) + { + int sig = 0; + int ll = node(l).left; + int lr = node(l).right; + + int rl = node(r).left; + int rr = node(r).right; + + sharp_assert ( ll < lr ); + sharp_assert ( rl < rr ); + sharp_assert ( ll < rl || ll == rl ); // to reduce lookup table size + + if (IS_NEGATED(ll)) sig |= (1<<0); + if (IS_NEGATED(lr)) sig |= (1<<1); + if (IS_NEGATED(rl)) sig |= (1<<2); + if (IS_NEGATED(rr)) sig |= (1<<3); + if (IS_NEGATED(l)) sig |= (1<<4); + if (IS_NEGATED(r)) sig |= (1<<5); + if (node(l).type == NodeType.XOR) sig |= (1<<6); + if (node(r).type == NodeType.XOR) sig |= (1<<7); + if (op == NodeType.XOR) sig |= (1<<8); + + int v_ll = NODE_ID( ll ); + int v_lr = NODE_ID( lr ); + int v_rl = NODE_ID( rl ); + int v_rr = NODE_ID( rr ); + + if (v_lr < v_rl) sig |= (0 << 9); //a < b < c < d + else if (v_lr == v_rl) sig |= (1 << 9); //a < b = c < d + else if (v_lr < v_rr) + { + if (v_ll < v_rl ) sig |= (2 << 9); //a < c < b < d + else sig |= (3 << 9); //a = c < b < d + } + else if (v_lr == v_rr) + { + if (v_ll < v_rl ) sig |= (4 << 9); //a < c < b = d + else sig |= (5 << 9); //a = c < b = d + } + else + { // v_lr > v_rr + if (v_ll < v_rl ) sig |= (6 << 9); //a < c < d < b + else sig |= (7 << 9); //a = c < d < b + } + return sig; + } + + int get_signature3(NodeType op, int l, int r) + { + //Functions that contains 3 operands: + //it is assumed that the structure is like this: + // o + // l (op) r + // ll (op1) lr + int sig = 0; + sharp_assert (!is_pi(l)); + sharp_assert (is_pi(r)); + int ll = node(l).left; + int lr = node(l).right; + + sharp_assert (ll < lr); + + if (IS_NEGATED(ll)) sig |= (1<<0); + if (IS_NEGATED(lr)) sig |= (1<<1); + if (IS_NEGATED(l)) sig |= (1<<2); + if (IS_NEGATED(r)) sig |= (1<<3); + if (node(l).type == NodeType.XOR) sig |= (1<<4); + if (op == NodeType.XOR) sig |= (1<<5); + + int v_r = NODE_ID(r); + int v_ll = NODE_ID(ll); + int v_lr = NODE_ID(lr); + + if (v_r > v_lr ) sig |= (0 << 6); //a < b < c + else if (v_r == v_lr ) sig |= (1 << 6); //a < b = c + else if (v_ll < v_r ) sig |= (2 << 6); //a < c < b + else if (v_ll == v_r ) sig |= (3 << 6); //a = c < b + else sig |= (4 << 6); //c < a < b + + return sig; + } + + /* + Create an op node and add it to hash table. + Just do it, don't do lookup or simplification + */ + int create_op_node2(NodeType op, int i1, int i2) + { + sharp_assert (op == NodeType.AND || op == NodeType.XOR); + + // do need to make it canonical + //1. left input always has smaller index than right + if (i1 > i2) + { + int temp = i1; + i1 = i2; + i2 = temp; + } + //2. For XOR gate, both of its input must be in positive phase + bool do_NEGATE = false; + if (op == NodeType.XOR) + { + if (IS_NEGATED(i1)) + { + i1 = NEGATE(i1); + do_NEGATE = !do_NEGATE; + } + if (IS_NEGATED(i2)) + { + i2 = NEGATE(i2); + do_NEGATE = !do_NEGATE; + } + } + + int o = new_node(op, i1, i2); + sharp_assert (o > i1 && o > i2); + + node(i1).outputs.push_back(o); //i.e. the sign is 0: Left child + node(i2).outputs.push_back(NEGATE(o)); //i.e. the sign is 1: Right child + reference (i1); + reference (i2); + + //add it to the hash + node_hash.insert( o, op, i1, i2); + + //return the actual result + if (do_NEGATE) + o = NEGATE(o); + + return o; + } + + /* + Create a node, one of its inputs is a PI + */ + int create_op_node3(NodeType op, int i1, int i2) + { + if (is_pi(i1)) + { + sharp_assert (!is_pi(i2)); + int temp = i2; + i2 = i1; + i1 = temp; + } + + int sig = get_signature3(op, i1, i2); + int r = look_up_3_input_node ( op, i1, i2, sig); + return r; + } + + /* + Create a node, none of its inputs is PI + */ + int create_op_node4(NodeType op, int i1, int i2) + { + if (node(i1).left > node(i2).left) + { + int temp = i1; + i1 = i2; + i2 = temp; + } + + int sig = get_signature4(op, i1, i2); + int r = look_up_4_input_node ( op, i1, i2, sig); + return r; + } + + /* + Merge two ints, always keep the one() with smaller index + */ + int merge (int i1, int i2) + { + return real_merge(canonical(i1), canonical(i2)); + } + + int real_merge(int i1, int i2) + { + if (i1 == i2) + return i1; + else if (i1 == NEGATE(i2)) + return INVALID; + + if (i1 > i2) + { + int temp = i2; + i2 = i1; + i1 = temp; + } + + for (int i=0; i< node(i2).outputs.size(); ++i) + { + int o = node(i2).output(i); + int output = NON_NEGATED (o); + int l_r = SIGN(o); //the left or the right input + int other_input = node(output).input(1 - l_r); + if (node(output).input(l_r) == i2) + { + int r_node = create (node(output).type, i1, other_input); + real_merge(r_node, output); + } + else + { + sharp_assert (node(output).input(l_r) == NEGATE(i2)); + int r_node = create (node(output).type, NEGATE(i1), other_input); + real_merge(r_node, output); + } + } + + node(i2).outputs.clear(); + + if (IS_NEGATED(i2)) + node(i2).canonical = NEGATE(i1); + else + node(i2).canonical = i1; + + return i1; + } + + internal void reference(int lit) + { + variable(lit>>1).ref_count ++; + } + + internal void deref (int lit) + { + // if (--variable(VID (lit)).ref_count != 0) + // return; + // + // IntVector to_be_processed = new IntVector(16); + // to_be_processed.push_back(VID (lit)); + // for (int i=0; i< to_be_processed.size(); ++i) + // { + // int vid = to_be_processed[i]; + // Variable var = variable(vid); + // if (var.is_gate()) + // { + // for (int j=0; j< 2; ++j) + // { + // int vin = (j==0)? VID(var.left): VID(var.right); + // Variable var_in = variable(vin); + // int size = var_in.outputs.size(); + // for (int k=0; k< size; ++k) + // { + // if (VID(var_in.output(k)) == vid) + // { + // var_in.outputs[k] = var_in.outputs.back; + // var_in.outputs.pop_back(); + // break; + // } + // } + // sharp_assert (size > var_in.outputs.size()); + // if ( --var_in.ref_count == 0) + // to_be_processed.push_back(vin); + // } + // } + // } + // free_nodes.add (to_be_processed); + } + /* + Compose: i.e. replace some ints with other ints + input : the output node and the replacement correspondence + output: the result of the composition + */ + internal int compose ( int output, int [] orig, int [] replace) + { + sharp_assert (orig.Length == replace.Length); + + if (node(output).type == NodeType.CONSTANT) + return output; + + MyHashtable sig_map = new MyHashtable(); + for (int i=0; i< orig.Length; ++i) + { + int s_orig = orig[i]; + int s_new = replace[i]; + if (IS_NEGATED(s_orig)) + { + s_orig = NEGATE(s_orig); + s_new = NEGATE(s_new); + } + sig_map[s_orig] = s_new; + } + return real_compose(canonical(output), sig_map); + } + + int real_compose(int old, MyHashtable sig_map ) + { + int result; + + bool invert = false; + + if (IS_NEGATED(old)) + { + old = NEGATE(old); + invert = true; + } + object item = sig_map[old]; + if (item != null) + result = (int) item; + else + { + if (is_pi(old)) //so, if a pi is not replaced, use it as is + result = old; + else + { + int left = real_compose(node(old).left, sig_map); + int right = real_compose(node(old).right, sig_map); + result = create(node(old).type, left, right); + sig_map[old] = result; + } + } + return (invert ? NEGATE(result): result); + } + + internal int gen_interpolant_from_clauses(int gid1, int gid2) + { + clean_up(); + rtrace.enable_trace(true); + SATStatus status = solve(); + rtrace.enable_trace(false); + reset(); + + if (status != SATStatus.UNSATISFIABLE) + return -1; + return rtrace.gen_interpolant_from_clauses (gid1, gid2); + } + + internal int gen_interpolant_from_signals(int s1, int s2) + { + clean_up(); + + int gid = alloc_gid(); + int [] cl1 = new int [] {s1}; + int c_1 = add_clause(cl1, gid); + int [] cl2 = new int [] {s2}; + int c_2 = add_clause(cl2, gid); + + rtrace.enable_trace(true); + SATStatus status = solve(); + rtrace.enable_trace(false); + reset(); + + int r; + if (status != SATStatus.UNSATISFIABLE) + r = -1; + else + r = rtrace.gen_interpolant_from_signals (s1, c_1, s2, c_2); + delete_clause_group(gid); + return r; + } + + // gretay - change start + internal int gen_interpolant_from_signals_ex(int s1, int s2) + { + // don't cleanup because conflict clauses + //clean_up(); + + int gid = alloc_gid(); + int [] cl1 = new int [] {s1}; + int c_1 = add_clause(cl1, gid, false); + int [] cl2 = new int [] {s2}; + int c_2 = add_clause(cl2, gid, false); + + rtrace.enable_trace(true); + SATStatus status = solve(); + rtrace.enable_trace(false); + reset(); + + int r; + if (status != SATStatus.UNSATISFIABLE) + r = -1; + else + r = rtrace.gen_interpolant_from_signals_ex (s1, c_1, s2, c_2, c_cls_id.ToArray(), c_interp.ToArray()); + return r; + } + + Hashtable interpolants = new Hashtable(); // maps clause_uid to signal that describes the interpolant provided for that clause + IntVector c_cls_id = new IntVector(4); + IntVector c_interp = new IntVector(4); + + public bool has_interpolant(int cl_uid) + { + return interpolants.Contains(cl_uid); + } + public void set_interpolant(int cl_uid, int interp) + { + Debug.Assert(!has_interpolant(cl_uid)); + interpolants[cl_uid] = interp; + c_cls_id.push_back(cl_uid); + c_interp.push_back(interp); + } + public int get_interpolant_by_clause_uid(int cl_uid) + { + Debug.Assert(has_interpolant(cl_uid)); + return (int) interpolants[cl_uid]; + } + // end gretay - change end + + internal UnsatCore gen_unsat_core () + { + clean_up(); + rtrace.enable_trace(true); + SATStatus status = solve(); + rtrace.enable_trace(false); + + if (status != SATStatus.UNSATISFIABLE) + return null; + + MyHashtable hash = rtrace.generate_unsat_core(); + UnsatCore core = new UnsatCore(); + IntVector core_cls = new IntVector(4); + IntVector core_nodes = new IntVector(4); + for (int i=0; i< clauses.size(); ++i) + { + Clause cl = clause(i); + if (cl == null) + continue; + if (hash.Contains(cl.uid)) + { + sharp_assert (cl.type == ClType.ORIGINAL); + core_cls.push_back (i); + } + } + for (int i=1; i < variables.size(); ++i) + { + Variable v = variable(i); + if (hash.Contains(v.uid)) + { + sharp_assert (v.type == NodeType.AND || v.type == NodeType.XOR); + core_nodes.push_back ( i + i); + } + } + core.core_clauses = core_cls.ToArray(); + core.core_nodes = core_nodes.ToArray(); + return core; + } + + void dump_unsat_core( string filename) + { + StreamWriter writer = new StreamWriter(filename); + UnsatCore core = gen_unsat_core(); + + writer.WriteLine ("p cnf {0} {1} ", num_variables() , core.core_clauses.Length); + foreach (int cl_id in core.core_clauses) + { + foreach (int lit in clause(cl_id).literals) + { + if ((lit & 1) == 1) + writer.Write("-"); + writer.Write ("{0} ", lit>>1); + } + writer.WriteLine ("0"); + } + writer.Close(); + if (core.core_nodes.Length != 0) + { + Console.WriteLine ("Warning: Contains Nodes in the UNSAT core " ); + foreach (int s in core.core_nodes) + { + Console.Write ("{0} ", s); + } + Console.WriteLine(""); + } + } + + internal void dump_node (StreamWriter wt, int s) + { + int flag = alloc_flag(); + mark_transitive_fanins(s, flag); + for (int i=1; i< variables.size(); ++i) + { + Variable var = variable(i); + if (var.flag(flag)) + { + switch (var.type) + { + case NodeType.PI: + wt.WriteLine("{0} = PI", i + i); + break; + case NodeType.AND: + wt.WriteLine("{0} = AND {1} {2}", i + i, var.left, var.right); + break; + case NodeType.XOR: + wt.WriteLine("{0} = XOR {1} {2}", i + i, var.left, var.right); + break; + } + } + } + free_flag(flag); + } + + internal int get_structure (SharpSATSolver solver, int output) + { + int f = solver.alloc_flag(); + solver.mark_transitive_fanins(output,f); + int [] lookup = new int [solver.variables.size() * 2]; + for (int i=0; i< lookup.Length; ++i) + lookup[i] = -1; + for (int i=1; i< solver.variables.size(); ++i) + { + Variable var = solver.variable(i); + if (!var.flag(f)) + continue; + int l = var.left; + int r = var.right; + int s ; + switch(var.type) + { + case NodeType.AND: + sharp_assert (solver.node(l).flag(f)); + sharp_assert (solver.node(r).flag(f)); + sharp_assert (lookup[l] != -1); + sharp_assert (lookup[r] != -1); + s = band(lookup[l], lookup[r]); + // sharp_assert (node(s).left == lookup[l]); + // sharp_assert (node(s).right == lookup[r]); + lookup[i + i] = s; + lookup[i + i + 1] = s ^ 1; + break; + case NodeType.XOR: + sharp_assert (solver.node(l).flag(f)); + sharp_assert (solver.node(r).flag(f)); + sharp_assert (lookup[l] != -1); + sharp_assert (lookup[r] != -1); + s = bxor(lookup[l], lookup[r]); + // sharp_assert (node(s).left == lookup[l]); + // sharp_assert (node(s).right == lookup[r]); + lookup[i + i] = s; + lookup[i + i + 1] = s ^ 1; + break; + case NodeType.PI: + s = new_pi(); + lookup[i + i] = s; + lookup[i + i + 1] = s ^ 1; + break; + default: + sharp_assert(false); + break; + } + } + return lookup[output]; + } + + internal void dump_original_clauses ( StreamWriter wt ) + { +// IntVector originals = new IntVector(128); +// foreach (object k in original_clauses.Keys) +// originals.push_back((int)k); +// originals.sort(); + for (int i=0; i< original_clauses.size(); ++i) + { + int cl_id = original_clauses[i]; + sharp_assert (clause(cl_id).type == ClType.ORIGINAL); + wt.Write ("{0} = CL", i); + foreach (int lit in clause(cl_id).literals) + wt.Write(" {0}", lit); + wt.Write("\n"); + } + } + /* ========================================================================= + + Simulation Etc. on the Boolean Network + + ========================================================================= */ + internal IntVector mark_transitive_fanouts(int s, int flag_id) + { + IntVector to_be_processed = new IntVector(64); + to_be_processed.push_back(s); + node(s).set_flag(flag_id); + for (int i = 0; i< to_be_processed.size(); ++i) + { + Variable nd = node (to_be_processed[i]); + for (int j=0, sz = nd.outputs.size(); j < sz; ++j) + if (node(nd.output(j)).flag(flag_id) == false) + { + node(nd.output(j)).set_flag(flag_id); + to_be_processed.push_back(nd.output(j)); + } + } + return to_be_processed; + } + + internal IntVector find_transitive_fanins (int s) + { + int flag = alloc_flag(); + IntVector result = mark_transitive_fanins(s, flag); + free_flag(flag); + return result; + } + + internal IntVector mark_transitive_fanins(IntVector to_be_processed, int flag_id) + { + for (int i = 0, sz = to_be_processed.size(); i < sz; ++i) + { + Variable nd = node (to_be_processed[i]); + nd.set_flag(flag_id); + } + for (int i = 0; i< to_be_processed.size(); ++i) + { + Variable nd = node (to_be_processed[i]); + if (nd.left == INVALID || nd.right == INVALID) + { + sharp_assert (nd.left == INVALID && nd.right == INVALID); + continue; + } + if (node(nd.left).flag(flag_id) == false) + { + node(nd.left).set_flag(flag_id); + to_be_processed.push_back(nd.left); + } + if (node(nd.right).flag(flag_id) == false) + { + node(nd.right).set_flag(flag_id); + to_be_processed.push_back(nd.right); + } + } + return to_be_processed; + } + + internal IntVector mark_transitive_fanins(int s, int flag_id) + { + sharp_assert (s != INVALID); + if (node(s).type == NodeType.CONSTANT) + return null; + IntVector to_be_processed = new IntVector(4); + to_be_processed.push_back(s); + node(s).set_flag(flag_id); + for (int i = 0; i< to_be_processed.size(); ++i) + { + Variable nd = node (to_be_processed[i]); + if (nd.left == INVALID || nd.right == INVALID) + { + sharp_assert (nd.left == INVALID && nd.right == INVALID); + continue; + } + + if (node(nd.left).flag(flag_id) == false) + { + node(nd.left).set_flag(flag_id); + to_be_processed.push_back(nd.left); + } + if (node(nd.right).flag(flag_id) == false) + { + node(nd.right).set_flag(flag_id); + to_be_processed.push_back(nd.right); + } + } + return to_be_processed; + } + + public int [] find_small_model() + { + return find_small_model_greed(); + } + + private int [] find_small_model_greed () + { + sharp_assert ( stats.outcome == SATStatus.SATISFIABLE); + sharp_assert ( stats.num_free_branch_vars == 0); + int f = alloc_flag(); + //1. collect all the lits that needs to be true for clauses + for (int i=0; i< clauses.size(); ++i) + { + if (clauses[i] == null || clauses[i].type == ClType.CONFLICT) //??? is this correct, do we need to satisfy the temp clauses? + continue; + bool cls_sat = false; + foreach (int lit in clause(i).literals) + { + if (lit_value(lit) == 1) + { + variable(VID(lit)).set_flag(f); + cls_sat = true; + break; + } + } + if (cls_sat == false) + { + fatal ("A clause does not contain true lit even though formula is SAT"); + } + } + //now traverse the tree in reverse topological order + for (int i=variables.size()-1; i > 0 ; --i) + { + Variable var = variable(i); + if (!var.flag(f)) + continue; + sharp_assert (var_value(i) != UNKNOWN); + switch (var.type) + { + case NodeType.AND: + if (var_value(i) == 1) //both inputs must be true + { + sharp_assert (lit_value(var.left) == 1); + sharp_assert (lit_value(var.right) == 1); + variable(VID(var.left)).set_flag(f); + variable(VID(var.right)).set_flag(f); + } + else + { + sharp_assert (var_value(i) == 0); + if (lit_value(var.left) == 0) + variable(VID(var.left)).set_flag(f); + else if (lit_value(var.right) == 0) + variable(VID(var.right)).set_flag(f); + else + fatal ("Variable unjustifiable"); + } + break; + case NodeType.XOR: + variable(VID(var.left)).set_flag(f); + variable(VID(var.right)).set_flag(f); + break; + default: + break; + } + } + IntVector cube = new IntVector(16); + for (int i=0; i< variables.size(); ++i) + { + if (variable(i).flag(f)) + { + sharp_assert (var_value(i) != UNKNOWN); + cube.push_back (i + i + 1 - var_value(i)); + } + } + free_flag(f); + return cube.ToArray(); + } + + private class EnumQuantification + { + SharpSATSolver solver; + + IntVector visiting_queue; + IntVector blocking_lits; + int bound_flag; + int visited_flag; + int occ_flag ; + int sign_flag ; + IntVector involved_signals; + Hashtable blocking_clauses; + + ObjVector cls_occurrence; + + Variable variable(int vid) { return solver.variable(vid); } + Variable node(int lit) { return solver.node(lit); } + Clause clause (int id) { return solver.clause(id); } + int band (int a, int b) { return solver.band(a, b); } + int bor (int a, int b) { return solver.bor(a, b); } + int alloc_flag () { return solver.alloc_flag(); } + + [Microsoft.Contracts.NotDelayed] + public EnumQuantification(SharpSATSolver sol) + { + solver = sol; + visiting_queue = new IntVector(128); + blocking_lits = new IntVector(64); + involved_signals= new IntVector(128); + cls_occurrence = new ObjVector(128); + blocking_clauses= new Hashtable(); + bound_flag = solver.alloc_flag(); + visited_flag = solver.alloc_flag(); + occ_flag = solver.alloc_flag(); + sign_flag = solver.alloc_flag(); + } + + void finalize_quantification () + { + solver.free_flag (visited_flag); + solver.free_flag(bound_flag); + solver.free_flag(occ_flag); + solver.free_flag(sign_flag); + } + + void init_quantification (int s, int [] bounded, bool block_with_pi_only) + { + + involved_signals = solver.find_transitive_fanins(s); + if (block_with_pi_only) + { + foreach (int sig in bounded) + { + sharp_assert (node(sig).is_pi()); + node(sig).set_flag(bound_flag); + } + for (int i=0; i< involved_signals.size(); ++i) + { + Variable var = node(involved_signals[i]); + if (!var.is_pi()) + var.set_flag(bound_flag); + } + } + else + { + foreach (int sig in bounded) + { + sharp_assert (node(sig).is_pi()); + solver.mark_transitive_fanouts(sig,bound_flag); + } + } + + cls_occurrence = new ObjVector(solver.variables.size()); + for (int i = 0; i< involved_signals.size(); ++i) + cls_occurrence[VID(involved_signals[i])] = new IntVector(4); + } + + int build_balanced_or (int [] signals, int start, int end) + { + if (signals.Length == 0) + return solver.zero(); + else if (start == end) + return signals[start]; + else + { + int middle = (end - start) /2 + start; + int s1 = build_balanced_or(signals, start, middle); + int s2 = build_balanced_or(signals, middle + 1, end); + return bor (s1, s2); + } + } + + int build_balanced_and (int [] signals, int start, int end) + { + if (signals.Length == 0) + return solver.one(); + else if (start == end) + return signals[start]; + else + { + int middle = (end - start) /2 + start; + int s1 = build_balanced_and(signals, start, middle); + int s2 = build_balanced_and(signals, middle + 1, end); + return band (s1, s2); + } + } + + int build_struct_balanced (IntVector cls_ids) + { + int [] cl_sigs = new int[cls_ids.size()]; + for (int i=0; i< cls_ids.size(); ++i) + { + int [] lits = clause(cls_ids[i]).literals; + cl_sigs[i] = build_balanced_or ( lits, 0, lits.Length - 1); + } + int result = build_balanced_and(cl_sigs, 0, cl_sigs.Length - 1); + return result; + } + + + int build_struct (IntVector cls) + { + //return build_struct_simple(cls); + return build_struct_balanced (cls); + } + + int build_struct_simple(IntVector cls) + { + int sig = solver.one(); + for (int i=0; i< cls.size(); ++i) + { + int s = solver.zero(); + foreach (int lit in clause(cls[i]).literals) + s = bor(s, lit); + sig = band(sig, s); + } + return sig; + } + + static IntVector intersect (IntVector a, IntVector b) + { + IntVector result = new IntVector(4); + for (int i=0, j=0; i< a.size() && j < b.size(); ) + { + if (a[i] < b[j]) + ++ i; + else if (a [i] > b[j]) + ++ j; + else + { + result.push_back (a[i]); + ++i; + ++j; + } + } + return result; + } + + IntVector resolve (IntVector a, int [] b) + { + IntVector result = new IntVector(b.Length - 1); + sharp_assert (a.size() == b.Length); + foreach (int lit in b) + { + Variable var = variable (VID(lit)); + var.set_flag (occ_flag); + if (IS_NEGATED(lit)) + var.set_flag (sign_flag); + } + for (int i=0; i< a.size(); ++i) + { + int lit = a[i]; + Variable var = variable (VID(lit)); + sharp_assert (var.flag(occ_flag)); + if (var.flag(sign_flag) == IS_NEGATED(lit)) + result.push_back(lit); + var.clear_flag (occ_flag); + var.clear_flag (sign_flag); + } + if (result.size() == a.size() - 1) + return result; + else + return null; + } + + bool subsume (IntVector a, int [] b) + { + sharp_assert (a.size() < b.Length); + for (int i=0; i< a.size(); ++i) + { + int lit = a[i]; + Variable var = variable (VID(lit)); + var.set_flag (occ_flag); + if (IS_NEGATED(lit)) + var.set_flag (sign_flag); + } + int same_lit = 0; + int same_var = 0; + foreach (int lit in b) + { + Variable var = variable (VID(lit)); + if (var.flag(occ_flag)) + { + same_var ++; + if (IS_NEGATED(lit) == var.flag(sign_flag)) + same_lit ++; + var.clear_flag (occ_flag); + var.clear_flag (sign_flag); + } + } + sharp_assert (same_var == a.size()); + return (same_lit == same_var); + } + + void remove_blocking (int cl_id) + { + blocking_clauses.Remove(cl_id); + foreach (int lit in solver.clause(cl_id).literals) + { + int vid = VID(lit); + IntVector occur = (IntVector)cls_occurrence[vid]; + int i; + for (i=0; occur[i] != cl_id; ++i); + for ( i = i + 1; i < occur.size(); ++i ) + occur[i-1] = occur[i]; + occur.pop_back(); + } + + Clause cl = solver.clause(cl_id); + if (cl.num_lits> 1) + solver.remove_cl_from_reasoning (cl_id); + + + for (int i=0; i< cl.num_lits; ++i) + solver.decr_lits_count(cl.literal(i)); + + ++ solver.stats.num_deleted_clauses; + solver.stats.num_deleted_literals += cl.num_lits; + solver.clauses[cl_id] = null; + solver.free_clauses.push_back(cl_id); + } + + void add_blocking (int gid) + { + int cl_id = solver.add_blocking_clause(blocking_lits.ToArray(), gid); + for (int i=0; i< blocking_lits.size(); ++i) + { + int lit = blocking_lits[i]; + IntVector occ_array = (IntVector) cls_occurrence[VID(lit)]; + occ_array.push_back(cl_id); + //bubble down + for (int j=occ_array.size()-2; j >= 0; --j) + { + if (occ_array[j] > cl_id) + { + occ_array[j+1] = occ_array[j]; + occ_array[j] = cl_id; + } + else + break; + } + } + blocking_clauses.Add(cl_id, null); + } + + int n_tab = 1; + void tab () { for (int i=0; i< n_tab; ++i) Console.Write(" "); } + + void dump_lits (int [] a) + { + IntVector cp = new IntVector (4); + foreach (int lit in a) + cp.push_back(lit); + cp.sort(); + for (int i=0; i< cp.size(); ++i) + Console.Write ("{0}{1}", IS_NEGATED(cp[i])?" -":" +", VID(cp[i])); + Console.WriteLine(""); + } + + void dump_lits (IntVector a) + { + IntVector cp = new IntVector (4); + for (int i=0; i< a.size(); ++i) + cp.push_back(a[i]); + cp.sort(); + for (int i=0; i< cp.size(); ++i) + Console.Write ("{0}{1}", IS_NEGATED(cp[i])?" -":" +", VID(cp[i])); + Console.WriteLine(""); + } + + void try_reduce() + { + if (blocking_lits.size() == 0) + return; +// tab(); System.Console.Write ("Try to Reduce ");dump_lits(blocking_lit); ++ n_tab; + + IntVector common = new IntVector((IntVector) cls_occurrence[VID(blocking_lits[0])]); + for (int i=1; i< blocking_lits.size(); ++i) + { + int vid = VID(blocking_lits[i]); + IntVector next = (IntVector) cls_occurrence[vid]; + common = intersect (common, next); + } + bool resolved = false; + for (int i=0; i< common.size(); ++i) + { + int cl_id = common[i]; + int [] lits = solver.clause(cl_id).literals; + sharp_assert (lits.Length >= blocking_lits.size()); + if (lits.Length > blocking_lits.size()) + { + if (subsume (blocking_lits, lits)) + { +// tab();Console.Write ("Subsume CL:{0} ->", cl_id); dump_lits(lits); + remove_blocking (cl_id); + } + } + else + { + IntVector r = resolve (blocking_lits, lits); + if (r != null) + { +// tab();Console.Write ("Resolve CL:{0} ->", cl_id); dump_lits(lits); + resolved = true; + blocking_lits = r; + remove_blocking (cl_id); + break; + } + } + } + if (resolved) + try_reduce(); + //-- n_tab; + } + + bool find_blocking_cls (int s) + { + blocking_lits.clear(); + visiting_queue.clear(); + SATStatus status = solver.solve(); + if (status == SATStatus.UNSATISFIABLE) + return false; + sharp_assert (status == SATStatus.SATISFIABLE); + int vid = VID(s); + visiting_queue.push_back( vid ); + variable(vid).set_flag(visited_flag); + for (int i=0; i< visiting_queue.size(); ++i) + { + vid = visiting_queue[i]; + Variable var = variable(vid); + if (!var.flag(bound_flag)) //so it doesn't depends on bounded vars. + blocking_lits.push_back(vid + vid + solver.var_value(vid)); + else + { + if (var.type == NodeType.PI) + continue; + if (var.type == NodeType.AND && solver.var_value(vid) == 0) + { + int l; + if (solver.lit_value(var.left) != 0) + l = var.right; + else if (solver.lit_value(var.right) != 0) + l = var.left; + else + { // both inputs are 0 + if (node(var.left).flag(visited_flag)) + l = var.left; + else if (node(var.right).flag(visited_flag)) + l = var.right; + else //neither has been visited + l = var.left; + } + if (!node(l).flag(visited_flag)) + { + node(l).set_flag(visited_flag); + visiting_queue.push_back(VID(l)); + } + } + else + { + sharp_assert (var.type == NodeType.XOR || var.type == NodeType.AND); + int l = var.left; + if (!node(l).flag(visited_flag)) + { + node(l).set_flag(visited_flag); + visiting_queue.push_back(VID(l)); + } + l = var.right; + if (!node(l).flag(visited_flag)) + { + node(l).set_flag(visited_flag); + visiting_queue.push_back(VID(l)); + } + } + } + } + for (int i=0; i< visiting_queue.size(); ++i) + variable(visiting_queue[i]).clear_flag(visited_flag); + return true; + } + + public int enum_exist_quantify (int s, int [] bounded, bool block_with_pi_only) + { + int c = solver.constraint(s); + int block_gid = solver.alloc_gid(); + init_quantification(s, bounded, block_with_pi_only); + bool empty_cl = false; + int total_solution = 0; + //int total_clauses; + while (find_blocking_cls(s)) + { + //solver.restart(); + ++ total_solution; + try_reduce(); + if (blocking_lits.size() == 0) + { //blocking clause size 0, i.e. no literal + empty_cl = true; + break; + } + else + add_blocking(block_gid); + } + solver.release_constraint(c); + int r; + if (empty_cl) + r = solver.zero(); + else if (blocking_clauses.Count == 0) + r = solver.one(); + else + { + IntVector blocking = new IntVector(4); + foreach (object k in blocking_clauses.Keys) + blocking.push_back((int)k); + //total_clauses = blocking.size(); + r = build_struct (blocking); + } + solver.delete_clause_group(block_gid); + finalize_quantification(); +// Console.WriteLine ("Enum {0} solutions, total blocking clauses {1}", total_solution, total_clauses); + return solver.bnot(r); + } + + public int enum_exist_quantify_dumb (int s, int [] bounded, bool with_pi_only) + { + if (node(s).type == NodeType.CONSTANT) + return s; + + int c = solver.constraint(s); + int block_gid = solver.alloc_gid(); + init_quantification(s, bounded, with_pi_only); + bool empty_cl = false; + IntVector blocking = new IntVector(16); + while (find_blocking_cls(s)) + { + if (blocking_lits.size() == 0) + { //blocking clause size 0, i.e. no literal + empty_cl = true; + break; + } + else + { + int cl_id = solver.add_blocking_clause(blocking_lits.ToArray(), block_gid); + blocking.push_back(cl_id); + } + } + solver.release_constraint(c); + int r; + if (empty_cl) + r = solver.zero(); + else if (blocking.size() == 0) + r = solver.one(); + else + r = build_struct (blocking); + solver.delete_clause_group(block_gid); + finalize_quantification(); + return solver.bnot(r); + } + } + + public int enum_exist_quantify_smart (int s, int [] bounded) + { + if (node(s).type == NodeType.CONSTANT) + return s; + + EnumQuantification quant = new EnumQuantification(this); + int r = quant.enum_exist_quantify (s, bounded, false); + return r; + } + + public int enum_exist_quantify_dumb (int s, int [] bounded) + { + EnumQuantification quant = new EnumQuantification(this); + int r = quant.enum_exist_quantify_dumb (s, bounded, false); + return r; + } + + public int expand_exist_quantify (int s, int [] bounded) + { + int flag = alloc_flag(); + mark_transitive_fanins(s, flag); + int result = s; + foreach (int input in bounded) + { + sharp_assert (node(input).is_pi()); + int [] orig = { input }; + int [] replace = { zero() }; + int cofactor_i = compose(result, orig, replace); + replace = new int [] { one () }; + int cofactor_ip = compose(result, orig, replace); + result = bor (cofactor_i, cofactor_ip); + } + free_flag(flag); + return result; + } + + #region NODE_CONSISTENCY_LOOKUP + void make_node_consistent (int s) + { + Variable n = node(s); + if (!is_reasoning(n)) + return; + + int output = NON_NEGATED(s); + int input0 = n.left; + int input1 = n.right; + + int signature; + signature = lit_value(output); + signature = (signature << 2); + signature |= lit_value(input0); + signature = (signature << 2); + signature |= lit_value(input1); + + if (n.type == NodeType.AND) + { + switch(signature) + { + case 34: //100010 : x0x + case 35: //100011 : x0x + case 50: //110010 : x0x + case 51: //110011 : x0x + case 40: //101000 : xx0 + case 44: //101100 : xx0 + case 56: //111000 : xx0 + case 60: //111100 : xx0 + case 36: //100100 : x10 + case 52: //110100 : x10 + case 33: //100001 : x01 + case 49: //110001 : x01 + case 32: //100000 : x00 + case 48: //110000 : x00 + queue_implication(output^1, VID (output), ImpType.NODE); + break; + case 37: //100101 : x11 + case 53: //110101 : x11 + queue_implication(output, VID (output), ImpType.NODE); + break; + case 6: //000110 : 01x + case 7: //000111 : 01x + queue_implication(input1^1, VID (output), ImpType.NODE); + break; + case 13: //001101 : 0x1 + case 9: //001001 : 0x1 + queue_implication(input0^1, VID (output), ImpType.NODE); + break; + case 22: //010110 : 11x + case 23: //010111 : 11x + queue_implication(input1, VID (output), ImpType.NODE); + break; + case 29: //011101 : 1x1 + case 25: //011001 : 1x1 + queue_implication(input0, VID (output), ImpType.NODE); + break; + case 30: //011110 : 1xx + case 31: //011111 : 1xx + case 26: //011010 : 1xx + case 27: //011011 : 1xx + queue_implication(input0, VID (output), ImpType.NODE); + queue_implication(input1, VID (output), ImpType.NODE); + break; + case 18: //010010 : 10x + case 19: //010011 : 10x + case 24: //011000 : 1x0 + case 28: //011100 : 1x0 + + case 17: //010001 : 101 + case 20: //010100 : 110 + case 16: //010000 : 100 + case 5: //000101 : 011 + queue_conflict(VID (output), ImpType.NODE); + break; + case 42: //101010 : xxx + case 43: //101011 : xxx + case 46: //101110 : xxx + case 47: //101111 : xxx + + case 58: //111010 : xxx + case 59: //111011 : xxx + case 62: //111110 : xxx + case 63: //111111 : xxx + break; + case 41: //101001 : xx1 + case 45: //101101 : xx1 + case 57: //111001 : xx1 + case 61: //111101 : xx1 + + case 38: //100110 : x1x + case 39: //100111 : x1x + case 54: //110110 : x1x + case 55: //110111 : x1x + + case 2: //000010 : 00x + case 3: //000011 : 00x + case 8: //001000 : 0x0 + case 12: //001100 : 0x0 + + case 10: //001010 : 0xx + case 11: //001011 : 0xx + case 14: //001110 : 0xx + case 15: //001111 : 0xx + + case 21: //010101 : 111 + case 4: //000100 : 010 + case 1: //000001 : 001 + case 0: //000000 : 000 + break; + } + } + else + { + sharp_assert (n.type == NodeType.XOR); + switch(signature) + { + case 32: //100000 : x00 + case 48: //110000 : x00 + case 37: //100101 : x11 + case 53: //110101 : x11 + queue_implication(output^1, VID (output), ImpType.NODE); + break; + case 33: //100001 : x01 + case 49: //110001 : x01 + case 36: //100100 : x10 + case 52: //110100 : x10 + queue_implication(output, VID (output), ImpType.NODE); + break; + case 3: //000011 : 00x + case 2: //000010 : 00x + case 23: //010111 : 11x + case 22: //010110 : 11x + queue_implication(input1^1, VID (output), ImpType.NODE); + break; + case 7: //000111 : 01x + case 6: //000110 : 01x + case 19: //010011 : 10x + case 18: //010010 : 10x + queue_implication(input1, VID (output), ImpType.NODE); + break; + case 13: //001101 : 0x1 + case 9: //001001 : 0x1 + case 28: //011100 : 1x0 + case 24: //011000 : 1x0 + queue_implication(input0, VID (output), ImpType.NODE); + break; + case 12: //001100 : 0x0 + case 8: //001000 : 0x0 + case 29: //011101 : 1x1 + case 25: //011001 : 1x1 + queue_implication(input0^1, VID (output), ImpType.NODE); + break; + case 1: //000001 : 001 + case 4: //000100 : 010 + case 16: //010000 : 100 + case 21: //010101 : 111 + queue_conflict(VID (output), ImpType.NODE); + break; + case 42: //101010 : xxx + case 43: //101011 : xxx + case 46: //101110 : xxx + case 47: //101111 : xxx + case 58: //111010 : xxx + case 59: //111011 : xxx + case 62: //111110 : xxx + case 63: //111111 : xxx + break; + case 41: //101001 : xx1 + case 45: //101101 : xx1 + case 57: //111001 : xx1 + case 61: //111101 : xx1 + + case 40: //101000 : xx0 + case 44: //101100 : xx0 + case 56: //111000 : xx0 + case 60: //111100 : xx0 + + case 38: //100110 : x1x + case 39: //100111 : x1x + case 54: //110110 : x1x + case 55: //110111 : x1x + + case 34: //100010 : x0x + case 35: //100011 : x0x + case 50: //110010 : x0x + case 51: //110011 : x0x + + case 10: //001010 : 0xx + case 11: //001011 : 0xx + case 14: //001110 : 0xx + case 15: //001111 : 0xx + + case 26: //011010 : 1xx + case 27: //011011 : 1xx + case 30: //011110 : 1xx + case 31: //011111 : 1xx + + case 20: //010100 : 110 + case 17: //010001 : 101 + case 5: //000101 : 011 + case 0: //000000 : 000 + break; + } + } + } + #endregion + #region CANONICAL_TABLE_LOOKUP + private static readonly int [] lookup_table_3_inputs = + new int[320] { + /* 0 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + /* 10 */ 10, 11, 12, 13, 14, 15, 16, 17, 17, 16, + /* 20 */ 17, 16, 16, 17, 18, 19, 19, 18, 19, 18, + /* 30 */ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + /* 40 */ 24, 25, 26, 27, 20, 21, 22, 23, 28, 29, + /* 50 */ 29, 28, 29, 28, 28, 29, 29, 28, 28, 29, + /* 60 */ 28, 29, 29, 28, 30, 31, 32, 32, 31, 30, + /* 70 */ 33, 33, 32, 32, 34, 35, 36, 36, 35, 34, + /* 80 */ 31, 30, 30, 31, 30, 31, 31, 30, 34, 35, + /* 90 */ 35, 34, 35, 34, 34, 35, 31, 30, 37, 38, + /* 100 */ 39, 40, 35, 34, 39, 40, 35, 34, 31, 30, + /* 110 */ 37, 38, 41, 42, 42, 41, 42, 41, 41, 42, + /* 120 */ 42, 41, 41, 42, 41, 42, 42, 41, 43, 44, + /* 130 */ 45, 46, 4, 5, 6, 7, 47, 48, 49, 50, + /* 140 */ 12, 13, 14, 15, 16, 17, 17, 16, 17, 16, + /* 150 */ 16, 17, 18, 19, 19, 18, 19, 18, 18, 19, + /* 160 */ 20, 21, 22, 23, 24, 25, 26, 27, 24, 25, + /* 170 */ 26, 27, 20, 21, 22, 23, 51, 52, 52, 51, + /* 180 */ 52, 51, 51, 52, 52, 51, 51, 52, 51, 52, + /* 190 */ 52, 51, 30, 32, 34, 32, 34, 41, 30, 41, + /* 200 */ 32, 31, 32, 35, 42, 35, 42, 31, 34, 30, + /* 210 */ 30, 34, 30, 34, 34, 30, 31, 35, 35, 31, + /* 220 */ 35, 31, 31, 35, 34, 37, 30, 39, 38, 35, + /* 230 */ 40, 31, 38, 35, 40, 31, 34, 37, 30, 39, + /* 240 */ 33, 36, 36, 33, 36, 33, 33, 36, 36, 33, + /* 250 */ 33, 36, 33, 36, 36, 33, 53, 54, 55, 56, + /* 260 */ 4, 5, 6, 7, 57, 58, 59, 60, 12, 13, + /* 270 */ 14, 15, 16, 17, 17, 16, 17, 16, 16, 17, + /* 280 */ 18, 19, 19, 18, 19, 18, 18, 19, 20, 21, + /* 290 */ 22, 23, 24, 25, 26, 27, 24, 25, 26, 27, + /* 300 */ 20, 21, 22, 23, 61, 62, 62, 61, 62, 61, + /* 310 */ 61, 62, 62, 61, 61, 62, 61, 62, 62, 61 }; + private static readonly int [] lookup_table_4_inputs = + new int [4096] { + /* 0 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + /* 10 */ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + /* 20 */ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + /* 30 */ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + /* 40 */ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + /* 50 */ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + /* 60 */ 60, 61, 62, 63, 64, 65, 65, 64, 66, 67, + /* 70 */ 67, 66, 68, 69, 69, 68, 70, 71, 71, 70, + /* 80 */ 65, 64, 64, 65, 67, 66, 66, 67, 69, 68, + /* 90 */ 68, 69, 71, 70, 70, 71, 72, 73, 73, 72, + /* 100 */ 74, 75, 75, 74, 76, 77, 77, 76, 78, 79, + /* 110 */ 79, 78, 73, 72, 72, 73, 75, 74, 74, 75, + /* 120 */ 77, 76, 76, 77, 79, 78, 78, 79, 80, 81, + /* 130 */ 82, 83, 84, 85, 86, 87, 84, 85, 86, 87, + /* 140 */ 80, 81, 82, 83, 88, 89, 90, 91, 92, 93, + /* 150 */ 94, 95, 92, 93, 94, 95, 88, 89, 90, 91, + /* 160 */ 84, 85, 86, 87, 80, 81, 82, 83, 80, 81, + /* 170 */ 82, 83, 84, 85, 86, 87, 92, 93, 94, 95, + /* 180 */ 88, 89, 90, 91, 88, 89, 90, 91, 92, 93, + /* 190 */ 94, 95, 96, 97, 97, 96, 98, 99, 99, 98, + /* 200 */ 98, 99, 99, 98, 96, 97, 97, 96, 97, 96, + /* 210 */ 96, 97, 99, 98, 98, 99, 99, 98, 98, 99, + /* 220 */ 97, 96, 96, 97, 98, 99, 99, 98, 96, 97, + /* 230 */ 97, 96, 96, 97, 97, 96, 98, 99, 99, 98, + /* 240 */ 99, 98, 98, 99, 97, 96, 96, 97, 97, 96, + /* 250 */ 96, 97, 99, 98, 98, 99, 100, 101, 102, 103, + /* 260 */ 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + /* 270 */ 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, + /* 280 */ 124, 125, 126, 127, 128, 129, 130, 131, 116, 117, + /* 290 */ 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + /* 300 */ 128, 129, 130, 131, 100, 101, 102, 103, 104, 105, + /* 310 */ 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, + /* 320 */ 132, 133, 133, 132, 134, 135, 135, 134, 136, 137, + /* 330 */ 137, 136, 138, 139, 139, 138, 133, 132, 132, 133, + /* 340 */ 135, 134, 134, 135, 137, 136, 136, 137, 139, 138, + /* 350 */ 138, 139, 133, 132, 132, 133, 135, 134, 134, 135, + /* 360 */ 137, 136, 136, 137, 139, 138, 138, 139, 132, 133, + /* 370 */ 133, 132, 134, 135, 135, 134, 136, 137, 137, 136, + /* 380 */ 138, 139, 139, 138, 140, 141, 142, 143, 144, 145, + /* 390 */ 146, 147, 144, 145, 146, 147, 140, 141, 142, 143, + /* 400 */ 144, 145, 146, 147, 140, 141, 142, 143, 140, 141, + /* 410 */ 142, 143, 144, 145, 146, 147, 144, 145, 146, 147, + /* 420 */ 140, 141, 142, 143, 140, 141, 142, 143, 144, 145, + /* 430 */ 146, 147, 140, 141, 142, 143, 144, 145, 146, 147, + /* 440 */ 144, 145, 146, 147, 140, 141, 142, 143, 148, 149, + /* 450 */ 149, 148, 149, 148, 148, 149, 149, 148, 148, 149, + /* 460 */ 148, 149, 149, 148, 149, 148, 148, 149, 148, 149, + /* 470 */ 149, 148, 148, 149, 149, 148, 149, 148, 148, 149, + /* 480 */ 149, 148, 148, 149, 148, 149, 149, 148, 148, 149, + /* 490 */ 149, 148, 149, 148, 148, 149, 148, 149, 149, 148, + /* 500 */ 149, 148, 148, 149, 149, 148, 148, 149, 148, 149, + /* 510 */ 149, 148, 150, 151, 152, 152, 152, 152, 153, 154, + /* 520 */ 155, 156, 152, 152, 152, 152, 157, 158, 151, 150, + /* 530 */ 159, 159, 160, 160, 154, 153, 156, 155, 161, 161, + /* 540 */ 162, 162, 158, 157, 155, 156, 163, 164, 165, 166, + /* 550 */ 157, 158, 150, 151, 163, 164, 165, 166, 153, 154, + /* 560 */ 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, + /* 570 */ 177, 178, 179, 180, 181, 182, 151, 150, 150, 151, + /* 580 */ 153, 154, 154, 153, 156, 155, 155, 156, 157, 158, + /* 590 */ 158, 157, 150, 151, 151, 150, 154, 153, 153, 154, + /* 600 */ 155, 156, 156, 155, 158, 157, 157, 158, 183, 184, + /* 610 */ 184, 183, 185, 186, 186, 185, 187, 188, 188, 187, + /* 620 */ 189, 190, 190, 189, 184, 183, 183, 184, 186, 185, + /* 630 */ 185, 186, 188, 187, 187, 188, 190, 189, 189, 190, + /* 640 */ 155, 156, 153, 154, 150, 151, 157, 158, 150, 151, + /* 650 */ 157, 158, 155, 156, 153, 154, 191, 192, 193, 194, + /* 660 */ 195, 196, 197, 198, 195, 196, 197, 198, 191, 192, + /* 670 */ 193, 194, 150, 151, 157, 158, 155, 156, 153, 154, + /* 680 */ 155, 156, 153, 154, 150, 151, 157, 158, 195, 196, + /* 690 */ 197, 198, 191, 192, 193, 194, 191, 192, 193, 194, + /* 700 */ 195, 196, 197, 198, 199, 200, 200, 199, 201, 202, + /* 710 */ 202, 201, 201, 202, 202, 201, 199, 200, 200, 199, + /* 720 */ 200, 199, 199, 200, 202, 201, 201, 202, 202, 201, + /* 730 */ 201, 202, 200, 199, 199, 200, 201, 202, 202, 201, + /* 740 */ 199, 200, 200, 199, 199, 200, 200, 199, 201, 202, + /* 750 */ 202, 201, 202, 201, 201, 202, 200, 199, 199, 200, + /* 760 */ 200, 199, 199, 200, 202, 201, 201, 202, 203, 204, + /* 770 */ 178, 177, 180, 179, 205, 206, 204, 203, 170, 169, + /* 780 */ 172, 171, 206, 205, 207, 208, 169, 170, 171, 172, + /* 790 */ 209, 210, 208, 207, 177, 178, 179, 180, 210, 209, + /* 800 */ 207, 208, 169, 170, 171, 172, 209, 210, 208, 207, + /* 810 */ 177, 178, 179, 180, 210, 209, 203, 204, 178, 177, + /* 820 */ 180, 179, 205, 206, 204, 203, 170, 169, 172, 171, + /* 830 */ 206, 205, 211, 212, 212, 211, 213, 214, 214, 213, + /* 840 */ 215, 216, 216, 215, 217, 218, 218, 217, 212, 211, + /* 850 */ 211, 212, 214, 213, 213, 214, 216, 215, 215, 216, + /* 860 */ 218, 217, 217, 218, 212, 211, 211, 212, 214, 213, + /* 870 */ 213, 214, 216, 215, 215, 216, 218, 217, 217, 218, + /* 880 */ 211, 212, 212, 211, 213, 214, 214, 213, 215, 216, + /* 890 */ 216, 215, 217, 218, 218, 217, 219, 220, 221, 222, + /* 900 */ 223, 224, 225, 226, 223, 224, 225, 226, 219, 220, + /* 910 */ 221, 222, 223, 224, 225, 226, 219, 220, 221, 222, + /* 920 */ 219, 220, 221, 222, 223, 224, 225, 226, 223, 224, + /* 930 */ 225, 226, 219, 220, 221, 222, 219, 220, 221, 222, + /* 940 */ 223, 224, 225, 226, 219, 220, 221, 222, 223, 224, + /* 950 */ 225, 226, 223, 224, 225, 226, 219, 220, 221, 222, + /* 960 */ 227, 228, 228, 227, 228, 227, 227, 228, 228, 227, + /* 970 */ 227, 228, 227, 228, 228, 227, 228, 227, 227, 228, + /* 980 */ 227, 228, 228, 227, 227, 228, 228, 227, 228, 227, + /* 990 */ 227, 228, 228, 227, 227, 228, 227, 228, 228, 227, + /* 1000 */ 227, 228, 228, 227, 228, 227, 227, 228, 227, 228, + /* 1010 */ 228, 227, 228, 227, 227, 228, 228, 227, 227, 228, + /* 1020 */ 227, 228, 228, 227, 229, 230, 231, 232, 233, 234, + /* 1030 */ 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + /* 1040 */ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + /* 1050 */ 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + /* 1060 */ 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + /* 1070 */ 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + /* 1080 */ 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + /* 1090 */ 65, 64, 66, 67, 67, 66, 68, 69, 69, 68, + /* 1100 */ 70, 71, 71, 70, 65, 64, 64, 65, 67, 66, + /* 1110 */ 66, 67, 69, 68, 68, 69, 71, 70, 70, 71, + /* 1120 */ 72, 73, 73, 72, 74, 75, 75, 74, 76, 77, + /* 1130 */ 77, 76, 78, 79, 79, 78, 73, 72, 72, 73, + /* 1140 */ 75, 74, 74, 75, 77, 76, 76, 77, 79, 78, + /* 1150 */ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + /* 1160 */ 84, 85, 86, 87, 80, 81, 82, 83, 88, 89, + /* 1170 */ 90, 91, 92, 93, 94, 95, 92, 93, 94, 95, + /* 1180 */ 88, 89, 90, 91, 84, 85, 86, 87, 80, 81, + /* 1190 */ 82, 83, 80, 81, 82, 83, 84, 85, 86, 87, + /* 1200 */ 92, 93, 94, 95, 88, 89, 90, 91, 88, 89, + /* 1210 */ 90, 91, 92, 93, 94, 95, 96, 97, 97, 96, + /* 1220 */ 98, 99, 99, 98, 98, 99, 99, 98, 96, 97, + /* 1230 */ 97, 96, 97, 96, 96, 97, 99, 98, 98, 99, + /* 1240 */ 99, 98, 98, 99, 97, 96, 96, 97, 98, 99, + /* 1250 */ 99, 98, 96, 97, 97, 96, 96, 97, 97, 96, + /* 1260 */ 98, 99, 99, 98, 99, 98, 98, 99, 97, 96, + /* 1270 */ 96, 97, 97, 96, 96, 97, 99, 98, 98, 99, + /* 1280 */ 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + /* 1290 */ 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + /* 1300 */ 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, + /* 1310 */ 130, 131, 116, 117, 118, 119, 120, 121, 122, 123, + /* 1320 */ 124, 125, 126, 127, 128, 129, 130, 131, 100, 101, + /* 1330 */ 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + /* 1340 */ 112, 113, 114, 115, 132, 133, 133, 132, 134, 135, + /* 1350 */ 135, 134, 136, 137, 137, 136, 138, 139, 139, 138, + /* 1360 */ 133, 132, 132, 133, 135, 134, 134, 135, 137, 136, + /* 1370 */ 136, 137, 139, 138, 138, 139, 133, 132, 132, 133, + /* 1380 */ 135, 134, 134, 135, 137, 136, 136, 137, 139, 138, + /* 1390 */ 138, 139, 132, 133, 133, 132, 134, 135, 135, 134, + /* 1400 */ 136, 137, 137, 136, 138, 139, 139, 138, 140, 141, + /* 1410 */ 142, 143, 144, 145, 146, 147, 144, 145, 146, 147, + /* 1420 */ 140, 141, 142, 143, 144, 145, 146, 147, 140, 141, + /* 1430 */ 142, 143, 140, 141, 142, 143, 144, 145, 146, 147, + /* 1440 */ 144, 145, 146, 147, 140, 141, 142, 143, 140, 141, + /* 1450 */ 142, 143, 144, 145, 146, 147, 140, 141, 142, 143, + /* 1460 */ 144, 145, 146, 147, 144, 145, 146, 147, 140, 141, + /* 1470 */ 142, 143, 245, 246, 246, 245, 246, 245, 245, 246, + /* 1480 */ 246, 245, 245, 246, 245, 246, 246, 245, 246, 245, + /* 1490 */ 245, 246, 245, 246, 246, 245, 245, 246, 246, 245, + /* 1500 */ 246, 245, 245, 246, 246, 245, 245, 246, 245, 246, + /* 1510 */ 246, 245, 245, 246, 246, 245, 246, 245, 245, 246, + /* 1520 */ 245, 246, 246, 245, 246, 245, 245, 246, 246, 245, + /* 1530 */ 245, 246, 245, 246, 246, 245, 150, 152, 153, 152, + /* 1540 */ 152, 151, 152, 154, 155, 152, 157, 152, 152, 156, + /* 1550 */ 152, 158, 153, 247, 150, 247, 248, 154, 248, 151, + /* 1560 */ 157, 249, 155, 249, 250, 158, 250, 156, 155, 166, + /* 1570 */ 157, 164, 165, 156, 163, 158, 150, 166, 153, 164, + /* 1580 */ 165, 151, 163, 154, 251, 252, 253, 254, 255, 256, + /* 1590 */ 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, + /* 1600 */ 153, 150, 150, 153, 151, 154, 154, 151, 157, 155, + /* 1610 */ 155, 157, 156, 158, 158, 156, 150, 153, 153, 150, + /* 1620 */ 154, 151, 151, 154, 155, 157, 157, 155, 158, 156, + /* 1630 */ 156, 158, 185, 184, 184, 185, 183, 186, 186, 183, + /* 1640 */ 189, 188, 188, 189, 187, 190, 190, 187, 184, 185, + /* 1650 */ 185, 184, 186, 183, 183, 186, 188, 189, 189, 188, + /* 1660 */ 190, 187, 187, 190, 155, 151, 157, 154, 150, 156, + /* 1670 */ 153, 158, 150, 156, 153, 158, 155, 151, 157, 154, + /* 1680 */ 267, 268, 269, 270, 271, 272, 273, 274, 271, 272, + /* 1690 */ 273, 274, 267, 268, 269, 270, 150, 156, 153, 158, + /* 1700 */ 155, 151, 157, 154, 155, 151, 157, 154, 150, 156, + /* 1710 */ 153, 158, 271, 272, 273, 274, 267, 268, 269, 270, + /* 1720 */ 267, 268, 269, 270, 271, 272, 273, 274, 201, 200, + /* 1730 */ 200, 201, 199, 202, 202, 199, 199, 202, 202, 199, + /* 1740 */ 201, 200, 200, 201, 200, 201, 201, 200, 202, 199, + /* 1750 */ 199, 202, 202, 199, 199, 202, 200, 201, 201, 200, + /* 1760 */ 199, 202, 202, 199, 201, 200, 200, 201, 201, 200, + /* 1770 */ 200, 201, 199, 202, 202, 199, 202, 199, 199, 202, + /* 1780 */ 200, 201, 201, 200, 200, 201, 201, 200, 202, 199, + /* 1790 */ 199, 202, 275, 262, 276, 260, 265, 277, 263, 278, + /* 1800 */ 276, 254, 275, 252, 257, 278, 255, 277, 279, 252, + /* 1810 */ 280, 254, 255, 281, 257, 282, 280, 260, 279, 262, + /* 1820 */ 263, 282, 265, 281, 279, 252, 280, 254, 255, 281, + /* 1830 */ 257, 282, 280, 260, 279, 262, 263, 282, 265, 281, + /* 1840 */ 275, 262, 276, 260, 265, 277, 263, 278, 276, 254, + /* 1850 */ 275, 252, 257, 278, 255, 277, 283, 284, 284, 283, + /* 1860 */ 285, 286, 286, 285, 287, 288, 288, 287, 289, 290, + /* 1870 */ 290, 289, 284, 283, 283, 284, 286, 285, 285, 286, + /* 1880 */ 288, 287, 287, 288, 290, 289, 289, 290, 284, 283, + /* 1890 */ 283, 284, 286, 285, 285, 286, 288, 287, 287, 288, + /* 1900 */ 290, 289, 289, 290, 283, 284, 284, 283, 285, 286, + /* 1910 */ 286, 285, 287, 288, 288, 287, 289, 290, 290, 289, + /* 1920 */ 226, 221, 220, 223, 222, 225, 224, 219, 222, 225, + /* 1930 */ 224, 219, 226, 221, 220, 223, 222, 225, 224, 219, + /* 1940 */ 226, 221, 220, 223, 226, 221, 220, 223, 222, 225, + /* 1950 */ 224, 219, 222, 225, 224, 219, 226, 221, 220, 223, + /* 1960 */ 226, 221, 220, 223, 222, 225, 224, 219, 226, 221, + /* 1970 */ 220, 223, 222, 225, 224, 219, 222, 225, 224, 219, + /* 1980 */ 226, 221, 220, 223, 291, 292, 292, 291, 292, 291, + /* 1990 */ 291, 292, 292, 291, 291, 292, 291, 292, 292, 291, + /* 2000 */ 292, 291, 291, 292, 291, 292, 292, 291, 291, 292, + /* 2010 */ 292, 291, 292, 291, 291, 292, 292, 291, 291, 292, + /* 2020 */ 291, 292, 292, 291, 291, 292, 292, 291, 292, 291, + /* 2030 */ 291, 292, 291, 292, 292, 291, 292, 291, 291, 292, + /* 2040 */ 292, 291, 291, 292, 291, 292, 292, 291, 293, 294, + /* 2050 */ 152, 152, 295, 296, 152, 152, 152, 152, 297, 298, + /* 2060 */ 152, 152, 299, 300, 294, 293, 301, 301, 296, 295, + /* 2070 */ 302, 302, 303, 303, 298, 297, 304, 304, 300, 299, + /* 2080 */ 295, 296, 163, 164, 293, 294, 163, 164, 165, 166, + /* 2090 */ 299, 300, 165, 166, 297, 298, 305, 306, 307, 308, + /* 2100 */ 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, + /* 2110 */ 319, 320, 294, 293, 293, 294, 296, 295, 295, 296, + /* 2120 */ 297, 298, 298, 297, 299, 300, 300, 299, 293, 294, + /* 2130 */ 294, 293, 295, 296, 296, 295, 298, 297, 297, 298, + /* 2140 */ 300, 299, 299, 300, 321, 322, 322, 321, 323, 324, + /* 2150 */ 324, 323, 325, 326, 326, 325, 327, 328, 328, 327, + /* 2160 */ 322, 321, 321, 322, 324, 323, 323, 324, 326, 325, + /* 2170 */ 325, 326, 328, 327, 327, 328, 295, 296, 297, 298, + /* 2180 */ 293, 294, 299, 300, 293, 294, 299, 300, 295, 296, + /* 2190 */ 297, 298, 329, 330, 331, 332, 333, 334, 335, 336, + /* 2200 */ 333, 334, 335, 336, 329, 330, 331, 332, 293, 294, + /* 2210 */ 299, 300, 295, 296, 297, 298, 295, 296, 297, 298, + /* 2220 */ 293, 294, 299, 300, 333, 334, 335, 336, 329, 330, + /* 2230 */ 331, 332, 329, 330, 331, 332, 333, 334, 335, 336, + /* 2240 */ 337, 338, 338, 337, 339, 340, 340, 339, 339, 340, + /* 2250 */ 340, 339, 337, 338, 338, 337, 338, 337, 337, 338, + /* 2260 */ 340, 339, 339, 340, 340, 339, 339, 340, 338, 337, + /* 2270 */ 337, 338, 339, 340, 340, 339, 337, 338, 338, 337, + /* 2280 */ 337, 338, 338, 337, 339, 340, 340, 339, 340, 339, + /* 2290 */ 339, 340, 338, 337, 337, 338, 338, 337, 337, 338, + /* 2300 */ 340, 339, 339, 340, 341, 342, 312, 311, 342, 341, + /* 2310 */ 308, 307, 318, 317, 343, 344, 314, 313, 344, 343, + /* 2320 */ 345, 346, 307, 308, 346, 345, 311, 312, 313, 314, + /* 2330 */ 347, 348, 317, 318, 348, 347, 345, 346, 307, 308, + /* 2340 */ 346, 345, 311, 312, 313, 314, 347, 348, 317, 318, + /* 2350 */ 348, 347, 341, 342, 312, 311, 342, 341, 308, 307, + /* 2360 */ 318, 317, 343, 344, 314, 313, 344, 343, 349, 350, + /* 2370 */ 350, 349, 351, 352, 352, 351, 353, 354, 354, 353, + /* 2380 */ 355, 356, 356, 355, 350, 349, 349, 350, 352, 351, + /* 2390 */ 351, 352, 354, 353, 353, 354, 356, 355, 355, 356, + /* 2400 */ 350, 349, 349, 350, 352, 351, 351, 352, 354, 353, + /* 2410 */ 353, 354, 356, 355, 355, 356, 349, 350, 350, 349, + /* 2420 */ 351, 352, 352, 351, 353, 354, 354, 353, 355, 356, + /* 2430 */ 356, 355, 357, 358, 359, 360, 361, 362, 363, 364, + /* 2440 */ 361, 362, 363, 364, 357, 358, 359, 360, 361, 362, + /* 2450 */ 363, 364, 357, 358, 359, 360, 357, 358, 359, 360, + /* 2460 */ 361, 362, 363, 364, 361, 362, 363, 364, 357, 358, + /* 2470 */ 359, 360, 357, 358, 359, 360, 361, 362, 363, 364, + /* 2480 */ 357, 358, 359, 360, 361, 362, 363, 364, 361, 362, + /* 2490 */ 363, 364, 357, 358, 359, 360, 365, 366, 366, 365, + /* 2500 */ 366, 365, 365, 366, 366, 365, 365, 366, 365, 366, + /* 2510 */ 366, 365, 366, 365, 365, 366, 365, 366, 366, 365, + /* 2520 */ 365, 366, 366, 365, 366, 365, 365, 366, 366, 365, + /* 2530 */ 365, 366, 365, 366, 366, 365, 365, 366, 366, 365, + /* 2540 */ 366, 365, 365, 366, 365, 366, 366, 365, 366, 365, + /* 2550 */ 365, 366, 366, 365, 365, 366, 365, 366, 366, 365, + /* 2560 */ 165, 152, 152, 152, 152, 166, 152, 152, 152, 152, + /* 2570 */ 163, 152, 152, 152, 152, 164, 152, 165, 165, 165, + /* 2580 */ 166, 152, 166, 166, 163, 163, 152, 163, 164, 164, + /* 2590 */ 164, 152, 152, 166, 163, 164, 165, 152, 163, 164, + /* 2600 */ 165, 166, 152, 164, 165, 166, 163, 152, 367, 368, + /* 2610 */ 369, 370, 368, 371, 372, 373, 369, 372, 374, 375, + /* 2620 */ 370, 373, 375, 376, 152, 165, 165, 152, 166, 152, + /* 2630 */ 152, 166, 163, 152, 152, 163, 152, 164, 164, 152, + /* 2640 */ 165, 152, 152, 165, 152, 166, 166, 152, 152, 163, + /* 2650 */ 163, 152, 164, 152, 152, 164, 370, 164, 164, 370, + /* 2660 */ 163, 372, 372, 163, 166, 372, 372, 166, 370, 165, + /* 2670 */ 165, 370, 164, 370, 370, 164, 372, 163, 163, 372, + /* 2680 */ 372, 166, 166, 372, 165, 370, 370, 165, 152, 166, + /* 2690 */ 163, 152, 165, 152, 152, 164, 165, 152, 152, 164, + /* 2700 */ 152, 166, 163, 152, 370, 163, 166, 370, 164, 372, + /* 2710 */ 372, 165, 164, 372, 372, 165, 370, 163, 166, 370, + /* 2720 */ 165, 152, 152, 164, 152, 166, 163, 152, 152, 166, + /* 2730 */ 163, 152, 165, 152, 152, 164, 164, 372, 372, 165, + /* 2740 */ 370, 163, 166, 370, 370, 163, 166, 370, 164, 372, + /* 2750 */ 372, 165, 370, 152, 152, 370, 152, 372, 372, 152, + /* 2760 */ 152, 372, 372, 152, 370, 152, 152, 370, 152, 370, + /* 2770 */ 370, 152, 372, 152, 152, 372, 372, 152, 152, 372, + /* 2780 */ 152, 370, 370, 152, 152, 372, 372, 152, 370, 152, + /* 2790 */ 152, 370, 370, 152, 152, 370, 152, 372, 372, 152, + /* 2800 */ 372, 152, 152, 372, 152, 370, 370, 152, 152, 370, + /* 2810 */ 370, 152, 372, 152, 152, 372, 152, 375, 373, 372, + /* 2820 */ 375, 152, 370, 369, 373, 370, 152, 368, 372, 369, + /* 2830 */ 368, 152, 377, 368, 369, 370, 368, 377, 372, 373, + /* 2840 */ 369, 372, 377, 375, 370, 373, 375, 377, 377, 368, + /* 2850 */ 369, 370, 368, 377, 372, 373, 369, 372, 377, 375, + /* 2860 */ 370, 373, 375, 377, 152, 375, 373, 372, 375, 152, + /* 2870 */ 370, 369, 373, 370, 152, 368, 372, 369, 368, 152, + /* 2880 */ 376, 164, 164, 376, 163, 374, 374, 163, 166, 371, + /* 2890 */ 371, 166, 367, 165, 165, 367, 164, 376, 376, 164, + /* 2900 */ 374, 163, 163, 374, 371, 166, 166, 371, 165, 367, + /* 2910 */ 367, 165, 164, 376, 376, 164, 374, 163, 163, 374, + /* 2920 */ 371, 166, 166, 371, 165, 367, 367, 165, 376, 164, + /* 2930 */ 164, 376, 163, 374, 374, 163, 166, 371, 371, 166, + /* 2940 */ 367, 165, 165, 367, 376, 163, 166, 367, 164, 374, + /* 2950 */ 371, 165, 164, 374, 371, 165, 376, 163, 166, 367, + /* 2960 */ 164, 374, 371, 165, 376, 163, 166, 367, 376, 163, + /* 2970 */ 166, 367, 164, 374, 371, 165, 164, 374, 371, 165, + /* 2980 */ 376, 163, 166, 367, 376, 163, 166, 367, 164, 374, + /* 2990 */ 371, 165, 376, 163, 166, 367, 164, 374, 371, 165, + /* 3000 */ 164, 374, 371, 165, 376, 163, 166, 367, 152, 377, + /* 3010 */ 377, 152, 377, 152, 152, 377, 377, 152, 152, 377, + /* 3020 */ 152, 377, 377, 152, 377, 152, 152, 377, 152, 377, + /* 3030 */ 377, 152, 152, 377, 377, 152, 377, 152, 152, 377, + /* 3040 */ 377, 152, 152, 377, 152, 377, 377, 152, 152, 377, + /* 3050 */ 377, 152, 377, 152, 152, 377, 152, 377, 377, 152, + /* 3060 */ 377, 152, 152, 377, 377, 152, 152, 377, 152, 377, + /* 3070 */ 377, 152, 378, 379, 380, 381, 382, 383, 384, 385, + /* 3080 */ 386, 387, 388, 389, 390, 391, 392, 393, 16, 17, + /* 3090 */ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, + /* 3100 */ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + /* 3110 */ 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + /* 3120 */ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + /* 3130 */ 58, 59, 60, 61, 62, 63, 64, 65, 65, 64, + /* 3140 */ 66, 67, 67, 66, 68, 69, 69, 68, 70, 71, + /* 3150 */ 71, 70, 65, 64, 64, 65, 67, 66, 66, 67, + /* 3160 */ 69, 68, 68, 69, 71, 70, 70, 71, 72, 73, + /* 3170 */ 73, 72, 74, 75, 75, 74, 76, 77, 77, 76, + /* 3180 */ 78, 79, 79, 78, 73, 72, 72, 73, 75, 74, + /* 3190 */ 74, 75, 77, 76, 76, 77, 79, 78, 78, 79, + /* 3200 */ 80, 81, 82, 83, 84, 85, 86, 87, 84, 85, + /* 3210 */ 86, 87, 80, 81, 82, 83, 88, 89, 90, 91, + /* 3220 */ 92, 93, 94, 95, 92, 93, 94, 95, 88, 89, + /* 3230 */ 90, 91, 84, 85, 86, 87, 80, 81, 82, 83, + /* 3240 */ 80, 81, 82, 83, 84, 85, 86, 87, 92, 93, + /* 3250 */ 94, 95, 88, 89, 90, 91, 88, 89, 90, 91, + /* 3260 */ 92, 93, 94, 95, 96, 97, 97, 96, 98, 99, + /* 3270 */ 99, 98, 98, 99, 99, 98, 96, 97, 97, 96, + /* 3280 */ 97, 96, 96, 97, 99, 98, 98, 99, 99, 98, + /* 3290 */ 98, 99, 97, 96, 96, 97, 98, 99, 99, 98, + /* 3300 */ 96, 97, 97, 96, 96, 97, 97, 96, 98, 99, + /* 3310 */ 99, 98, 99, 98, 98, 99, 97, 96, 96, 97, + /* 3320 */ 97, 96, 96, 97, 99, 98, 98, 99, 100, 101, + /* 3330 */ 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, + /* 3340 */ 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + /* 3350 */ 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, + /* 3360 */ 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, + /* 3370 */ 126, 127, 128, 129, 130, 131, 100, 101, 102, 103, + /* 3380 */ 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + /* 3390 */ 114, 115, 132, 133, 133, 132, 134, 135, 135, 134, + /* 3400 */ 136, 137, 137, 136, 138, 139, 139, 138, 133, 132, + /* 3410 */ 132, 133, 135, 134, 134, 135, 137, 136, 136, 137, + /* 3420 */ 139, 138, 138, 139, 133, 132, 132, 133, 135, 134, + /* 3430 */ 134, 135, 137, 136, 136, 137, 139, 138, 138, 139, + /* 3440 */ 132, 133, 133, 132, 134, 135, 135, 134, 136, 137, + /* 3450 */ 137, 136, 138, 139, 139, 138, 140, 141, 142, 143, + /* 3460 */ 144, 145, 146, 147, 144, 145, 146, 147, 140, 141, + /* 3470 */ 142, 143, 144, 145, 146, 147, 140, 141, 142, 143, + /* 3480 */ 140, 141, 142, 143, 144, 145, 146, 147, 144, 145, + /* 3490 */ 146, 147, 140, 141, 142, 143, 140, 141, 142, 143, + /* 3500 */ 144, 145, 146, 147, 140, 141, 142, 143, 144, 145, + /* 3510 */ 146, 147, 144, 145, 146, 147, 140, 141, 142, 143, + /* 3520 */ 394, 395, 395, 394, 395, 394, 394, 395, 395, 394, + /* 3530 */ 394, 395, 394, 395, 395, 394, 395, 394, 394, 395, + /* 3540 */ 394, 395, 395, 394, 394, 395, 395, 394, 395, 394, + /* 3550 */ 394, 395, 395, 394, 394, 395, 394, 395, 395, 394, + /* 3560 */ 394, 395, 395, 394, 395, 394, 394, 395, 394, 395, + /* 3570 */ 395, 394, 395, 394, 394, 395, 395, 394, 394, 395, + /* 3580 */ 394, 395, 395, 394, 396, 152, 397, 152, 152, 398, + /* 3590 */ 152, 399, 400, 152, 401, 152, 152, 402, 152, 403, + /* 3600 */ 397, 247, 396, 247, 248, 399, 248, 398, 401, 249, + /* 3610 */ 400, 249, 250, 403, 250, 402, 400, 166, 401, 164, + /* 3620 */ 165, 402, 163, 403, 396, 166, 397, 164, 165, 398, + /* 3630 */ 163, 399, 404, 405, 406, 407, 408, 409, 410, 411, + /* 3640 */ 412, 413, 414, 415, 416, 417, 418, 419, 397, 396, + /* 3650 */ 396, 397, 398, 399, 399, 398, 401, 400, 400, 401, + /* 3660 */ 402, 403, 403, 402, 396, 397, 397, 396, 399, 398, + /* 3670 */ 398, 399, 400, 401, 401, 400, 403, 402, 402, 403, + /* 3680 */ 420, 421, 421, 420, 422, 423, 423, 422, 424, 425, + /* 3690 */ 425, 424, 426, 427, 427, 426, 421, 420, 420, 421, + /* 3700 */ 423, 422, 422, 423, 425, 424, 424, 425, 427, 426, + /* 3710 */ 426, 427, 400, 398, 401, 399, 396, 402, 397, 403, + /* 3720 */ 396, 402, 397, 403, 400, 398, 401, 399, 428, 429, + /* 3730 */ 430, 431, 432, 433, 434, 435, 432, 433, 434, 435, + /* 3740 */ 428, 429, 430, 431, 396, 402, 397, 403, 400, 398, + /* 3750 */ 401, 399, 400, 398, 401, 399, 396, 402, 397, 403, + /* 3760 */ 432, 433, 434, 435, 428, 429, 430, 431, 428, 429, + /* 3770 */ 430, 431, 432, 433, 434, 435, 436, 437, 437, 436, + /* 3780 */ 438, 439, 439, 438, 438, 439, 439, 438, 436, 437, + /* 3790 */ 437, 436, 437, 436, 436, 437, 439, 438, 438, 439, + /* 3800 */ 439, 438, 438, 439, 437, 436, 436, 437, 438, 439, + /* 3810 */ 439, 438, 436, 437, 437, 436, 436, 437, 437, 436, + /* 3820 */ 438, 439, 439, 438, 439, 438, 438, 439, 437, 436, + /* 3830 */ 436, 437, 437, 436, 436, 437, 439, 438, 438, 439, + /* 3840 */ 440, 415, 441, 413, 418, 442, 416, 443, 441, 407, + /* 3850 */ 440, 405, 410, 443, 408, 442, 444, 405, 445, 407, + /* 3860 */ 408, 446, 410, 447, 445, 413, 444, 415, 416, 447, + /* 3870 */ 418, 446, 444, 405, 445, 407, 408, 446, 410, 447, + /* 3880 */ 445, 413, 444, 415, 416, 447, 418, 446, 440, 415, + /* 3890 */ 441, 413, 418, 442, 416, 443, 441, 407, 440, 405, + /* 3900 */ 410, 443, 408, 442, 283, 284, 284, 283, 285, 286, + /* 3910 */ 286, 285, 287, 288, 288, 287, 289, 290, 290, 289, + /* 3920 */ 284, 283, 283, 284, 286, 285, 285, 286, 288, 287, + /* 3930 */ 287, 288, 290, 289, 289, 290, 284, 283, 283, 284, + /* 3940 */ 286, 285, 285, 286, 288, 287, 287, 288, 290, 289, + /* 3950 */ 289, 290, 283, 284, 284, 283, 285, 286, 286, 285, + /* 3960 */ 287, 288, 288, 287, 289, 290, 290, 289, 226, 221, + /* 3970 */ 220, 223, 222, 225, 224, 219, 222, 225, 224, 219, + /* 3980 */ 226, 221, 220, 223, 222, 225, 224, 219, 226, 221, + /* 3990 */ 220, 223, 226, 221, 220, 223, 222, 225, 224, 219, + /* 4000 */ 222, 225, 224, 219, 226, 221, 220, 223, 226, 221, + /* 4010 */ 220, 223, 222, 225, 224, 219, 226, 221, 220, 223, + /* 4020 */ 222, 225, 224, 219, 222, 225, 224, 219, 226, 221, + /* 4030 */ 220, 223, 448, 449, 449, 448, 449, 448, 448, 449, + /* 4040 */ 449, 448, 448, 449, 448, 449, 449, 448, 449, 448, + /* 4050 */ 448, 449, 448, 449, 449, 448, 448, 449, 449, 448, + /* 4060 */ 449, 448, 448, 449, 449, 448, 448, 449, 448, 449, + /* 4070 */ 449, 448, 448, 449, 449, 448, 449, 448, 448, 449, + /* 4080 */ 448, 449, 449, 448, 449, 448, 448, 449, 449, 448, + /* 4090 */ 448, 449, 448, 449, 449, 448 }; + + int look_up_3_input_node (NodeType op, int i1, int i2, int signature) + { + int ll_nn = NON_NEGATED( node(i1).left ); + int lr_nn = NON_NEGATED( node(i1).right ); + int r_nn = NON_NEGATED( i2 ); + + int result = INVALID; + int idx = lookup_table_3_inputs[signature]; + + switch (idx) + { + case 0: // i1 i2 and i3 and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, r_nn ); + result = temp1; + break; + } + case 1: // i1 neg i2 and i3 and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, r_nn ); + result = temp1; + break; + } + case 2: // i1 i2 neg and i3 and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.AND, temp0, r_nn ); + result = temp1; + break; + } + case 3: // i1 neg i2 neg and i3 and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.AND, temp0, r_nn ); + result = temp1; + break; + } + case 4: // i1 i2 and neg i3 and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), r_nn ); + result = temp1; + break; + } + case 5: // i1 neg i2 and neg i3 and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), r_nn ); + result = temp1; + break; + } + case 6: // i1 i2 neg and neg i3 and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), r_nn ); + result = temp1; + break; + } + case 7: // i1 neg i2 neg and neg i3 and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), r_nn ); + result = temp1; + break; + } + case 8: // i1 i2 and i3 neg and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( r_nn ) ); + result = temp1; + break; + } + case 9: // i1 neg i2 and i3 neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( r_nn ) ); + result = temp1; + break; + } + case 10: // i1 i2 neg and i3 neg and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( r_nn ) ); + result = temp1; + break; + } + case 11: // i1 neg i2 neg and i3 neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( r_nn ) ); + result = temp1; + break; + } + case 12: // i1 i2 and neg i3 neg and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( r_nn ) ); + result = temp1; + break; + } + case 13: // i1 neg i2 and neg i3 neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( r_nn ) ); + result = temp1; + break; + } + case 14: // i1 i2 neg and neg i3 neg and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( r_nn ) ); + result = temp1; + break; + } + case 15: // i1 neg i2 neg and neg i3 neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( r_nn ) ); + result = temp1; + break; + } + case 16: // i1 i2 xor i3 and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, r_nn ); + result = temp1; + break; + } + case 17: // i1 i2 xor neg i3 and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), r_nn ); + result = temp1; + break; + } + case 18: // i1 i2 xor i3 neg and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( r_nn ) ); + result = temp1; + break; + } + case 19: // i1 i2 xor neg i3 neg and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( r_nn ) ); + result = temp1; + break; + } + case 20: // i1 i2 and i3 xor + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, r_nn ); + result = temp1; + break; + } + case 21: // i1 neg i2 and i3 xor + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, r_nn ); + result = temp1; + break; + } + case 22: // i1 i2 neg and i3 xor + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.XOR, temp0, r_nn ); + result = temp1; + break; + } + case 23: // i1 neg i2 neg and i3 xor + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.XOR, temp0, r_nn ); + result = temp1; + break; + } + case 24: // i1 i2 and i3 xor neg + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, r_nn ); + result = NEGATE( temp1 ); + break; + } + case 25: // i1 neg i2 and i3 xor neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, r_nn ); + result = NEGATE( temp1 ); + break; + } + case 26: // i1 i2 neg and i3 xor neg + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.XOR, temp0, r_nn ); + result = NEGATE( temp1 ); + break; + } + case 27: // i1 neg i2 neg and i3 xor neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.XOR, temp0, r_nn ); + result = NEGATE( temp1 ); + break; + } + case 28: // i1 i2 xor i3 xor + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, r_nn ); + result = temp1; + break; + } + case 29: // i1 i2 xor i3 xor neg + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, r_nn ); + result = NEGATE( temp1 ); + break; + } + case 30: // i1 i2 and + { + int temp0 = create_op_node (NodeType.AND, ll_nn, lr_nn ); + result = temp0; + break; + } + case 31: // i1 neg i2 and + { + int temp0 = create_op_node (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + result = temp0; + break; + } + case 32: // neg + { + result = zero(); + break; + } + case 33: // i2 + { + result = lr_nn; + break; + } + case 34: // i1 i2 neg and + { + int temp0 = create_op_node (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + result = temp0; + break; + } + case 35: // i1 neg i2 neg and + { + int temp0 = create_op_node (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + result = temp0; + break; + } + case 36: // i2 neg + { + result = NEGATE( lr_nn ); + break; + } + case 37: // i1 neg i2 neg and neg + { + int temp0 = create_op_node (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + result = NEGATE( temp0 ); + break; + } + case 38: // i1 i2 neg and neg + { + int temp0 = create_op_node (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + result = NEGATE( temp0 ); + break; + } + case 39: // i1 neg i2 and neg + { + int temp0 = create_op_node (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + result = NEGATE( temp0 ); + break; + } + case 40: // i1 i2 and neg + { + int temp0 = create_op_node (NodeType.AND, ll_nn, lr_nn ); + result = NEGATE( temp0 ); + break; + } + case 41: // i1 + { + result = ll_nn; + break; + } + case 42: // i1 neg + { + result = NEGATE( ll_nn ); + break; + } + case 43: // i1 i3 and i2 and + { + int temp0 = create (NodeType.AND, ll_nn, r_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, lr_nn ); + result = temp1; + break; + } + case 44: // i1 neg i3 and i2 and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), r_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, lr_nn ); + result = temp1; + break; + } + case 45: // i1 i3 and i2 neg and + { + int temp0 = create (NodeType.AND, ll_nn, r_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( lr_nn ) ); + result = temp1; + break; + } + case 46: // i1 neg i3 and i2 neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), r_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( lr_nn ) ); + result = temp1; + break; + } + case 47: // i1 i3 neg and i2 and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( r_nn ) ); + int temp1 = create_op_node (NodeType.AND, temp0, lr_nn ); + result = temp1; + break; + } + case 48: // i1 neg i3 neg and i2 and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( r_nn ) ); + int temp1 = create_op_node (NodeType.AND, temp0, lr_nn ); + result = temp1; + break; + } + case 49: // i1 i3 neg and i2 neg and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( r_nn ) ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( lr_nn ) ); + result = temp1; + break; + } + case 50: // i1 neg i3 neg and i2 neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( r_nn ) ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( lr_nn ) ); + result = temp1; + break; + } + case 51: // i1 i3 xor i2 xor + { + int temp0 = create (NodeType.XOR, ll_nn, r_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, lr_nn ); + result = temp1; + break; + } + case 52: // i1 i3 xor i2 xor neg + { + int temp0 = create (NodeType.XOR, ll_nn, r_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, lr_nn ); + result = NEGATE( temp1 ); + break; + } + case 53: // i3 i1 and i2 and + { + int temp0 = create (NodeType.AND, r_nn, ll_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, lr_nn ); + result = temp1; + break; + } + case 54: // i3 i1 neg and i2 and + { + int temp0 = create (NodeType.AND, r_nn, NEGATE( ll_nn ) ); + int temp1 = create_op_node (NodeType.AND, temp0, lr_nn ); + result = temp1; + break; + } + case 55: // i3 i1 and i2 neg and + { + int temp0 = create (NodeType.AND, r_nn, ll_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( lr_nn ) ); + result = temp1; + break; + } + case 56: // i3 i1 neg and i2 neg and + { + int temp0 = create (NodeType.AND, r_nn, NEGATE( ll_nn ) ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( lr_nn ) ); + result = temp1; + break; + } + case 57: // i3 neg i1 and i2 and + { + int temp0 = create (NodeType.AND, NEGATE( r_nn ), ll_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, lr_nn ); + result = temp1; + break; + } + case 58: // i3 neg i1 neg and i2 and + { + int temp0 = create (NodeType.AND, NEGATE( r_nn ), NEGATE( ll_nn ) ); + int temp1 = create_op_node (NodeType.AND, temp0, lr_nn ); + result = temp1; + break; + } + case 59: // i3 neg i1 and i2 neg and + { + int temp0 = create (NodeType.AND, NEGATE( r_nn ), ll_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( lr_nn ) ); + result = temp1; + break; + } + case 60: // i3 neg i1 neg and i2 neg and + { + int temp0 = create (NodeType.AND, NEGATE( r_nn ), NEGATE( ll_nn ) ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( lr_nn ) ); + result = temp1; + break; + } + case 61: // i3 i1 xor i2 xor + { + int temp0 = create (NodeType.XOR, r_nn, ll_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, lr_nn ); + result = temp1; + break; + } + case 62: // i3 i1 xor i2 xor neg + { + int temp0 = create (NodeType.XOR, r_nn, ll_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, lr_nn ); + result = NEGATE( temp1 ); + break; + } + default: + throw new Exception ("Unknown Cases"); + } + return result; + } + + int look_up_4_input_node (NodeType op, int i1, int i2, int signature) + { + int ll_nn = NON_NEGATED( node(i1).input(0) ); + int lr_nn = NON_NEGATED( node(i1).input(1) ); + int rl_nn = NON_NEGATED( node(i2).input(0) ); + int rr_nn = NON_NEGATED( node(i2).input(1) ); + + int result = INVALID; + int idx = lookup_table_4_inputs[signature]; + + switch (idx) + { + case 0: // i1 i2 and i3 i4 and and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 1: // i1 neg i2 and i3 i4 and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 2: // i1 i2 neg and i3 i4 and and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 3: // i1 neg i2 neg and i3 i4 and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 4: // i1 i2 and i3 neg i4 and and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 5: // i1 neg i2 and i3 neg i4 and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 6: // i1 i2 neg and i3 neg i4 and and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 7: // i1 neg i2 neg and i3 neg i4 and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 8: // i1 i2 and i3 i4 neg and and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 9: // i1 neg i2 and i3 i4 neg and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 10: // i1 i2 neg and i3 i4 neg and and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 11: // i1 neg i2 neg and i3 i4 neg and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 12: // i1 i2 and i3 neg i4 neg and and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 13: // i1 neg i2 and i3 neg i4 neg and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 14: // i1 i2 neg and i3 neg i4 neg and and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 15: // i1 neg i2 neg and i3 neg i4 neg and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 16: // i1 i2 and neg i3 i4 and and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 17: // i1 neg i2 and neg i3 i4 and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 18: // i1 i2 neg and neg i3 i4 and and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 19: // i1 neg i2 neg and neg i3 i4 and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 20: // i1 i2 and neg i3 neg i4 and and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 21: // i1 neg i2 and neg i3 neg i4 and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 22: // i1 i2 neg and neg i3 neg i4 and and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 23: // i1 neg i2 neg and neg i3 neg i4 and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 24: // i1 i2 and neg i3 i4 neg and and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 25: // i1 neg i2 and neg i3 i4 neg and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 26: // i1 i2 neg and neg i3 i4 neg and and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 27: // i1 neg i2 neg and neg i3 i4 neg and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 28: // i1 i2 and neg i3 neg i4 neg and and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 29: // i1 neg i2 and neg i3 neg i4 neg and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 30: // i1 i2 neg and neg i3 neg i4 neg and and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 31: // i1 neg i2 neg and neg i3 neg i4 neg and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 32: // i1 i2 and i3 i4 and neg and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 33: // i1 neg i2 and i3 i4 and neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 34: // i1 i2 neg and i3 i4 and neg and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 35: // i1 neg i2 neg and i3 i4 and neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 36: // i1 i2 and i3 neg i4 and neg and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 37: // i1 neg i2 and i3 neg i4 and neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 38: // i1 i2 neg and i3 neg i4 and neg and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 39: // i1 neg i2 neg and i3 neg i4 and neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 40: // i1 i2 and i3 i4 neg and neg and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 41: // i1 neg i2 and i3 i4 neg and neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 42: // i1 i2 neg and i3 i4 neg and neg and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 43: // i1 neg i2 neg and i3 i4 neg and neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 44: // i1 i2 and i3 neg i4 neg and neg and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 45: // i1 neg i2 and i3 neg i4 neg and neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 46: // i1 i2 neg and i3 neg i4 neg and neg and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 47: // i1 neg i2 neg and i3 neg i4 neg and neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 48: // i1 i2 and neg i3 i4 and neg and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 49: // i1 neg i2 and neg i3 i4 and neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 50: // i1 i2 neg and neg i3 i4 and neg and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 51: // i1 neg i2 neg and neg i3 i4 and neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 52: // i1 i2 and neg i3 neg i4 and neg and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 53: // i1 neg i2 and neg i3 neg i4 and neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 54: // i1 i2 neg and neg i3 neg i4 and neg and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 55: // i1 neg i2 neg and neg i3 neg i4 and neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 56: // i1 i2 and neg i3 i4 neg and neg and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 57: // i1 neg i2 and neg i3 i4 neg and neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 58: // i1 i2 neg and neg i3 i4 neg and neg and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 59: // i1 neg i2 neg and neg i3 i4 neg and neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 60: // i1 i2 and neg i3 neg i4 neg and neg and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 61: // i1 neg i2 and neg i3 neg i4 neg and neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 62: // i1 i2 neg and neg i3 neg i4 neg and neg and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 63: // i1 neg i2 neg and neg i3 neg i4 neg and neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 64: // i1 i2 xor i3 i4 and and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 65: // i1 i2 xor neg i3 i4 and and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 66: // i1 i2 xor i3 neg i4 and and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 67: // i1 i2 xor neg i3 neg i4 and and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 68: // i1 i2 xor i3 i4 neg and and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 69: // i1 i2 xor neg i3 i4 neg and and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 70: // i1 i2 xor i3 neg i4 neg and and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 71: // i1 i2 xor neg i3 neg i4 neg and and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 72: // i1 i2 xor i3 i4 and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 73: // i1 i2 xor neg i3 i4 and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 74: // i1 i2 xor i3 neg i4 and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 75: // i1 i2 xor neg i3 neg i4 and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 76: // i1 i2 xor i3 i4 neg and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 77: // i1 i2 xor neg i3 i4 neg and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 78: // i1 i2 xor i3 neg i4 neg and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 79: // i1 i2 xor neg i3 neg i4 neg and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 80: // i1 i2 and i3 i4 xor and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 81: // i1 neg i2 and i3 i4 xor and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 82: // i1 i2 neg and i3 i4 xor and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 83: // i1 neg i2 neg and i3 i4 xor and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 84: // i1 i2 and i3 i4 xor neg and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 85: // i1 neg i2 and i3 i4 xor neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 86: // i1 i2 neg and i3 i4 xor neg and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 87: // i1 neg i2 neg and i3 i4 xor neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 88: // i1 i2 and neg i3 i4 xor and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 89: // i1 neg i2 and neg i3 i4 xor and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 90: // i1 i2 neg and neg i3 i4 xor and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 91: // i1 neg i2 neg and neg i3 i4 xor and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 92: // i1 i2 and neg i3 i4 xor neg and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 93: // i1 neg i2 and neg i3 i4 xor neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 94: // i1 i2 neg and neg i3 i4 xor neg and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 95: // i1 neg i2 neg and neg i3 i4 xor neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 96: // i1 i2 xor i3 i4 xor and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 97: // i1 i2 xor neg i3 i4 xor and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 98: // i1 i2 xor i3 i4 xor neg and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 99: // i1 i2 xor neg i3 i4 xor neg and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 100: // i1 i2 and i3 i4 and xor + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = temp2; + break; + } + case 101: // i1 neg i2 and i3 i4 and xor + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = temp2; + break; + } + case 102: // i1 i2 neg and i3 i4 and xor + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = temp2; + break; + } + case 103: // i1 neg i2 neg and i3 i4 and xor + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = temp2; + break; + } + case 104: // i1 i2 and i3 neg i4 and xor + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = temp2; + break; + } + case 105: // i1 neg i2 and i3 neg i4 and xor + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = temp2; + break; + } + case 106: // i1 i2 neg and i3 neg i4 and xor + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = temp2; + break; + } + case 107: // i1 neg i2 neg and i3 neg i4 and xor + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = temp2; + break; + } + case 108: // i1 i2 and i3 i4 neg and xor + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = temp2; + break; + } + case 109: // i1 neg i2 and i3 i4 neg and xor + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = temp2; + break; + } + case 110: // i1 i2 neg and i3 i4 neg and xor + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = temp2; + break; + } + case 111: // i1 neg i2 neg and i3 i4 neg and xor + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = temp2; + break; + } + case 112: // i1 i2 and i3 neg i4 neg and xor + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = temp2; + break; + } + case 113: // i1 neg i2 and i3 neg i4 neg and xor + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = temp2; + break; + } + case 114: // i1 i2 neg and i3 neg i4 neg and xor + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = temp2; + break; + } + case 115: // i1 neg i2 neg and i3 neg i4 neg and xor + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = temp2; + break; + } + case 116: // i1 i2 and i3 i4 and xor neg + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = NEGATE( temp2 ); + break; + } + case 117: // i1 neg i2 and i3 i4 and xor neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = NEGATE( temp2 ); + break; + } + case 118: // i1 i2 neg and i3 i4 and xor neg + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = NEGATE( temp2 ); + break; + } + case 119: // i1 neg i2 neg and i3 i4 and xor neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = NEGATE( temp2 ); + break; + } + case 120: // i1 i2 and i3 neg i4 and xor neg + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = NEGATE( temp2 ); + break; + } + case 121: // i1 neg i2 and i3 neg i4 and xor neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = NEGATE( temp2 ); + break; + } + case 122: // i1 i2 neg and i3 neg i4 and xor neg + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = NEGATE( temp2 ); + break; + } + case 123: // i1 neg i2 neg and i3 neg i4 and xor neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = NEGATE( temp2 ); + break; + } + case 124: // i1 i2 and i3 i4 neg and xor neg + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = NEGATE( temp2 ); + break; + } + case 125: // i1 neg i2 and i3 i4 neg and xor neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = NEGATE( temp2 ); + break; + } + case 126: // i1 i2 neg and i3 i4 neg and xor neg + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = NEGATE( temp2 ); + break; + } + case 127: // i1 neg i2 neg and i3 i4 neg and xor neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = NEGATE( temp2 ); + break; + } + case 128: // i1 i2 and i3 neg i4 neg and xor neg + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = NEGATE( temp2 ); + break; + } + case 129: // i1 neg i2 and i3 neg i4 neg and xor neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = NEGATE( temp2 ); + break; + } + case 130: // i1 i2 neg and i3 neg i4 neg and xor neg + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = NEGATE( temp2 ); + break; + } + case 131: // i1 neg i2 neg and i3 neg i4 neg and xor neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = NEGATE( temp2 ); + break; + } + case 132: // i1 i2 xor i3 i4 and xor + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = temp2; + break; + } + case 133: // i1 i2 xor i3 i4 and xor neg + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = NEGATE( temp2 ); + break; + } + case 134: // i1 i2 xor i3 neg i4 and xor + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = temp2; + break; + } + case 135: // i1 i2 xor i3 neg i4 and xor neg + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = NEGATE( temp2 ); + break; + } + case 136: // i1 i2 xor i3 i4 neg and xor + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = temp2; + break; + } + case 137: // i1 i2 xor i3 i4 neg and xor neg + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = NEGATE( temp2 ); + break; + } + case 138: // i1 i2 xor i3 neg i4 neg and xor + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = temp2; + break; + } + case 139: // i1 i2 xor i3 neg i4 neg and xor neg + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = NEGATE( temp2 ); + break; + } + case 140: // i1 i2 and i3 i4 xor xor + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = temp2; + break; + } + case 141: // i1 neg i2 and i3 i4 xor xor + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = temp2; + break; + } + case 142: // i1 i2 neg and i3 i4 xor xor + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = temp2; + break; + } + case 143: // i1 neg i2 neg and i3 i4 xor xor + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = temp2; + break; + } + case 144: // i1 i2 and i3 i4 xor xor neg + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = NEGATE( temp2 ); + break; + } + case 145: // i1 neg i2 and i3 i4 xor xor neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = NEGATE( temp2 ); + break; + } + case 146: // i1 i2 neg and i3 i4 xor xor neg + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = NEGATE( temp2 ); + break; + } + case 147: // i1 neg i2 neg and i3 i4 xor xor neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = NEGATE( temp2 ); + break; + } + case 148: // i1 i2 xor i3 i4 xor xor + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = temp2; + break; + } + case 149: // i1 i2 xor i3 i4 xor xor neg + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.XOR, rl_nn, rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = NEGATE( temp2 ); + break; + } + case 150: // i1 i2 and i4 and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, rr_nn ); + result = temp1; + break; + } + case 151: // i1 neg i2 and i4 and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, rr_nn ); + result = temp1; + break; + } + case 152: // neg + { + result = zero(); + break; + } + case 153: // i1 i2 neg and i4 and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.AND, temp0, rr_nn ); + result = temp1; + break; + } + case 154: // i1 neg i2 neg and i4 and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.AND, temp0, rr_nn ); + result = temp1; + break; + } + case 155: // i1 i2 and i4 neg and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( rr_nn ) ); + result = temp1; + break; + } + case 156: // i1 neg i2 and i4 neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( rr_nn ) ); + result = temp1; + break; + } + case 157: // i1 i2 neg and i4 neg and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( rr_nn ) ); + result = temp1; + break; + } + case 158: // i1 neg i2 neg and i4 neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( rr_nn ) ); + result = temp1; + break; + } + case 159: // i2 i4 and + { + int temp0 = create_op_node (NodeType.AND, lr_nn, rr_nn ); + result = temp0; + break; + } + case 160: // i2 neg i4 and + { + int temp0 = create_op_node (NodeType.AND, NEGATE( lr_nn ), rr_nn ); + result = temp0; + break; + } + case 161: // i2 i4 neg and + { + int temp0 = create_op_node (NodeType.AND, lr_nn, NEGATE( rr_nn ) ); + result = temp0; + break; + } + case 162: // i2 neg i4 neg and + { + int temp0 = create_op_node (NodeType.AND, NEGATE( lr_nn ), NEGATE( rr_nn ) ); + result = temp0; + break; + } + case 163: // i1 i2 neg and + { + int temp0 = create_op_node (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + result = temp0; + break; + } + case 164: // i1 neg i2 neg and + { + int temp0 = create_op_node (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + result = temp0; + break; + } + case 165: // i1 i2 and + { + int temp0 = create_op_node (NodeType.AND, ll_nn, lr_nn ); + result = temp0; + break; + } + case 166: // i1 neg i2 and + { + int temp0 = create_op_node (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + result = temp0; + break; + } + case 167: // i1 neg i4 neg and neg i2 and neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( rr_nn ) ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), lr_nn ); + result = NEGATE( temp1 ); + break; + } + case 168: // i1 i4 neg and neg i2 and neg + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( rr_nn ) ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), lr_nn ); + result = NEGATE( temp1 ); + break; + } + case 169: // i1 i2 neg and neg i2 i4 and neg and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, lr_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 170: // i1 i2 neg and neg i2 i4 neg and neg and neg + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, lr_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = NEGATE( temp2 ); + break; + } + case 171: // i1 i2 and neg i2 neg i4 and neg and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( lr_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 172: // i1 i2 and neg i2 neg i4 neg and neg and neg + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( lr_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = NEGATE( temp2 ); + break; + } + case 173: // i1 neg i4 neg and neg i2 neg and neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( rr_nn ) ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( lr_nn ) ); + result = NEGATE( temp1 ); + break; + } + case 174: // i1 i4 neg and neg i2 neg and neg + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( rr_nn ) ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( lr_nn ) ); + result = NEGATE( temp1 ); + break; + } + case 175: // i1 neg i4 and neg i2 and neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), rr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), lr_nn ); + result = NEGATE( temp1 ); + break; + } + case 176: // i1 i4 and neg i2 and neg + { + int temp0 = create (NodeType.AND, ll_nn, rr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), lr_nn ); + result = NEGATE( temp1 ); + break; + } + case 177: // i1 i2 neg and neg i2 i4 neg and neg and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, lr_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 178: // i1 i2 neg and neg i2 i4 and neg and neg + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, lr_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = NEGATE( temp2 ); + break; + } + case 179: // i1 i2 and neg i2 neg i4 neg and neg and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( lr_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 180: // i1 i2 and neg i2 neg i4 and neg and neg + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( lr_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = NEGATE( temp2 ); + break; + } + case 181: // i1 neg i4 and neg i2 neg and neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), rr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( lr_nn ) ); + result = NEGATE( temp1 ); + break; + } + case 182: // i1 i4 and neg i2 neg and neg + { + int temp0 = create (NodeType.AND, ll_nn, rr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( lr_nn ) ); + result = NEGATE( temp1 ); + break; + } + case 183: // i1 i2 xor i2 i4 and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, lr_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 184: // i1 i2 xor neg i1 i4 and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, ll_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 185: // i1 i2 xor i1 i4 and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, ll_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 186: // i1 i2 xor neg i1 neg i4 and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( ll_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 187: // i1 i2 xor i2 i4 neg and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, lr_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 188: // i1 i2 xor neg i1 i4 neg and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, ll_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 189: // i1 i2 xor i1 i4 neg and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, ll_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 190: // i1 i2 xor neg i1 neg i4 neg and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 191: // i1 i2 and neg i2 i4 xor and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.XOR, lr_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 192: // i1 neg i2 and neg i2 i4 xor and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.XOR, lr_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 193: // i1 i4 and neg i2 i4 xor and + { + int temp0 = create (NodeType.AND, ll_nn, rr_nn ); + int temp1 = create (NodeType.XOR, lr_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 194: // i1 neg i4 and neg i2 i4 xor and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), rr_nn ); + int temp1 = create (NodeType.XOR, lr_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 195: // i1 i2 and neg i2 i4 xor neg and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.XOR, lr_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 196: // i1 neg i2 and neg i2 i4 xor neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.XOR, lr_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 197: // i1 i2 neg and neg i2 i4 xor neg and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.XOR, lr_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 198: // i1 neg i2 neg and neg i2 i4 xor neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.XOR, lr_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 199: // i1 i2 xor i2 i4 xor and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.XOR, lr_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 200: // i1 i4 xor i2 i4 xor and + { + int temp0 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp1 = create (NodeType.XOR, lr_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 201: // i1 i2 xor i1 i4 xor and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 202: // i1 i2 xor neg i1 i4 xor neg and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 203: // i1 i4 xor i2 and + { + int temp0 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, lr_nn ); + result = temp1; + break; + } + case 204: // i1 i4 xor neg i2 and + { + int temp0 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), lr_nn ); + result = temp1; + break; + } + case 205: // i1 i4 xor i2 neg and + { + int temp0 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( lr_nn ) ); + result = temp1; + break; + } + case 206: // i1 i4 xor neg i2 neg and + { + int temp0 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( lr_nn ) ); + result = temp1; + break; + } + case 207: // i1 i4 xor i2 and neg + { + int temp0 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, lr_nn ); + result = NEGATE( temp1 ); + break; + } + case 208: // i1 i4 xor neg i2 and neg + { + int temp0 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), lr_nn ); + result = NEGATE( temp1 ); + break; + } + case 209: // i1 i4 xor i2 neg and neg + { + int temp0 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( lr_nn ) ); + result = NEGATE( temp1 ); + break; + } + case 210: // i1 i4 xor neg i2 neg and neg + { + int temp0 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( lr_nn ) ); + result = NEGATE( temp1 ); + break; + } + case 211: // i2 i4 neg and i1 xor + { + int temp0 = create (NodeType.AND, lr_nn, NEGATE( rr_nn ) ); + int temp1 = create_op_node (NodeType.XOR, temp0, ll_nn ); + result = temp1; + break; + } + case 212: // i2 i4 neg and i1 xor neg + { + int temp0 = create (NodeType.AND, lr_nn, NEGATE( rr_nn ) ); + int temp1 = create_op_node (NodeType.XOR, temp0, ll_nn ); + result = NEGATE( temp1 ); + break; + } + case 213: // i2 neg i4 neg and i1 xor neg + { + int temp0 = create (NodeType.AND, NEGATE( lr_nn ), NEGATE( rr_nn ) ); + int temp1 = create_op_node (NodeType.XOR, temp0, ll_nn ); + result = NEGATE( temp1 ); + break; + } + case 214: // i2 neg i4 neg and i1 xor + { + int temp0 = create (NodeType.AND, NEGATE( lr_nn ), NEGATE( rr_nn ) ); + int temp1 = create_op_node (NodeType.XOR, temp0, ll_nn ); + result = temp1; + break; + } + case 215: // i2 i4 and i1 xor + { + int temp0 = create (NodeType.AND, lr_nn, rr_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, ll_nn ); + result = temp1; + break; + } + case 216: // i2 i4 and i1 xor neg + { + int temp0 = create (NodeType.AND, lr_nn, rr_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, ll_nn ); + result = NEGATE( temp1 ); + break; + } + case 217: // i2 neg i4 and i1 xor neg + { + int temp0 = create (NodeType.AND, NEGATE( lr_nn ), rr_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, ll_nn ); + result = NEGATE( temp1 ); + break; + } + case 218: // i2 neg i4 and i1 xor + { + int temp0 = create (NodeType.AND, NEGATE( lr_nn ), rr_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, ll_nn ); + result = temp1; + break; + } + case 219: // i1 neg i2 and i4 xor + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, rr_nn ); + result = temp1; + break; + } + case 220: // i1 i2 and i4 xor + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, rr_nn ); + result = temp1; + break; + } + case 221: // i1 neg i2 neg and i4 xor neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.XOR, temp0, rr_nn ); + result = NEGATE( temp1 ); + break; + } + case 222: // i1 i2 neg and i4 xor neg + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.XOR, temp0, rr_nn ); + result = NEGATE( temp1 ); + break; + } + case 223: // i1 neg i2 and i4 xor neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, rr_nn ); + result = NEGATE( temp1 ); + break; + } + case 224: // i1 i2 and i4 xor neg + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, rr_nn ); + result = NEGATE( temp1 ); + break; + } + case 225: // i1 neg i2 neg and i4 xor + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.XOR, temp0, rr_nn ); + result = temp1; + break; + } + case 226: // i1 i2 neg and i4 xor + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.XOR, temp0, rr_nn ); + result = temp1; + break; + } + case 227: // i1 i4 xor + { + int temp0 = create_op_node (NodeType.XOR, ll_nn, rr_nn ); + result = temp0; + break; + } + case 228: // i1 i4 xor neg + { + int temp0 = create_op_node (NodeType.XOR, ll_nn, rr_nn ); + result = NEGATE( temp0 ); + break; + } + case 229: // i1 i3 and i2 i4 and and + { + int temp0 = create (NodeType.AND, ll_nn, rl_nn ); + int temp1 = create (NodeType.AND, lr_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 230: // i1 neg i3 and i2 i4 and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), rl_nn ); + int temp1 = create (NodeType.AND, lr_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 231: // i1 i3 and i2 neg i4 and and + { + int temp0 = create (NodeType.AND, ll_nn, rl_nn ); + int temp1 = create (NodeType.AND, NEGATE( lr_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 232: // i1 neg i3 and i2 neg i4 and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), rl_nn ); + int temp1 = create (NodeType.AND, NEGATE( lr_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 233: // i1 i3 neg and i2 i4 and and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( rl_nn ) ); + int temp1 = create (NodeType.AND, lr_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 234: // i1 neg i3 neg and i2 i4 and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( rl_nn ) ); + int temp1 = create (NodeType.AND, lr_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 235: // i1 i3 neg and i2 neg i4 and and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( rl_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( lr_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 236: // i1 neg i3 neg and i2 neg i4 and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( rl_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( lr_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 237: // i1 i3 and i2 i4 neg and and + { + int temp0 = create (NodeType.AND, ll_nn, rl_nn ); + int temp1 = create (NodeType.AND, lr_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 238: // i1 neg i3 and i2 i4 neg and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), rl_nn ); + int temp1 = create (NodeType.AND, lr_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 239: // i1 i3 and i2 neg i4 neg and and + { + int temp0 = create (NodeType.AND, ll_nn, rl_nn ); + int temp1 = create (NodeType.AND, NEGATE( lr_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 240: // i1 neg i3 and i2 neg i4 neg and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), rl_nn ); + int temp1 = create (NodeType.AND, NEGATE( lr_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 241: // i1 i3 neg and i2 i4 neg and and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( rl_nn ) ); + int temp1 = create (NodeType.AND, lr_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 242: // i1 neg i3 neg and i2 i4 neg and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( rl_nn ) ); + int temp1 = create (NodeType.AND, lr_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 243: // i1 i3 neg and i2 neg i4 neg and and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( rl_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( lr_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 244: // i1 neg i3 neg and i2 neg i4 neg and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( rl_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( lr_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 245: // i1 i3 xor i2 i4 xor xor + { + int temp0 = create (NodeType.XOR, ll_nn, rl_nn ); + int temp1 = create (NodeType.XOR, lr_nn, rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = temp2; + break; + } + case 246: // i1 i3 xor i2 i4 xor xor neg + { + int temp0 = create (NodeType.XOR, ll_nn, rl_nn ); + int temp1 = create (NodeType.XOR, lr_nn, rr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = NEGATE( temp2 ); + break; + } + case 247: // i1 i4 and + { + int temp0 = create_op_node (NodeType.AND, ll_nn, rr_nn ); + result = temp0; + break; + } + case 248: // i1 neg i4 and + { + int temp0 = create_op_node (NodeType.AND, NEGATE( ll_nn ), rr_nn ); + result = temp0; + break; + } + case 249: // i1 i4 neg and + { + int temp0 = create_op_node (NodeType.AND, ll_nn, NEGATE( rr_nn ) ); + result = temp0; + break; + } + case 250: // i1 neg i4 neg and + { + int temp0 = create_op_node (NodeType.AND, NEGATE( ll_nn ), NEGATE( rr_nn ) ); + result = temp0; + break; + } + case 251: // i2 neg i4 neg and neg i1 and neg + { + int temp0 = create (NodeType.AND, NEGATE( lr_nn ), NEGATE( rr_nn ) ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), ll_nn ); + result = NEGATE( temp1 ); + break; + } + case 252: // i1 neg i2 and neg i1 i4 and neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.AND, ll_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 253: // i2 i4 neg and neg i1 and neg + { + int temp0 = create (NodeType.AND, lr_nn, NEGATE( rr_nn ) ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), ll_nn ); + result = NEGATE( temp1 ); + break; + } + case 254: // i1 neg i2 and neg i1 i4 neg and neg and neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.AND, ll_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = NEGATE( temp2 ); + break; + } + case 255: // i1 i2 and neg i1 neg i4 and neg and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( ll_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 256: // i2 neg i4 neg and neg i1 neg and neg + { + int temp0 = create (NodeType.AND, NEGATE( lr_nn ), NEGATE( rr_nn ) ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( ll_nn ) ); + result = NEGATE( temp1 ); + break; + } + case 257: // i1 i2 and neg i1 neg i4 neg and neg and neg + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = NEGATE( temp2 ); + break; + } + case 258: // i2 i4 neg and neg i1 neg and neg + { + int temp0 = create (NodeType.AND, lr_nn, NEGATE( rr_nn ) ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( ll_nn ) ); + result = NEGATE( temp1 ); + break; + } + case 259: // i2 neg i4 and neg i1 and neg + { + int temp0 = create (NodeType.AND, NEGATE( lr_nn ), rr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), ll_nn ); + result = NEGATE( temp1 ); + break; + } + case 260: // i1 neg i2 and neg i1 i4 neg and neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.AND, ll_nn, NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 261: // i2 i4 and neg i1 and neg + { + int temp0 = create (NodeType.AND, lr_nn, rr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), ll_nn ); + result = NEGATE( temp1 ); + break; + } + case 262: // i1 neg i2 and neg i1 i4 and neg and neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.AND, ll_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = NEGATE( temp2 ); + break; + } + case 263: // i1 i2 and neg i1 neg i4 neg and neg and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( rr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 264: // i2 neg i4 and neg i1 neg and neg + { + int temp0 = create (NodeType.AND, NEGATE( lr_nn ), rr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( ll_nn ) ); + result = NEGATE( temp1 ); + break; + } + case 265: // i1 i2 and neg i1 neg i4 and neg and neg + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( ll_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = NEGATE( temp2 ); + break; + } + case 266: // i2 i4 and neg i1 neg and neg + { + int temp0 = create (NodeType.AND, lr_nn, rr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( ll_nn ) ); + result = NEGATE( temp1 ); + break; + } + case 267: // i1 i2 and neg i1 i4 xor and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 268: // i1 i4 xor i2 i4 and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp1 = create (NodeType.AND, lr_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 269: // i1 i2 neg and neg i1 i4 xor and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 270: // i1 i4 xor i2 neg i4 and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp1 = create (NodeType.AND, NEGATE( lr_nn ), rr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 271: // i1 i2 and neg i1 i4 xor neg and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 272: // i1 neg i2 and neg i1 i4 xor neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 273: // i1 i2 neg and neg i1 i4 xor neg and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 274: // i1 neg i2 neg and neg i1 i4 xor neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 275: // i2 i4 xor i1 and + { + int temp0 = create (NodeType.XOR, lr_nn, rr_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, ll_nn ); + result = temp1; + break; + } + case 276: // i2 i4 xor neg i1 and + { + int temp0 = create (NodeType.XOR, lr_nn, rr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), ll_nn ); + result = temp1; + break; + } + case 277: // i2 i4 xor i1 neg and + { + int temp0 = create (NodeType.XOR, lr_nn, rr_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( ll_nn ) ); + result = temp1; + break; + } + case 278: // i2 i4 xor neg i1 neg and + { + int temp0 = create (NodeType.XOR, lr_nn, rr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( ll_nn ) ); + result = temp1; + break; + } + case 279: // i2 i4 xor i1 and neg + { + int temp0 = create (NodeType.XOR, lr_nn, rr_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, ll_nn ); + result = NEGATE( temp1 ); + break; + } + case 280: // i2 i4 xor neg i1 and neg + { + int temp0 = create (NodeType.XOR, lr_nn, rr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), ll_nn ); + result = NEGATE( temp1 ); + break; + } + case 281: // i2 i4 xor i1 neg and neg + { + int temp0 = create (NodeType.XOR, lr_nn, rr_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( ll_nn ) ); + result = NEGATE( temp1 ); + break; + } + case 282: // i2 i4 xor neg i1 neg and neg + { + int temp0 = create (NodeType.XOR, lr_nn, rr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( ll_nn ) ); + result = NEGATE( temp1 ); + break; + } + case 283: // i1 i4 neg and i2 xor + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( rr_nn ) ); + int temp1 = create_op_node (NodeType.XOR, temp0, lr_nn ); + result = temp1; + break; + } + case 284: // i1 i4 neg and i2 xor neg + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( rr_nn ) ); + int temp1 = create_op_node (NodeType.XOR, temp0, lr_nn ); + result = NEGATE( temp1 ); + break; + } + case 285: // i1 neg i4 neg and i2 xor neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( rr_nn ) ); + int temp1 = create_op_node (NodeType.XOR, temp0, lr_nn ); + result = NEGATE( temp1 ); + break; + } + case 286: // i1 neg i4 neg and i2 xor + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( rr_nn ) ); + int temp1 = create_op_node (NodeType.XOR, temp0, lr_nn ); + result = temp1; + break; + } + case 287: // i1 i4 and i2 xor + { + int temp0 = create (NodeType.AND, ll_nn, rr_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, lr_nn ); + result = temp1; + break; + } + case 288: // i1 i4 and i2 xor neg + { + int temp0 = create (NodeType.AND, ll_nn, rr_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, lr_nn ); + result = NEGATE( temp1 ); + break; + } + case 289: // i1 neg i4 and i2 xor neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), rr_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, lr_nn ); + result = NEGATE( temp1 ); + break; + } + case 290: // i1 neg i4 and i2 xor + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), rr_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, lr_nn ); + result = temp1; + break; + } + case 291: // i2 i4 xor + { + int temp0 = create_op_node (NodeType.XOR, lr_nn, rr_nn ); + result = temp0; + break; + } + case 292: // i2 i4 xor neg + { + int temp0 = create_op_node (NodeType.XOR, lr_nn, rr_nn ); + result = NEGATE( temp0 ); + break; + } + case 293: // i1 i3 and i2 and + { + int temp0 = create (NodeType.AND, ll_nn, rl_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, lr_nn ); + result = temp1; + break; + } + case 294: // i1 neg i3 and i2 and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), rl_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, lr_nn ); + result = temp1; + break; + } + case 295: // i1 i3 neg and i2 and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( rl_nn ) ); + int temp1 = create_op_node (NodeType.AND, temp0, lr_nn ); + result = temp1; + break; + } + case 296: // i1 neg i3 neg and i2 and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( rl_nn ) ); + int temp1 = create_op_node (NodeType.AND, temp0, lr_nn ); + result = temp1; + break; + } + case 297: // i1 i3 and i2 neg and + { + int temp0 = create (NodeType.AND, ll_nn, rl_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( lr_nn ) ); + result = temp1; + break; + } + case 298: // i1 neg i3 and i2 neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), rl_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( lr_nn ) ); + result = temp1; + break; + } + case 299: // i1 i3 neg and i2 neg and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( rl_nn ) ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( lr_nn ) ); + result = temp1; + break; + } + case 300: // i1 neg i3 neg and i2 neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( rl_nn ) ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( lr_nn ) ); + result = temp1; + break; + } + case 301: // i3 i2 and + { + int temp0 = create_op_node (NodeType.AND, rl_nn, lr_nn ); + result = temp0; + break; + } + case 302: // i3 neg i2 and + { + int temp0 = create_op_node (NodeType.AND, NEGATE( rl_nn ), lr_nn ); + result = temp0; + break; + } + case 303: // i3 i2 neg and + { + int temp0 = create_op_node (NodeType.AND, rl_nn, NEGATE( lr_nn ) ); + result = temp0; + break; + } + case 304: // i3 neg i2 neg and + { + int temp0 = create_op_node (NodeType.AND, NEGATE( rl_nn ), NEGATE( lr_nn ) ); + result = temp0; + break; + } + case 305: // i1 neg i3 neg and neg i2 and neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( rl_nn ) ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), lr_nn ); + result = NEGATE( temp1 ); + break; + } + case 306: // i1 i3 neg and neg i2 and neg + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( rl_nn ) ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), lr_nn ); + result = NEGATE( temp1 ); + break; + } + case 307: // i1 i2 neg and neg i3 i2 and neg and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, rl_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 308: // i1 i2 neg and neg i3 neg i2 and neg and neg + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = NEGATE( temp2 ); + break; + } + case 309: // i1 neg i3 and neg i2 and neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), rl_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), lr_nn ); + result = NEGATE( temp1 ); + break; + } + case 310: // i1 i3 and neg i2 and neg + { + int temp0 = create (NodeType.AND, ll_nn, rl_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), lr_nn ); + result = NEGATE( temp1 ); + break; + } + case 311: // i1 i2 neg and neg i3 neg i2 and neg and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 312: // i1 i2 neg and neg i3 i2 and neg and neg + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create (NodeType.AND, rl_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = NEGATE( temp2 ); + break; + } + case 313: // i1 i2 and neg i3 i2 neg and neg and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( lr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 314: // i1 i2 and neg i3 neg i2 neg and neg and neg + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( lr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = NEGATE( temp2 ); + break; + } + case 315: // i1 neg i3 neg and neg i2 neg and neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( rl_nn ) ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( lr_nn ) ); + result = NEGATE( temp1 ); + break; + } + case 316: // i1 i3 neg and neg i2 neg and neg + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( rl_nn ) ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( lr_nn ) ); + result = NEGATE( temp1 ); + break; + } + case 317: // i1 i2 and neg i3 neg i2 neg and neg and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( lr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 318: // i1 i2 and neg i3 i2 neg and neg and neg + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, NEGATE( lr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = NEGATE( temp2 ); + break; + } + case 319: // i1 neg i3 and neg i2 neg and neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), rl_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( lr_nn ) ); + result = NEGATE( temp1 ); + break; + } + case 320: // i1 i3 and neg i2 neg and neg + { + int temp0 = create (NodeType.AND, ll_nn, rl_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( lr_nn ) ); + result = NEGATE( temp1 ); + break; + } + case 321: // i1 i2 xor i3 i2 and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, rl_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 322: // i1 i3 and neg i1 i2 xor neg and + { + int temp0 = create (NodeType.AND, ll_nn, rl_nn ); + int temp1 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 323: // i1 i2 xor i3 neg i2 and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rl_nn ), lr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 324: // i1 i3 neg and neg i1 i2 xor neg and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( rl_nn ) ); + int temp1 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 325: // i1 i3 and neg i1 i2 xor and + { + int temp0 = create (NodeType.AND, ll_nn, rl_nn ); + int temp1 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 326: // i1 neg i3 and neg i1 i2 xor neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), rl_nn ); + int temp1 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 327: // i1 i3 neg and neg i1 i2 xor and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( rl_nn ) ); + int temp1 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 328: // i1 neg i3 neg and neg i1 i2 xor neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( rl_nn ) ); + int temp1 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 329: // i1 i2 and neg i3 i2 xor and + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create (NodeType.XOR, rl_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 330: // i1 neg i2 and neg i3 i2 xor and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create (NodeType.XOR, rl_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 331: // i1 i3 and neg i3 i2 xor and + { + int temp0 = create (NodeType.AND, ll_nn, rl_nn ); + int temp1 = create (NodeType.XOR, rl_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 332: // i1 neg i3 and neg i3 i2 xor and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), rl_nn ); + int temp1 = create (NodeType.XOR, rl_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 333: // i1 i3 and neg i3 i2 xor neg and + { + int temp0 = create (NodeType.AND, ll_nn, rl_nn ); + int temp1 = create (NodeType.XOR, rl_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 334: // i1 neg i3 and neg i3 i2 xor neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), rl_nn ); + int temp1 = create (NodeType.XOR, rl_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 335: // i1 i3 neg and neg i3 i2 xor neg and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( rl_nn ) ); + int temp1 = create (NodeType.XOR, rl_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 336: // i1 neg i3 neg and neg i3 i2 xor neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( rl_nn ) ); + int temp1 = create (NodeType.XOR, rl_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 337: // i1 i2 xor i3 i2 xor and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.XOR, rl_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 338: // i1 i3 xor i3 i2 xor and + { + int temp0 = create (NodeType.XOR, ll_nn, rl_nn ); + int temp1 = create (NodeType.XOR, rl_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 339: // i1 i3 xor i1 i2 xor and + { + int temp0 = create (NodeType.XOR, ll_nn, rl_nn ); + int temp1 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 340: // i1 i3 xor neg i1 i2 xor neg and + { + int temp0 = create (NodeType.XOR, ll_nn, rl_nn ); + int temp1 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 341: // i1 i3 xor i2 and + { + int temp0 = create (NodeType.XOR, ll_nn, rl_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, lr_nn ); + result = temp1; + break; + } + case 342: // i1 i3 xor neg i2 and + { + int temp0 = create (NodeType.XOR, ll_nn, rl_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), lr_nn ); + result = temp1; + break; + } + case 343: // i1 i3 xor i2 neg and + { + int temp0 = create (NodeType.XOR, ll_nn, rl_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( lr_nn ) ); + result = temp1; + break; + } + case 344: // i1 i3 xor neg i2 neg and + { + int temp0 = create (NodeType.XOR, ll_nn, rl_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( lr_nn ) ); + result = temp1; + break; + } + case 345: // i1 i3 xor i2 and neg + { + int temp0 = create (NodeType.XOR, ll_nn, rl_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, lr_nn ); + result = NEGATE( temp1 ); + break; + } + case 346: // i1 i3 xor neg i2 and neg + { + int temp0 = create (NodeType.XOR, ll_nn, rl_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), lr_nn ); + result = NEGATE( temp1 ); + break; + } + case 347: // i1 i3 xor i2 neg and neg + { + int temp0 = create (NodeType.XOR, ll_nn, rl_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( lr_nn ) ); + result = NEGATE( temp1 ); + break; + } + case 348: // i1 i3 xor neg i2 neg and neg + { + int temp0 = create (NodeType.XOR, ll_nn, rl_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( lr_nn ) ); + result = NEGATE( temp1 ); + break; + } + case 349: // i3 neg i2 and i1 xor + { + int temp0 = create (NodeType.AND, NEGATE( rl_nn ), lr_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, ll_nn ); + result = temp1; + break; + } + case 350: // i3 neg i2 and i1 xor neg + { + int temp0 = create (NodeType.AND, NEGATE( rl_nn ), lr_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, ll_nn ); + result = NEGATE( temp1 ); + break; + } + case 351: // i3 i2 and i1 xor + { + int temp0 = create (NodeType.AND, rl_nn, lr_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, ll_nn ); + result = temp1; + break; + } + case 352: // i3 i2 and i1 xor neg + { + int temp0 = create (NodeType.AND, rl_nn, lr_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, ll_nn ); + result = NEGATE( temp1 ); + break; + } + case 353: // i3 neg i2 neg and i1 xor neg + { + int temp0 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.XOR, temp0, ll_nn ); + result = NEGATE( temp1 ); + break; + } + case 354: // i3 neg i2 neg and i1 xor + { + int temp0 = create (NodeType.AND, NEGATE( rl_nn ), NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.XOR, temp0, ll_nn ); + result = temp1; + break; + } + case 355: // i3 i2 neg and i1 xor neg + { + int temp0 = create (NodeType.AND, rl_nn, NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.XOR, temp0, ll_nn ); + result = NEGATE( temp1 ); + break; + } + case 356: // i3 i2 neg and i1 xor + { + int temp0 = create (NodeType.AND, rl_nn, NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.XOR, temp0, ll_nn ); + result = temp1; + break; + } + case 357: // i1 neg i2 and i3 xor + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, rl_nn ); + result = temp1; + break; + } + case 358: // i1 i2 and i3 xor + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, rl_nn ); + result = temp1; + break; + } + case 359: // i1 neg i2 neg and i3 xor neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.XOR, temp0, rl_nn ); + result = NEGATE( temp1 ); + break; + } + case 360: // i1 i2 neg and i3 xor neg + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.XOR, temp0, rl_nn ); + result = NEGATE( temp1 ); + break; + } + case 361: // i1 neg i2 and i3 xor neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, rl_nn ); + result = NEGATE( temp1 ); + break; + } + case 362: // i1 i2 and i3 xor neg + { + int temp0 = create (NodeType.AND, ll_nn, lr_nn ); + int temp1 = create_op_node (NodeType.XOR, temp0, rl_nn ); + result = NEGATE( temp1 ); + break; + } + case 363: // i1 neg i2 neg and i3 xor + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.XOR, temp0, rl_nn ); + result = temp1; + break; + } + case 364: // i1 i2 neg and i3 xor + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.XOR, temp0, rl_nn ); + result = temp1; + break; + } + case 365: // i1 i3 xor + { + int temp0 = create_op_node (NodeType.XOR, ll_nn, rl_nn ); + result = temp0; + break; + } + case 366: // i1 i3 xor neg + { + int temp0 = create_op_node (NodeType.XOR, ll_nn, rl_nn ); + result = NEGATE( temp0 ); + break; + } + case 367: // i1 i2 and neg + { + int temp0 = create_op_node (NodeType.AND, ll_nn, lr_nn ); + result = NEGATE( temp0 ); + break; + } + case 368: // i2 neg + { + result = NEGATE( lr_nn ); + break; + } + case 369: // i1 neg + { + result = NEGATE( ll_nn ); + break; + } + case 370: // i1 i2 xor + { + int temp0 = create_op_node (NodeType.XOR, ll_nn, lr_nn ); + result = temp0; + break; + } + case 371: // i1 neg i2 and neg + { + int temp0 = create_op_node (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + result = NEGATE( temp0 ); + break; + } + case 372: // i1 i2 xor neg + { + int temp0 = create_op_node (NodeType.XOR, ll_nn, lr_nn ); + result = NEGATE( temp0 ); + break; + } + case 373: // i1 + { + result = ll_nn; + break; + } + case 374: // i1 i2 neg and neg + { + int temp0 = create_op_node (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + result = NEGATE( temp0 ); + break; + } + case 375: // i2 + { + result = lr_nn; + break; + } + case 376: // i1 neg i2 neg and neg + { + int temp0 = create_op_node (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + result = NEGATE( temp0 ); + break; + } + case 377: // + { + result = one(); + break; + } + case 378: // i1 i3 and i4 i2 and and + { + int temp0 = create (NodeType.AND, ll_nn, rl_nn ); + int temp1 = create (NodeType.AND, rr_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 379: // i1 neg i3 and i4 i2 and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), rl_nn ); + int temp1 = create (NodeType.AND, rr_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 380: // i1 i3 and i4 i2 neg and and + { + int temp0 = create (NodeType.AND, ll_nn, rl_nn ); + int temp1 = create (NodeType.AND, rr_nn, NEGATE( lr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 381: // i1 neg i3 and i4 i2 neg and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), rl_nn ); + int temp1 = create (NodeType.AND, rr_nn, NEGATE( lr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 382: // i1 i3 neg and i4 i2 and and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( rl_nn ) ); + int temp1 = create (NodeType.AND, rr_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 383: // i1 neg i3 neg and i4 i2 and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( rl_nn ) ); + int temp1 = create (NodeType.AND, rr_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 384: // i1 i3 neg and i4 i2 neg and and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( rl_nn ) ); + int temp1 = create (NodeType.AND, rr_nn, NEGATE( lr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 385: // i1 neg i3 neg and i4 i2 neg and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( rl_nn ) ); + int temp1 = create (NodeType.AND, rr_nn, NEGATE( lr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 386: // i1 i3 and i4 neg i2 and and + { + int temp0 = create (NodeType.AND, ll_nn, rl_nn ); + int temp1 = create (NodeType.AND, NEGATE( rr_nn ), lr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 387: // i1 neg i3 and i4 neg i2 and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), rl_nn ); + int temp1 = create (NodeType.AND, NEGATE( rr_nn ), lr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 388: // i1 i3 and i4 neg i2 neg and and + { + int temp0 = create (NodeType.AND, ll_nn, rl_nn ); + int temp1 = create (NodeType.AND, NEGATE( rr_nn ), NEGATE( lr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 389: // i1 neg i3 and i4 neg i2 neg and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), rl_nn ); + int temp1 = create (NodeType.AND, NEGATE( rr_nn ), NEGATE( lr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 390: // i1 i3 neg and i4 neg i2 and and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( rl_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rr_nn ), lr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 391: // i1 neg i3 neg and i4 neg i2 and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( rl_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rr_nn ), lr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 392: // i1 i3 neg and i4 neg i2 neg and and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( rl_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rr_nn ), NEGATE( lr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 393: // i1 neg i3 neg and i4 neg i2 neg and and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( rl_nn ) ); + int temp1 = create (NodeType.AND, NEGATE( rr_nn ), NEGATE( lr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 394: // i1 i3 xor i4 i2 xor xor + { + int temp0 = create (NodeType.XOR, ll_nn, rl_nn ); + int temp1 = create (NodeType.XOR, rr_nn, lr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = temp2; + break; + } + case 395: // i1 i3 xor i4 i2 xor xor neg + { + int temp0 = create (NodeType.XOR, ll_nn, rl_nn ); + int temp1 = create (NodeType.XOR, rr_nn, lr_nn ); + int temp2 = create_op_node (NodeType.XOR, temp0, temp1 ); + result = NEGATE( temp2 ); + break; + } + case 396: // i1 i4 and i2 and + { + int temp0 = create (NodeType.AND, ll_nn, rr_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, lr_nn ); + result = temp1; + break; + } + case 397: // i1 i4 and i2 neg and + { + int temp0 = create (NodeType.AND, ll_nn, rr_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( lr_nn ) ); + result = temp1; + break; + } + case 398: // i1 neg i4 and i2 and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), rr_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, lr_nn ); + result = temp1; + break; + } + case 399: // i1 neg i4 and i2 neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), rr_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( lr_nn ) ); + result = temp1; + break; + } + case 400: // i1 i4 neg and i2 and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( rr_nn ) ); + int temp1 = create_op_node (NodeType.AND, temp0, lr_nn ); + result = temp1; + break; + } + case 401: // i1 i4 neg and i2 neg and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( rr_nn ) ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( lr_nn ) ); + result = temp1; + break; + } + case 402: // i1 neg i4 neg and i2 and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( rr_nn ) ); + int temp1 = create_op_node (NodeType.AND, temp0, lr_nn ); + result = temp1; + break; + } + case 403: // i1 neg i4 neg and i2 neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( rr_nn ) ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( lr_nn ) ); + result = temp1; + break; + } + case 404: // i4 neg i2 neg and neg i1 and neg + { + int temp0 = create (NodeType.AND, NEGATE( rr_nn ), NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), ll_nn ); + result = NEGATE( temp1 ); + break; + } + case 405: // i1 i4 and neg i1 neg i2 and neg and + { + int temp0 = create (NodeType.AND, ll_nn, rr_nn ); + int temp1 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 406: // i4 neg i2 and neg i1 and neg + { + int temp0 = create (NodeType.AND, NEGATE( rr_nn ), lr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), ll_nn ); + result = NEGATE( temp1 ); + break; + } + case 407: // i1 i4 and neg i1 neg i2 neg and neg and + { + int temp0 = create (NodeType.AND, ll_nn, rr_nn ); + int temp1 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 408: // i1 neg i4 and neg i1 i2 and neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), rr_nn ); + int temp1 = create (NodeType.AND, ll_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 409: // i4 neg i2 neg and neg i1 neg and neg + { + int temp0 = create (NodeType.AND, NEGATE( rr_nn ), NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( ll_nn ) ); + result = NEGATE( temp1 ); + break; + } + case 410: // i1 neg i4 and neg i1 i2 neg and neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), rr_nn ); + int temp1 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 411: // i4 neg i2 and neg i1 neg and neg + { + int temp0 = create (NodeType.AND, NEGATE( rr_nn ), lr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( ll_nn ) ); + result = NEGATE( temp1 ); + break; + } + case 412: // i4 i2 neg and neg i1 and neg + { + int temp0 = create (NodeType.AND, rr_nn, NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), ll_nn ); + result = NEGATE( temp1 ); + break; + } + case 413: // i1 i4 and neg i1 neg i2 neg and neg and neg + { + int temp0 = create (NodeType.AND, ll_nn, rr_nn ); + int temp1 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = NEGATE( temp2 ); + break; + } + case 414: // i4 i2 and neg i1 and neg + { + int temp0 = create (NodeType.AND, rr_nn, lr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), ll_nn ); + result = NEGATE( temp1 ); + break; + } + case 415: // i1 i4 and neg i1 neg i2 and neg and neg + { + int temp0 = create (NodeType.AND, ll_nn, rr_nn ); + int temp1 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = NEGATE( temp2 ); + break; + } + case 416: // i1 neg i4 and neg i1 i2 neg and neg and neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), rr_nn ); + int temp1 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = NEGATE( temp2 ); + break; + } + case 417: // i4 i2 neg and neg i1 neg and neg + { + int temp0 = create (NodeType.AND, rr_nn, NEGATE( lr_nn ) ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( ll_nn ) ); + result = NEGATE( temp1 ); + break; + } + case 418: // i1 neg i4 and neg i1 i2 and neg and neg + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), rr_nn ); + int temp1 = create (NodeType.AND, ll_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = NEGATE( temp2 ); + break; + } + case 419: // i4 i2 and neg i1 neg and neg + { + int temp0 = create (NodeType.AND, rr_nn, lr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( ll_nn ) ); + result = NEGATE( temp1 ); + break; + } + case 420: // i1 i4 and neg i1 i2 xor and + { + int temp0 = create (NodeType.AND, ll_nn, rr_nn ); + int temp1 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 421: // i1 i4 and neg i1 i2 xor neg and + { + int temp0 = create (NodeType.AND, ll_nn, rr_nn ); + int temp1 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 422: // i1 i2 xor i4 i2 and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, rr_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 423: // i1 neg i4 and neg i1 i2 xor neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), rr_nn ); + int temp1 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 424: // i1 i4 neg and neg i1 i2 xor and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( rr_nn ) ); + int temp1 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), temp1 ); + result = temp2; + break; + } + case 425: // i1 i4 neg and neg i1 i2 xor neg and + { + int temp0 = create (NodeType.AND, ll_nn, NEGATE( rr_nn ) ); + int temp1 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 426: // i1 i2 xor i4 neg i2 and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.AND, NEGATE( rr_nn ), lr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 427: // i1 neg i4 neg and neg i1 i2 xor neg and + { + int temp0 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( rr_nn ) ); + int temp1 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 428: // i1 i4 xor i1 i2 and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp1 = create (NodeType.AND, ll_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 429: // i1 i4 xor i4 i2 and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp1 = create (NodeType.AND, rr_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 430: // i1 i4 xor i1 i2 neg and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp1 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 431: // i1 i4 xor i4 i2 neg and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp1 = create (NodeType.AND, rr_nn, NEGATE( lr_nn ) ); + int temp2 = create_op_node (NodeType.AND, temp0, NEGATE( temp1 ) ); + result = temp2; + break; + } + case 432: // i1 i4 xor neg i1 i2 and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp1 = create (NodeType.AND, ll_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 433: // i1 i4 xor neg i1 neg i2 and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp1 = create (NodeType.AND, NEGATE( ll_nn ), lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 434: // i1 i4 xor neg i1 i2 neg and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp1 = create (NodeType.AND, ll_nn, NEGATE( lr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 435: // i1 i4 xor neg i1 neg i2 neg and neg and + { + int temp0 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp1 = create (NodeType.AND, NEGATE( ll_nn ), NEGATE( lr_nn ) ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 436: // i1 i4 xor i1 i2 xor and + { + int temp0 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp1 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 437: // i1 i4 xor i4 i2 xor and + { + int temp0 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp1 = create (NodeType.XOR, rr_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 438: // i1 i2 xor i4 i2 xor and + { + int temp0 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp1 = create (NodeType.XOR, rr_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, temp0, temp1 ); + result = temp2; + break; + } + case 439: // i1 i4 xor neg i1 i2 xor neg and + { + int temp0 = create (NodeType.XOR, ll_nn, rr_nn ); + int temp1 = create (NodeType.XOR, ll_nn, lr_nn ); + int temp2 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( temp1 ) ); + result = temp2; + break; + } + case 440: // i4 i2 xor i1 and + { + int temp0 = create (NodeType.XOR, rr_nn, lr_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, ll_nn ); + result = temp1; + break; + } + case 441: // i4 i2 xor neg i1 and + { + int temp0 = create (NodeType.XOR, rr_nn, lr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), ll_nn ); + result = temp1; + break; + } + case 442: // i4 i2 xor i1 neg and + { + int temp0 = create (NodeType.XOR, rr_nn, lr_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( ll_nn ) ); + result = temp1; + break; + } + case 443: // i4 i2 xor neg i1 neg and + { + int temp0 = create (NodeType.XOR, rr_nn, lr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( ll_nn ) ); + result = temp1; + break; + } + case 444: // i4 i2 xor i1 and neg + { + int temp0 = create (NodeType.XOR, rr_nn, lr_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, ll_nn ); + result = NEGATE( temp1 ); + break; + } + case 445: // i4 i2 xor neg i1 and neg + { + int temp0 = create (NodeType.XOR, rr_nn, lr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), ll_nn ); + result = NEGATE( temp1 ); + break; + } + case 446: // i4 i2 xor i1 neg and neg + { + int temp0 = create (NodeType.XOR, rr_nn, lr_nn ); + int temp1 = create_op_node (NodeType.AND, temp0, NEGATE( ll_nn ) ); + result = NEGATE( temp1 ); + break; + } + case 447: // i4 i2 xor neg i1 neg and neg + { + int temp0 = create (NodeType.XOR, rr_nn, lr_nn ); + int temp1 = create_op_node (NodeType.AND, NEGATE( temp0 ), NEGATE( ll_nn ) ); + result = NEGATE( temp1 ); + break; + } + case 448: // i4 i2 xor + { + int temp0 = create_op_node (NodeType.XOR, rr_nn, lr_nn ); + result = temp0; + break; + } + case 449: // i4 i2 xor neg + { + int temp0 = create_op_node (NodeType.XOR, rr_nn, lr_nn ); + result = NEGATE( temp0 ); + break; + } + default: + throw new Exception ("Unknown Cases"); + + } + return result; + } + #endregion + + } +} + diff --git a/base/Applications/Benchmarks/sharpSAT/basic_classes.cs b/base/Applications/Benchmarks/sharpSAT/basic_classes.cs new file mode 100644 index 0000000..fa00717 --- /dev/null +++ b/base/Applications/Benchmarks/sharpSAT/basic_classes.cs @@ -0,0 +1,328 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +/////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Collections; +using System.Diagnostics; +//using Microsoft.Zap; +namespace SharpSAT +{ + public class Variable : SATCommon + { + + //public bool branchable = true; + //public bool reasoning = true; + private ushort flags = 0; + public ushort gflag = 0; + + public NodeType type = NodeType.UNKNOWN; + public IntVector outputs = new IntVector(2); + public int left = INVALID; + public int right = INVALID; + public int canonical = INVALID; + public int ref_count = 0; + public short lits_count_0= 0; + public short lits_count_1= 0; + public int uid = 0; + + public short score_0 = 0; + public short score_1 = 0; + public int asgn_pos = -1; + public int ordered_pos = 0; + + public short varValue = UNKNOWN; + public Antecedent antecedent= -1; + public int dlevel = -1; + + public void set_gid (int i) { gflag |= (ushort) (1<<(i-1)); } + public void clear_gid(int i) { gflag &= (ushort) ~(1<<(i-1)); } + public void clear_all_gid() { gflag = 0; } + public bool gid (int i) { return (( gflag & (ushort) (1<<(i-1))) != 0); } + + public void clear_all_flag() { flags = 0; } + public void set_flag(int idx) { flags |= (ushort) (1 << idx); } + public void clear_flag(int idx) { flags &= (ushort) (~(1< score_1? score_0 : score_1); } + public int lits_count() { return lits_count_0 + lits_count_1; } + public bool is_pi() { return type == NodeType.PI; } + public bool is_gate() { return (type == NodeType.AND || type == NodeType.XOR); } + public int output(int i) { return outputs[i];} + public int input(int k) { return (k==0 ? left: right); } + } + + + public class Clause : SATCommon + { + public ClType type = ClType.UNKNOWN; //indicates the clause type + public ushort gflag = 0; + public int uid = 0; + public int[] literals = null; + public int activity = 0; + + public void init (ClType tp, int [] lits, ushort gflg, int id) + { + type = tp; + literals = new int[lits.Length]; + Array.Copy(lits, 0, literals, 0, lits.Length); + gflag = gflg; + uid = id; + activity = 0; + } + + public bool gid (int i) + { + sharp_assert (i>=1 && i<= WORD_WIDTH); + return (( gflag & (ushort)(1<<(i-1))) != 0); + } + + public void set_gid (int i) + { + sharp_assert (i>=1 && i<= WORD_WIDTH); + gflag |= (ushort)(1<<(i-1)); + } + + public void clear_gid(int i) + { + sharp_assert (i>=1 && i<= WORD_WIDTH); + gflag &= (ushort)~(1<<(i-1)); + } + + public int num_lits { get {return literals.Length; } } + + public int literal (int n) + { + return literals[n]; + } + } + + public struct Antecedent + { + private int anteVal; + + public static implicit operator Antecedent( int v ) { return new Antecedent(v); } + public static implicit operator int (Antecedent an) { return an.anteVal; } + public Antecedent (int v) { anteVal = v; } + public Antecedent (ImpType tp, int index) + { + anteVal = (index << 3) + (int) tp; + } + public ImpType type + { + get { return (ImpType) (anteVal & 0x7); } + set + { + uint a = (uint) anteVal & (~(uint) 0x7); + uint b = (uint) value; + anteVal = (int) (a | b); + //anteVal = (((uint)anteVal) & (~(uint)0x7)) | (uint) value; + } + } + + public int index + { + get { return (anteVal >> 3); } + set { anteVal = ((anteVal & 7) | (value << 3)); } + } + } + + public struct Implication + { + public int lit; + public Antecedent ante; + } + + public class NodeHashMap : SATCommon + { + private const int XOR_MARK = (1 << 30); + private MyHashtable hash_table = new MyHashtable(); + + private class NodeHashMapKey + { + public int left; + public int right; + public NodeHashMapKey(int l, int r) + { + left = l; + right = r; + } + public override int GetHashCode() + { + long hashcode = left; + hashcode <<= 16; + hashcode ^= right; + int lsig = (int)(hashcode & 0xffffffff); + int msig = (int)(hashcode >> 32); + return lsig ^ msig; + } + public override bool Equals(object obj) + { + NodeHashMapKey other = obj as NodeHashMapKey; + if(other == null) return false; + return other.left == left && other.right == right; + } + } + + public int lookup (NodeType op, int i1, int i2) + { + sharp_assert (op == NodeType.AND || op == NodeType.XOR); + //1. left input always has smaller index than right + if (i1 > i2) + { + int temp = i1; + i1 = i2; + i2 = temp; + } + //2. For XOR gate, always require both inputs not negated + bool do_NEGATE = false; + if (op == NodeType.XOR) + { + if (IS_NEGATED(i1)) + { + i1 = NEGATE (i1); + do_NEGATE = !do_NEGATE; + } + if (IS_NEGATED(i2)) + { + i2 = NEGATE(i2); + do_NEGATE = !do_NEGATE; + } + } + //3. put special mark on the XOR node + int l, r; + l = i1; + r = i2; + if (op == NodeType.XOR) + l += XOR_MARK; + //4. Lookup + NodeHashMapKey key = new NodeHashMapKey(l, r); +// ulong key = ((ulong)l << 32) + (ulong) r; + object item = hash_table[key]; + if (item == null) + return INVALID; + int o = (int) item; + if (do_NEGATE) + o = NEGATE(o); + return o; + } + + public void insert ( int n, NodeType op, int i1, int i2) + { + sharp_assert (op == NodeType.AND || op == NodeType.XOR); + sharp_assert (i1 < i2); + sharp_assert (! ( (op == NodeType.XOR) && + ( IS_NEGATED(i1) || IS_NEGATED(i2) ))); + sharp_assert (!IS_NEGATED(n)); + + int l, r; + l = i1; + r = i2; + if (op == NodeType.XOR) + l += XOR_MARK; + NodeHashMapKey key = new NodeHashMapKey(l, r); +// ulong key = ((ulong)l << 32) + (ulong) r; + sharp_assert ( !hash_table.Contains(key)); + hash_table[key] = n; + } + + public void remove ( int n, NodeType op, int i1, int i2) + { + sharp_assert (op == NodeType.AND || op == NodeType.XOR); + sharp_assert (i1 < i2); + sharp_assert (! ( (op == NodeType.XOR) && + ( IS_NEGATED(i1) || IS_NEGATED(i2) ))); + sharp_assert ( ! IS_NEGATED(n) ); + //put special mark on the XOR node + int l, r; + l = i1; + r = i2; + if (op == NodeType.XOR) + l += XOR_MARK; + NodeHashMapKey key = new NodeHashMapKey(l, r); +// ulong key = ((ulong)l << 32) + (ulong) r; + + sharp_assert ( (int)hash_table[key] == n); + hash_table.Remove(key); + } + } + + + class FreeList + { + VarVector variables; + IntVector free_list; + int delete_count; + const double compact_ratio = 0.5; + + public FreeList (VarVector vars) + { + free_list = new IntVector(16); + variables = vars; + } + + public void add (IntVector new_frees) + { + for (int i=0; i< new_frees.size(); ++i) + free_list.push_back(new_frees[i]); + free_list.sort(); + } + + public void delete_index (int idx) + { + delete_count ++; + if ((double)delete_count / (double)free_list.size() > compact_ratio) + { + IntVector temp = new IntVector(16); + for (int i=0; i< free_list.size(); ++i) + { + if (idx == i) //just deleted, so won't be in free_list anymore + continue; + if (variables[free_list[i]] == null || + variables[free_list[i]].type == NodeType.FREE ) + temp.push_back(free_list[i]); + } + free_list = temp; + } + } + public int find_greater_than (int v) + { + int idx = free_list.binary_search (v); + if (idx < 0) + idx = ~ idx; + else + idx ++; + for (int i=idx; i < free_list.size(); ++i) + { + if (variables[free_list[i]] == null || + variables[free_list[i]].type == NodeType.FREE ) + { + int r = free_list[i]; + delete_index(i); + return r; + } + } + return -1; + } + } + + public class UnsatCore + { + public int [] core_clauses; + public int [] core_nodes; + } + + public class MyHashtable : Hashtable {} + + public interface SATHook + { + void OnBCP(); + void OnBacktrack(int blevel); + void OnCaseSplit(int svar); + } +} diff --git a/base/Applications/Benchmarks/sharpSAT/blifparser.cs b/base/Applications/Benchmarks/sharpSAT/blifparser.cs new file mode 100644 index 0000000..1685e5b --- /dev/null +++ b/base/Applications/Benchmarks/sharpSAT/blifparser.cs @@ -0,0 +1,429 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +/////////////////////////////////////////////////////////////////////////////// + +using System.Collections; +using System.Text; +using System.IO; +using System; +//using Microsoft.Zap; +namespace SharpSAT +{ + public class NetConst + { + public const int PI_MASK = 1; + public const int PO_MASK = (1 << 1); + public const int LATCH_OUT_MASK = (1 << 2); + public const int LATCH_IN_MASK = (1 << 3); + public const int COMB_MASK = (1 << 4); + //private NetConst() {} + } + + public enum ELatchDefault + { + LATCH_0 = 0, + LATCH_1 = 1, + LATCH_DC = 2, + LATCH_X = 3 + }; + + public enum EGateType + { + G_UNKNOWN, + G_NOT, //o = a' + G_AND_11, //o = ab + G_AND_10, //o = ab' + G_AND_01, //o = a'b + G_AND_00, //o = a'b' + G_OR_11, //o = a+b + G_OR_10, //o = a+b' + G_OR_01, //o = a'+b + G_OR_00, //o = a'+b' + G_CONST_1, + G_CONST_0, + G_WIRE, + }; + + public class Gate + { + public int index = -1; + public EGateType gate_type = EGateType.G_UNKNOWN; + public string name; + public IntVector fanins = new IntVector(2); + public IntVector fanouts = new IntVector(2); + public int type ; + public ELatchDefault latch_default ; + public ObjVector fanin_names = new ObjVector(1); + + public bool is_PI() { return ((type & NetConst.PI_MASK) != 0); } + public bool is_PO() { return ((type & NetConst.PO_MASK) != 0); } + public bool is_LATCH_IN() { return ((type & NetConst.LATCH_IN_MASK) != 0); } + public bool is_LATCH() { return ((type & NetConst.LATCH_OUT_MASK) != 0); } + public bool is_COMB() { return ((type & NetConst.COMB_MASK) != 0); } + public void set_PI() { type |= NetConst.PI_MASK; } + public void set_PO() { type |= NetConst.PO_MASK; } + public void set_LATCH_IN() { type |= NetConst.LATCH_IN_MASK; } + public void set_LATCH() { type |= NetConst.LATCH_OUT_MASK; } + public void set_COMB() { type |= NetConst.COMB_MASK; } + } + + class NetList : SATCommon + { + public string name; + public ObjVector nodes = new ObjVector(128); + public IntVector primary_inputs = new IntVector(4); + public IntVector primary_outputs = new IntVector(4); + public IntVector latches = new IntVector(4); + public IntVector combs = new IntVector(4); + public IntVector inputs = new IntVector(4); //include PI and latch's outputs + public IntVector outputs = new IntVector(4); //include PO and latch's inputs + public MyHashtable name2nodeid = new MyHashtable(); + + public Gate node (int k) + { + return (Gate)nodes[k]; + } + + Gate new_node(string name) + { + Gate node = new Gate(); + node.name = name;; + node.index = nodes.size(); + nodes.push_back(node); + name2nodeid[name] = node.index; + return node; + } + + Gate find_node_by_name(string name) + { + object o = name2nodeid[name]; + if (o == null) + return null; + else + return (Gate)nodes[(int)o]; + } + + Gate create_pi(string name) + { + Gate n; + if ( (n = find_node_by_name(name)) != null) + { + sharp_assert (n.is_PI()); + return n; + } + n = new_node(name); + n.set_PI(); + return n; + } + + Gate create_po(string name) + { + Gate n; + if ((n = find_node_by_name(name)) == null) + n = new_node(name); + n.set_PO(); + return n; + } + + Gate create_latch(string latch_in, string latch_out, ELatchDefault deft) + { + Gate n; + if ((n = find_node_by_name(latch_out)) == null) + n = new_node(latch_out); + //int id = n.index; + sharp_assert (n.fanin_names.empty()); + n.fanin_names.push_back(latch_in); + n.latch_default = deft; + n.set_LATCH(); + return n; + } + + Gate create_comb(string name, string [] inputs) + { + Gate n; + if ( (n = find_node_by_name(name)) == null) + n = new_node(name); + //int id = n.index; + sharp_assert (n.fanin_names.empty()); + foreach (string s in inputs) + n.fanin_names.push_back(s); + n.set_COMB(); + return n; + } + + static string get_multiple_line (StreamReader input) + { + string line = null; + StringBuilder str = new StringBuilder(); + while (true) + { + try + { + line = input.ReadLine(); + } + catch (Exception e) + { + Console.WriteLine("The file could not be read:"); + Console.WriteLine(e.Message); + fatal(); + } + if (line == null) + return null; + if (line.IndexOf('\\') == -1) + { + str.Append(line); + return str.ToString(); + } + else + str.Append(line.Replace('\\',' ')); + } + } + + void finalize_construct_network() + { + for ( int i=0; i< nodes.size(); ++i) + { + Gate n = node(i); + for ( int j=0; j< n.fanin_names.size(); ++j) + { + string name = (string)n.fanin_names[j]; + Gate pin = find_node_by_name(name); + sharp_assert (pin != null); + n.fanins.push_back(pin.index); + pin.fanouts.push_back(n.index); + if (n.is_LATCH()) + pin.set_LATCH_IN(); + } + } + for ( int i=0; i< nodes.size(); ++i) + { + Gate n = node(i); + if (n.is_PI()) + primary_inputs.push_back(n.index); + if (n.is_PI() || n.is_LATCH()) + inputs.push_back(n.index); + if (n.is_PO()) + primary_outputs.push_back(n.index); + if (n.is_PO() || n.is_LATCH_IN()) + outputs.push_back(n.index); + if (n.is_LATCH()) + latches.push_back(n.index); + if (n.is_COMB()) + combs.push_back(n.index); + } + } + + public void read_blif (string filename) + { + StreamReader input = null; + ObjVector lines = new ObjVector(128); + try + { + input = new StreamReader(filename); + } + catch (Exception e) + { + Console.WriteLine("The file could not be read:"); + Console.WriteLine(e.Message); + fatal(); + } + while (true) + { + string line = get_multiple_line(input); + if (line == null) + break; + lines.push_back(line); + if (line == ".end") + break; + } + for ( int i=0; i< lines.size(); ++i) + { + string line = (string)lines[i]; + string [] temp_tokens = line.Split(new char[] {' ','\t'}); + int total_tokens = 0; + foreach (string str in temp_tokens) + if (str != String.Empty) + ++ total_tokens; + if (total_tokens == 0) + continue; + string [] tokens = new string[total_tokens]; + foreach (string str in temp_tokens) + { + if (str != String.Empty) + { + tokens[tokens.Length - total_tokens] = str; + -- total_tokens; + } + } + string first_token = tokens[0]; + if (first_token == ".model") + { + this.name = tokens[1]; + } + else if (first_token == ".inputs") + { + for ( int k=1; k< tokens.Length; ++k) + create_pi(tokens[k]); + } + else if (first_token == ".outputs") + { + for ( int k=1; k< tokens.Length; ++k) + create_po(tokens[k]); + } + else if (first_token == ".latch") + { + sharp_assert (tokens.Length == 3 || tokens.Length == 4); + ELatchDefault dft_v = ELatchDefault.LATCH_X; + if (tokens.Length == 4) + { + string last_token = tokens[3]; + sharp_assert (last_token.Length == 1); + dft_v = (ELatchDefault) Int32.Parse(last_token); + } + create_latch(tokens[1], tokens[2], dft_v); + } + else if (first_token == ".names") + { + string [] inputs = new string [tokens.Length - 2]; + sharp_assert (inputs.Length == 1 || inputs.Length == 2); + string name = tokens[tokens.Length - 1]; + for ( int k=1; k< tokens.Length - 1; ++k) + inputs[k-1] = tokens[k]; + Gate node = create_comb(name, inputs); + + if ((string)lines[i+1] == "1 1" && + (string)lines[i+2] == "0 1" ) + { + node.gate_type = EGateType.G_CONST_1; + i+=2; + } + else if ((string)lines[i+1] == "1 1") + { + warning ("A gate is a wire, sweep first "); + node.gate_type = EGateType.G_WIRE; ++ i; + } + else if ((string)lines[i+1] == "0 1") + { + node.gate_type = EGateType.G_NOT; ++ i; + } + else if ((string)lines[i+1] == "11 1") + { + node.gate_type = EGateType.G_AND_11; ++ i; + } + else if ((string)lines[i+1] == "10 1") + { + node.gate_type = EGateType.G_AND_10; ++ i; + } + else if ((string)lines[i+1] == "01 1") + { + node.gate_type = EGateType.G_AND_01; ++ i; + } + else if ((string)lines[i+1] == "00 1") + { + node.gate_type = EGateType.G_AND_00; ++ i; + } + else if ((string)lines[i+1] == "0- 1" && + (string)lines[i+2] == "-0 1") + { + node.gate_type = EGateType.G_OR_00; i+=2; + } + else if ((string)lines[i+1] == "0- 1" && + (string)lines[i+2] == "-1 1") + { + node.gate_type = EGateType.G_OR_01; i+=2; + } + else if ((string)lines[i+1] == "1- 1" && + (string)lines[i+2] == "-0 1") + { + node.gate_type = EGateType.G_OR_10; i+=2; + } + else if ((string)lines[i+1] == "1- 1" && + (string)lines[i+2] == "-1 1") + { + node.gate_type = EGateType.G_OR_11; i+=2; + } + else + { + fatal ("Don't know gate type for " + line); + } + sharp_assert ( ((string)lines[i+1])[0] == '.'); + } + else if (first_token == ".end") + { + break; + } + else if (first_token == ".wire_load_slope") + { + warning("Warning: Ignoring " + first_token); + } + else if (first_token[0] == '.') + { + fatal (first_token + ": Unable to handle this keyword"); + } + } + finalize_construct_network(); + } + + public void write_blif(string filename) + { + StreamWriter outfile = new StreamWriter(filename); + outfile.WriteLine ( ".model " + this.name ); + + outfile.Write ( ".inputs" ); + for ( int i=0; i< primary_inputs.size(); ++i) + outfile.Write ( " " + node(primary_inputs[i]).name) ; + outfile.WriteLine (); + + outfile.Write ( ".outputs" ); + for ( int i=0; i< primary_outputs.size(); ++i) + outfile.Write ( " " + node(primary_outputs[i]).name) ; + outfile.WriteLine (); + + for ( int i=0; i< latches.size(); ++i) + { + Gate n = node(latches[i]); + outfile.WriteLine ( ".latch " + node(n.fanins[0]).name + " " + n.name + " " + (int) n.latch_default ); + } + for ( int i=0; i< combs.size(); ++i) + { + Gate n = node(combs[i]); + outfile.Write ( ".names"); + for ( int j=0; j< n.fanins.size(); ++j) + outfile.Write ( " " + node(n.fanins[j]).name); + outfile.WriteLine (" " + n.name ); + if (n.gate_type == EGateType.G_NOT) + outfile.WriteLine ( "0 1" ); + else if (n.gate_type == EGateType.G_AND_11) + outfile.WriteLine ( "11 1" ); + else if (n.gate_type == EGateType.G_AND_10) + outfile.WriteLine ( "10 1" ); + else if (n.gate_type == EGateType.G_AND_01) + outfile.WriteLine ( "01 1" ); + else if (n.gate_type == EGateType.G_AND_00) + outfile.WriteLine ( "00 1" ); + else if (n.gate_type == EGateType.G_OR_11) + outfile.WriteLine ( "1- 1" + '\n' + "-1 1" ); + else if (n.gate_type == EGateType.G_OR_10) + outfile.WriteLine ( "1- 1" + '\n' + "-0 1" ); + else if (n.gate_type == EGateType.G_OR_01) + outfile.WriteLine ( "0- 1" + '\n' + "-1 1" ); + else if (n.gate_type == EGateType.G_OR_00) + outfile.WriteLine ( "0- 1" + '\n' + "-0 1" ); +// else if (n.gate_type == EGateType.G_EQUAL) +// outfile.WriteLine ( "11 1" + '\n' + "00 1" ); + else if (n.gate_type == EGateType.G_CONST_1) + outfile.WriteLine ( "1 1" + '\n' + "0 1" ); + else if (n.gate_type == EGateType.G_WIRE) + outfile.WriteLine ( "1 1" + '\n' + "0 0" ); + else + fatal ("Unknown gate type" ); + } + outfile.WriteLine ( ".end" ); + outfile.Close(); + } + } +} diff --git a/base/Applications/Benchmarks/sharpSAT/constants.cs b/base/Applications/Benchmarks/sharpSAT/constants.cs new file mode 100644 index 0000000..9478dd3 --- /dev/null +++ b/base/Applications/Benchmarks/sharpSAT/constants.cs @@ -0,0 +1,252 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +/////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Collections; +using System.Diagnostics; +//using Microsoft.Zap; +namespace SharpSAT +{ + public class SATCommon + { + private static void print_stack () + { + /* HACKHACK unavailable on Singularity + Console.WriteLine("Stack Trace:"); + StackTrace st = new StackTrace(true); + for(int i =0; i< st.FrameCount; i++ ) + { + StackFrame sf = st.GetFrame(i); + Console.WriteLine("\t{0} at File: {1} Line: {2} ", + sf.GetMethod() , + sf.GetFileName(), + sf.GetFileLineNumber()); + } + */ + } + + public static void sharp_assert (bool is_true) + { + if (!is_true) + { + Console.WriteLine("\nAssertion Failed" ); + print_stack(); + System.Environment.Exit(1); + } + + } + + public static void warning (string msg) + { + Console.Write("\nWarning:" ); + Console.WriteLine(msg); + } + + public static void fatal () + { + Console.WriteLine("\nFatal Error" ); + print_stack(); + System.Environment.Exit(2); + } + + public static void fatal (string msg) + { + Console.WriteLine ("Fatal Error: {0}", msg); + print_stack(); + System.Environment.Exit(2); + } + + public static string StatusToString(SATStatus status) + { + switch (status) { + case SATStatus.UNDETERMINED: return "UNDETERMINED"; + case SATStatus.UNSATISFIABLE: return "UNSATISFIABLE"; + case SATStatus.SATISFIABLE: return "SATISFIABLE"; + case SATStatus.TIME_OUT: return "TIME"; + case SATStatus.MEM_OUT: return "MEM"; + case SATStatus.ABORTED: return "ABORTED"; + } + + return "UNKNOWN_RESULT"; + } + + public static int NEGATE (int s) { return s^1; } + public static int NON_NEGATED (int s) { return s&(~1);} + public static int SIGN (int s) { return s & 1; } + public static int NODE_ID (int s) { return s >> 1; } + public static int VID (int s) { return s >> 1; } + public static bool IS_NEGATED(int s) { return (s&1) == 1; } + + public const int INVALID = -1; + public const int UNKNOWN = 2; + public const int WORD_WIDTH = 16; + public const int UIDSHIFT = 27; + + } + + public enum ImpType : sbyte + { + NONE, + CLAUSE, + NODE, + PB, + } + + public enum ClType : sbyte + { + UNKNOWN, + ORIGINAL, + CONFLICT, + BLOCKING, + TEMP, + DELETED + } + + public enum NodeType : sbyte + { + UNKNOWN, + VARIABLE, + CONSTANT, + PI, + AND, + XOR, + FREE, + } + + public enum SATStatus + { + UNDETERMINED, + UNSATISFIABLE, + SATISFIABLE, + TIME_OUT, + MEM_OUT, + ABORTED + } + + public struct SolverStats + { + public bool been_reset ; + public bool active_area_changed ; + public int constraint_zero ; + public bool is_solving ; + public SATStatus outcome ; + public bool is_mem_out ; + public double start_cpu_time ; + public double finish_cpu_time ; + + public double total_cpu_time ; + public int num_rounds ; + public int num_free_variables ; + public int num_free_branch_vars ; + public int num_decisions ; + public int num_conflicts ; + public int num_backtracks ; + public int max_dlevel ; + public long num_implications ; + + public int num_cls_vars ; + public int num_orig_clauses ; + public int num_orig_literals ; + public int num_learned_clauses ; + public long num_learned_literals ; + public int num_deleted_clauses ; + public long num_deleted_literals ; + + public int next_restart; + public int next_gc; + public int next_decay; + + public int num_restarts; + public int num_garbage_collections; + + public int marked_current_dl; + + public SolverStats (bool do_init) + { + //regardless of the input, we have to init + been_reset = true; + active_area_changed = true; + constraint_zero = 0; + is_solving = false; + outcome = SATStatus.UNDETERMINED; + is_mem_out = false; + start_cpu_time = 0; + finish_cpu_time = 0; + + total_cpu_time = 0; + num_rounds = 0; + num_free_variables = 0; + num_free_branch_vars = 0; + num_decisions = 0; + num_conflicts = 0; + num_backtracks = 0; + max_dlevel = 0; + num_implications = 0; + + num_cls_vars = 0; + num_orig_clauses = 0; + num_orig_literals = 0; + num_learned_clauses = 0; + num_learned_literals = 0; + num_deleted_clauses = 0; + num_deleted_literals = 0; + + next_restart = 0; + next_gc = 0; + next_decay = 0; + + num_restarts = 0; + num_garbage_collections = 0; + + marked_current_dl = 0; + } + } + + public struct SolverParams + { + public double time_limit; + public long mem_limit; + + public bool enable_restart; + public int first_restart; + public int restart_period; + + public bool enable_gc; + public int gc_period; + public int gc_head_threshold; + public int gc_tail_threshold; + public int gc_head_length; + public int gc_tail_length; + public int gc_head_tail_ratio; + + public int decay_period; + + //public bool reason_on_trans_fanin_only; + + public SolverParams (bool init) + { + time_limit = 24 * 3600; + mem_limit = 1024 * 1024 * 512; + + enable_restart = true; + first_restart = 7000; + restart_period = 700; + + enable_gc = true; + gc_period = 600; + gc_head_threshold = 500; + gc_tail_threshold = 10; + gc_head_length = 6; + gc_tail_length = 45; + gc_head_tail_ratio = 16; + + decay_period = 40; + //reason_on_trans_fanin_only = false; + } + } +} diff --git a/base/Applications/Benchmarks/sharpSAT/core_extraction.cs b/base/Applications/Benchmarks/sharpSAT/core_extraction.cs new file mode 100644 index 0000000..a2ed5a5 --- /dev/null +++ b/base/Applications/Benchmarks/sharpSAT/core_extraction.cs @@ -0,0 +1,927 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +/////////////////////////////////////////////////////////////////////////////// + +using System; +using System.IO; +using System.Collections; +using System.Diagnostics; +//using Microsoft.Zap; +namespace SharpSAT +{ + sealed class ResolveNode : SATCommon + { + public int uid; + public int [] reasons; + + public ResolveNode () {} + public ResolveNode (int r, int [] antes) + { + uid = r; + reasons = antes; + } + + public int footprint() + { + return (3 + reasons.Length) * 4; + } + + public void Serialize (Stream stream) + { + stream.Seek (0, SeekOrigin.End); + BinaryWriter bw = new BinaryWriter ( stream ); + bw.Write (uid); + bw.Write (reasons.Length); + for (int i=0; i< reasons.Length; ++i) + bw.Write (reasons[i]); + bw.Write ( - reasons.Length); + bw.Flush(); + } + + static public ResolveNode DeSerializeForward (Stream stream) + { + BinaryReader br = new BinaryReader ( stream ); + ResolveNode r = new ResolveNode(); + r.uid = br.ReadInt32(); + int len = br.ReadInt32(); + r.reasons = new int [len]; + for (int i=0; i< r.reasons.Length; ++i) + r.reasons[i] = br.ReadInt32(); + int mlen = br.ReadInt32(); + sharp_assert (mlen == - len); + return r; + } + + static public ResolveNode DeSerializeBackward (Stream stream) + { + BinaryReader br = new BinaryReader ( stream ); + ResolveNode r = new ResolveNode(); + stream.Seek( -4, SeekOrigin.Current ); + int l = br.ReadInt32(); + sharp_assert (l < 0); + stream.Seek( - (-l + 3) * 4, SeekOrigin.Current ); + + r.uid = br.ReadInt32(); + int len = br.ReadInt32(); + r.reasons = new int [len]; + for (int i=0; i< r.reasons.Length; ++i) + r.reasons[i] = br.ReadInt32(); + int mlen = br.ReadInt32(); + sharp_assert (mlen == - len); + stream.Seek( - (-l + 3) * 4, SeekOrigin.Current ); + return r; + } + } + + class ResolutionTrace : SATCommon + { + const int A_LOCAL = 1; + const int B_LOCAL = 2; + const int GLOBAL = (A_LOCAL | B_LOCAL); + + private SharpSATSolver solver = null; + private bool enable = false; + private int cache_limit = 1024 * 1024 * 4; // 4 meg + private ResolveNode empty = null; + private Stream storage = new MemoryStream(); + private string filename = "resolution.trace"; + private IntVector reasons = new IntVector(4); + + public ResolutionTrace (SharpSATSolver s ) + { + solver = s; + } + public void enable_trace (bool e) + { + enable = e; + } + + public void reset() + { + empty = null; + if (storage != null) + storage.Close(); + storage = new MemoryStream(); + reasons = new IntVector(4); + } + + public void set_cache_limit (int sz) + { + cache_limit = sz; + } + public void set_temp_file (string fname) + { + filename = fname; + } + public void add_reason (int uid) + { + reasons.push_back(uid); + } + public void set_resolvent (int uid) + { + if (enable) + { + ResolveNode nd = new ResolveNode (uid, reasons.ToArray()); + + if (storage is MemoryStream && + storage.Length + nd.footprint() > cache_limit) //out of cache, so use file + { + Stream newstream = new FileStream (filename, FileMode.Create); + MemoryStream memstream = storage as MemoryStream; + byte [] buffer = memstream.ToArray(); + newstream.Write (buffer, 0, buffer.Length); + storage = newstream; + } + nd.Serialize(storage); + } + reasons.clear(); + } + public void set_empty_resolvents() + { + empty = new ResolveNode(-1, reasons.ToArray()); + } + + Clause clause(int cl_id) { + return solver.clause(cl_id); + } + + public void dump_trace (string fname) + { + StreamWriter output = new StreamWriter (fname, false); + long oldpos = storage.Position; + storage.Seek(0, SeekOrigin.Begin); + while (storage.Position < storage.Length) + { + ResolveNode nd = ResolveNode.DeSerializeForward (storage); + output.Write ("{0} <== ", nd.uid); + foreach (int r in nd.reasons) + { + if (is_node(r)) + output.Write(" {0}({1)}", node_uid(r), cls_idx(r)); + else + output.Write (" {0}", r); + } + output.Write("\n"); + } + output.Close(); + storage.Seek (oldpos, SeekOrigin.Begin); + } + + public MyHashtable generate_unsat_core() + { + if (empty == null) + fatal ("Not UNSAT, Cannot Generate Core"); + + MyHashtable hash = new MyHashtable(); + foreach (int uid in empty.reasons) + hash.Add (uid, null); + + long oldpos = storage.Position; + storage.Seek(0, SeekOrigin.End); + while (storage.Position > 0) + { + ResolveNode nd = ResolveNode.DeSerializeBackward (storage); + sharp_assert (!is_node(nd.uid)); + if (hash.Contains (nd.uid)) + { + foreach (int id in nd.reasons) + { + int uid = id; + if (is_node(id)) + uid = node_uid(id); + if (!hash.Contains(uid)) + hash.Add (uid, null); + } + hash.Remove (nd.uid); + } + } + storage.Seek (oldpos, SeekOrigin.Begin); + return hash; + } + + int find_pivot (int [] cl1, int [] cl2) + { + int [] combined = new int [ cl1.Length + cl2.Length ]; + Array.Copy (cl1, 0, combined, 0, cl1.Length); + Array.Copy (cl2, 0, combined, cl1.Length, cl2.Length); + Array.Sort (combined); + for (int i=1; i< combined.Length; ++ i) + if (combined[i] == (combined[i-1]^1)) + return VID(combined[i]); + fatal ("No pivot variable? "); + return 0; + } + + int [] resolve (int [] cl1, int [] cl2) + { + IntVector result = new IntVector(4); + int [] combined = new int [ cl1.Length + cl2.Length ]; + Array.Copy (cl1, 0, combined, 0, cl1.Length); + Array.Copy (cl2, 0, combined, cl1.Length, cl2.Length); + Array.Sort (combined); + + for (int i=0; i< combined.Length; ++ i) + { + if (result.empty()) + result.push_back (combined[i]); + else if (result.back == combined[i]) + continue; + else if (result.back == (combined[i] ^ 1)) + result.pop_back(); + else + result.push_back (combined[i]); + } + return result.ToArray(); + } + + int distance (int [] cl1, int [] cl2) + { + int [] combined = new int [ cl1.Length + cl2.Length ]; + Array.Copy (cl1, 0, combined, 0, cl1.Length); + Array.Copy (cl2, 0, combined, cl1.Length, cl2.Length); + Array.Sort (combined); + int distance = 0; + for (int i=1; i< combined.Length; ++ i) + { + if (combined[i] == (combined[i-1] ^ 1)) + { + distance ++; + i++; + } + } + return distance; + } + + int [][] gen_gate_clause (int vid) + { + Variable var = solver.variable(vid); + int a = var.input(0); + int b = var.input(1); + int o = vid + vid; + sharp_assert (a != INVALID && b != INVALID); + int [][] result; + if (var.type == NodeType.AND) + { + result = new int [3][]; + result[0] = new int [] { a, NEGATE(o)}; + result[1] = new int [] { b, NEGATE(o)}; + result[2] = new int [] { NEGATE(a), NEGATE(b), o}; + } + else + { + sharp_assert (var.type == NodeType.XOR); + result = new int [4][]; + result[0] = new int [] { NEGATE(a), b, o}; + result[1] = new int [] { a, NEGATE(b), o}; + result[2] = new int [] { a, b, NEGATE(o)}; + result[3] = new int [] { NEGATE(a), NEGATE(b), NEGATE(o)}; + } + return result; + } + + MyHashtable find_all_involved() + { + if (empty == null) + fatal ("Not UNSAT, Cannot Generate Core"); + + MyHashtable hash = new MyHashtable(); + foreach (int uid in empty.reasons) + hash.Add (uid, 1); + + long oldpos = storage.Position; + storage.Seek(0, SeekOrigin.End); + while (storage.Position > 0) + { + ResolveNode nd = ResolveNode.DeSerializeBackward (storage); + if (hash.Contains (nd.uid)) + foreach (int uid in nd.reasons) + { + if (!hash.Contains(uid)) + hash[uid] = 1; + else + hash[uid] = (int)hash[uid] + 1; + } + } + storage.Seek (oldpos, SeekOrigin.Begin); + return hash; + } + + void prepare_original_clauses (int a_gid, int b_gid, MyHashtable uid2lits, MyHashtable uid2sig, MyHashtable involved, int[] var_flag) + { + for (int i=0; i< var_flag.Length; ++i) + var_flag[i] = 0; + for (int i=0; i< solver.clauses.size(); ++i) + { + Clause cl = clause(i); + if (cl == null || !involved.Contains(cl.uid)) + continue; + + if (cl.type == ClType.ORIGINAL) + { + if (cl.gid(a_gid)) + { + sharp_assert (!cl.gid(b_gid)); + foreach (int lit in cl.literals) + var_flag [VID(lit)] |= A_LOCAL; + } + else + { + sharp_assert (cl.gid(b_gid)); + foreach (int lit in cl.literals) + var_flag [VID(lit)] |= B_LOCAL; + } + } + uid2lits[cl.uid] = cl.literals; + } + + for (int i=0; i< solver.original_clauses.size(); ++i) + { + Clause cl = clause(solver.original_clauses[i]); + sharp_assert (cl != null); + sharp_assert (cl.type == ClType.ORIGINAL); + + if (!involved.Contains(cl.uid)) + continue; + + int signal; + if (cl.gid(a_gid)) + { + sharp_assert (!cl.gid(b_gid)); + signal = solver.zero(); + foreach (int lit in cl.literals) + { + if (var_flag[VID(lit)] == GLOBAL) + signal = solver.bor (signal, lit); + } + } + else + { + sharp_assert (cl.gid(b_gid)); + signal = solver.one(); + } + uid2sig[cl.uid] = signal; + } + } + + public int gen_interpolant_from_clauses (int a_gid, int b_gid) + { + //solver.dump_file = new StreamWriter ("dump_file"); + //solver.dump_file.WriteLine ("{0} = INIT_VARS", solver.num_variables()); + + sharp_assert (solver.is_pure_clause_based()); + solver.convert_vars_to_pi(); + + MyHashtable uid2lits = new MyHashtable(); + MyHashtable uid2sig = new MyHashtable(); + MyHashtable involved = find_all_involved(); + int [] var_flag = new int [ solver.variables.size() ]; + prepare_original_clauses ( a_gid, b_gid, uid2lits, uid2sig, involved, var_flag); + + long oldpos = storage.Position; + storage.Seek(0, SeekOrigin.Begin); + while (storage.Position < storage.Length) + { + ResolveNode nd = ResolveNode.DeSerializeForward (storage); + if (!involved.Contains (nd.uid)) + continue; + + int uid = nd.reasons[0]; + sharp_assert (involved.Contains(uid)); + sharp_assert (uid2lits.Contains(uid)); + sharp_assert (uid2sig.Contains(uid)); + int [] lits = (int[])uid2lits[uid]; + int signal = (int)uid2sig[uid]; + + int count = (int)involved[uid] - 1 ; + if ( count == 0) + { + uid2lits.Remove(uid); + uid2sig.Remove(uid); + involved.Remove(uid); + } + else + involved[uid] = count; + + for (int i=1; i< nd.reasons.Length; ++i) + { + uid = nd.reasons[i]; + sharp_assert (uid < (1 << 29)); + sharp_assert (involved.Contains(uid)); + sharp_assert (uid2lits.Contains(uid)); + sharp_assert (uid2sig.Contains(uid)); + int [] lits1 = (int[]) uid2lits[uid]; + int signal1 = (int)uid2sig[uid]; + + count = (int)involved[uid] - 1 ; + if ( count == 0) + { + uid2lits.Remove(uid); + uid2sig.Remove(uid); + involved.Remove(uid); + } + else + involved[uid] = count; + + int pivot = find_pivot (lits, lits1); + lits = resolve(lits, lits1); + if (var_flag[pivot] == A_LOCAL) + signal = solver.bor (signal, signal1); + else + signal = solver.band (signal, signal1); + } + if (!uid2lits.Contains(nd.uid)) + uid2lits[nd.uid] = lits; + sharp_assert (!uid2sig.Contains(nd.uid)); + uid2sig[nd.uid] = signal; + + } + storage.Seek (oldpos, SeekOrigin.Begin); + { + int uid = empty.reasons[0]; + sharp_assert (involved.Contains(uid)); + sharp_assert (uid2lits.Contains(uid)); + sharp_assert (uid2sig.Contains(uid)); + int [] lits = (int[])uid2lits[uid]; + int signal = (int)uid2sig[uid]; + + int count = (int)involved[uid] - 1 ; + if ( count == 0) + { + uid2lits.Remove(uid); + uid2sig.Remove(uid); + involved.Remove(uid); + } + else + involved[uid] = count; + + for (int i=1; i< empty.reasons.Length; ++i) + { + uid = empty.reasons[i]; + sharp_assert (involved.Contains(uid)); + sharp_assert (uid2lits.Contains(uid)); + sharp_assert (uid2sig.Contains(uid)); + int [] lits1 = (int[]) uid2lits[uid]; + int signal1 = (int)uid2sig[uid]; + + count = (int)involved[uid] - 1 ; + if ( count == 0) + { + uid2lits.Remove(uid); + uid2sig.Remove(uid); + involved.Remove(uid); + } + else + involved[uid] = count; + + int pivot = find_pivot (lits, lits1); + lits = resolve(lits, lits1); + if (var_flag[pivot] == A_LOCAL) + signal = solver.bor (signal, signal1); + else + signal = solver.band (signal, signal1); + } + sharp_assert (lits.Length == 0); + sharp_assert (involved.Count == 0); + sharp_assert (uid2lits.Count == 0); + sharp_assert (uid2sig.Count == 0); + //solver.dump_file.WriteLine ("{0} = CONSTRAINT", signal); + //solver.dump_file.Close(); + return signal; + } + } + + bool is_node (int uid) + { + return (uid > (1<> UIDSHIFT; + } + + int not (int s) { return s ^ 1; } + + /* for AND + * 1: (a + c') + * 2: (b + c') + * 3: (a' + b' + c) + * for XOR + * 4: (a' + b + c) + * 5: (a + b' + c) + * 6: (a + b + c') + * 7: (a' + b' + c') + */ + + int [] get_cls (int vid, int cl_idx) + { + int [] result; + sharp_assert (solver.is_gate(vid + vid)); + int a = solver.variable(vid).input(0); + int b = solver.variable(vid).input(1); + int c = vid + vid; + switch(cl_idx) + { + case 1: + result = new int[]{a, not(c)}; + break; + case 2: + result = new int[]{b, not(c)}; + break; + case 3: + result = new int[]{not(a), not(b), c}; + break; + case 4: + result = new int[]{not(a), b, c}; + break; + case 5: + result = new int[]{a, not(b), c}; + break; + case 6: + result = new int[]{a, b, not(c)}; + break; + case 7: + result = new int[]{not(a), not(b), not(c)}; + break; + default: + sharp_assert (false); + result = null; + break; + } + return result; + } + + void prepare_original_nodes (int a_flag, int b_flag, MyHashtable uid2lits, MyHashtable uid2sig, MyHashtable involved) + { + MyHashtable uid2vid = new MyHashtable(); + + for (int i=1; i< solver.variables.size(); ++i) + { + Variable var = solver.variable(i); + if (var != null && (var.flag(a_flag) || var.flag(b_flag))) + uid2vid[var.uid] = i; + } + + foreach (object obj in involved) + { + int uid = (int)((DictionaryEntry) obj).Key; + if (!is_node(uid) || !uid2vid.Contains(node_uid(uid))) + continue; + int nid = node_uid (uid); + int cls_id = cls_idx (uid); + int vid = (int) uid2vid[nid]; + int [] lits = get_cls(vid, cls_id); + int sig; + sharp_assert (solver.variable(vid).flag(a_flag) || solver.variable(vid).flag(b_flag)); + if (solver.variable(vid).flag(b_flag)) + sig = solver.one(); + else + { + sig = solver.zero(); + foreach (int lit in lits) + { + sharp_assert (solver.node(lit).flag(a_flag)); + if (solver.node(lit).flag(b_flag)) + sig = solver.bor(sig, lit); + } + } + uid2lits[uid] = lits; + uid2sig[uid] = sig; + } + } + + public int gen_interpolant_from_signals (int a_node, int a_cls_id, int b_node, int b_cls_id) + { + //solver.dump_file = new StreamWriter ("dump_file"); + //solver.dump_file.WriteLine ("{0} = INIT_VARS", solver.num_variables()); + + int a_flag = solver.alloc_flag(); + int b_flag = solver.alloc_flag(); + solver.mark_transitive_fanins(a_node, a_flag); + solver.mark_transitive_fanins(b_node, b_flag); + + MyHashtable uid2lits = new MyHashtable(); + MyHashtable uid2sig = new MyHashtable(); + MyHashtable involved = find_all_involved(); + prepare_original_nodes (a_flag, b_flag, uid2lits, uid2sig, involved); + uid2lits[solver.clause(a_cls_id).uid] = solver.clause(a_cls_id).literals; + uid2lits[solver.clause(b_cls_id).uid] = solver.clause(b_cls_id).literals; + if (solver.node(a_node).flag(b_flag)) + uid2sig[solver.clause(a_cls_id).uid] = a_node; + else + uid2sig[solver.clause(a_cls_id).uid] = solver.zero(); + uid2sig[solver.clause(b_cls_id).uid] = solver.one(); + + long oldpos = storage.Position; + storage.Seek(0, SeekOrigin.Begin); + while (storage.Position < storage.Length) + { + ResolveNode nd = ResolveNode.DeSerializeForward (storage); + if (!involved.Contains (nd.uid)) + continue; + + int [] lits; + int signal; + int uid = nd.reasons[0]; + sharp_assert (involved.Contains(uid)); + sharp_assert (uid2sig.Contains(uid)); + lits = (int[])uid2lits[uid]; + signal = (int)uid2sig[uid]; + + int count = (int)involved[uid] - 1 ; + if ( count == 0) + { + uid2lits.Remove(uid); + uid2sig.Remove(uid); + involved.Remove(uid); + } + else + involved[uid] = count; + + for (int i=1; i< nd.reasons.Length; ++i) + { + uid = nd.reasons[i]; + sharp_assert (uid < (1 << 29)); + sharp_assert (involved.Contains(uid)); + sharp_assert (uid2lits.Contains(uid)); + sharp_assert (uid2sig.Contains(uid)); + int [] lits1 = (int[]) uid2lits[uid]; + int signal1 = (int)uid2sig[uid]; + + count = (int)involved[uid] - 1 ; + if ( count == 0) + { + uid2lits.Remove(uid); + uid2sig.Remove(uid); + involved.Remove(uid); + } + else + involved[uid] = count; + + int pivot = find_pivot (lits, lits1); + lits = resolve(lits, lits1); + if (!solver.variable(pivot).flag(b_flag)) + { + sharp_assert (solver.variable(pivot).flag(a_flag)); + signal = solver.bor (signal, signal1); + } + else + signal = solver.band (signal, signal1); + } + if (!uid2lits.Contains(nd.uid)) + uid2lits[nd.uid] = lits; + sharp_assert (!uid2sig.Contains(nd.uid)); + uid2sig[nd.uid] = signal; + } + storage.Seek (oldpos, SeekOrigin.Begin); + { + int uid = empty.reasons[0]; + sharp_assert (involved.Contains(uid)); + sharp_assert (uid2lits.Contains(uid)); + sharp_assert (uid2sig.Contains(uid)); + int [] lits = (int[])uid2lits[uid]; + int signal = (int)uid2sig[uid]; + + int count = (int)involved[uid] - 1 ; + if ( count == 0) + { + uid2lits.Remove(uid); + uid2sig.Remove(uid); + involved.Remove(uid); + } + else + involved[uid] = count; + + for (int i=1; i< empty.reasons.Length; ++i) + { + uid = empty.reasons[i]; + sharp_assert (involved.Contains(uid)); + sharp_assert (uid2lits.Contains(uid)); + sharp_assert (uid2sig.Contains(uid)); + int [] lits1 = (int[]) uid2lits[uid]; + int signal1 = (int)uid2sig[uid]; + + count = (int)involved[uid] - 1 ; + if ( count == 0) + { + uid2lits.Remove(uid); + uid2sig.Remove(uid); + involved.Remove(uid); + } + else + involved[uid] = count; + + int pivot = find_pivot (lits, lits1); + lits = resolve(lits, lits1); + if (!solver.variable(pivot).flag(b_flag)) + { + sharp_assert (solver.variable(pivot).flag(a_flag)); + signal = solver.bor (signal, signal1); + } + else + signal = solver.band (signal, signal1); + } + sharp_assert (lits.Length == 0); + sharp_assert (involved.Count == 0); + sharp_assert (uid2lits.Count == 0); + sharp_assert (uid2sig.Count == 0); + //solver.dump_file.WriteLine ("{0} = CONSTRAINT", signal); + //solver.dump_file.Close(); + + solver.free_flag(a_flag); + solver.free_flag(b_flag); + return signal; + } + } + // gretay -- change start + public int gen_interpolant_from_signals_ex (int a_node, int a_cls_id, int b_node, int b_cls_id, int[] c_cls_id, int[] c_interp) + { + //solver.dump_file = new StreamWriter ("dump_file"); + //solver.dump_file.WriteLine ("{0} = INIT_VARS", solver.num_variables()); + + int a_flag = solver.alloc_flag(); + int b_flag = solver.alloc_flag(); + solver.mark_transitive_fanins(a_node, a_flag); + solver.mark_transitive_fanins(b_node, b_flag); + + assert(c_cls_id.Length == c_interp.Length); + + MyHashtable uid2lits = new MyHashtable(); + MyHashtable uid2sig = new MyHashtable(); + MyHashtable involved = find_all_involved(); + prepare_original_nodes (a_flag, b_flag, uid2lits, uid2sig, involved); + + // init A info + int a_uid = solver.clause(a_cls_id).uid; + if (involved.Contains(a_uid)) + { + uid2lits[a_uid] = solver.clause(a_cls_id).literals; + int s = solver.zero(); + foreach (int lit in solver.clause(a_cls_id).literals) + { + sharp_assert (solver.node(lit).flag(a_flag)); + if (solver.node(lit).flag(b_flag)) + s = solver.bor(s, lit); + } + uid2sig[a_uid] = s; + //uid2sig[a_uid] = a_node; + } + // init B info + int b_uid = solver.clause(b_cls_id).uid; + if (involved.Contains(b_uid)) + { + uid2lits[b_uid] = solver.clause(b_cls_id).literals; + uid2sig[b_uid] = solver.one(); + } + // init C info + for (int i = 0; i < c_cls_id.Length; i++ ) + { + Clause cl = solver.clause(c_cls_id[i]); + if (involved.Contains(cl.uid)) + { + uid2lits[cl.uid] = cl.literals; + uid2sig[cl.uid] = c_interp[i]; + } + } + + long oldpos = storage.Position; + storage.Seek(0, SeekOrigin.Begin); + while (storage.Position < storage.Length) + { + ResolveNode nd = ResolveNode.DeSerializeForward (storage); + if (!involved.Contains (nd.uid)) + continue; + + int [] lits; + int signal; + int uid = nd.reasons[0]; + sharp_assert (involved.Contains(uid)); + sharp_assert (uid2sig.Contains(uid)); + lits = (int[])uid2lits[uid]; + signal = (int)uid2sig[uid]; + + int count = (int)involved[uid] - 1 ; + if ( count == 0) + { + uid2lits.Remove(uid); + uid2sig.Remove(uid); + involved.Remove(uid); + } + else + involved[uid] = count; + + for (int i=1; i< nd.reasons.Length; ++i) + { + uid = nd.reasons[i]; + sharp_assert (uid < (1 << 29)); + sharp_assert (involved.Contains(uid)); + sharp_assert (uid2lits.Contains(uid)); + sharp_assert (uid2sig.Contains(uid)); + int [] lits1 = (int[]) uid2lits[uid]; + int signal1 = (int)uid2sig[uid]; + + count = (int)involved[uid] - 1 ; + if ( count == 0) + { + uid2lits.Remove(uid); + uid2sig.Remove(uid); + involved.Remove(uid); + } + else + involved[uid] = count; + + int pivot = find_pivot (lits, lits1); + lits = resolve(lits, lits1); + if ( (solver.variable(pivot).flag(a_flag)) + && (!solver.variable(pivot).flag(b_flag))) + { + signal = solver.bor (signal, signal1); + } + else + { + signal = solver.band (signal, signal1); + } + } + if (!uid2lits.Contains(nd.uid)) + uid2lits[nd.uid] = lits; + sharp_assert (!uid2sig.Contains(nd.uid)); + uid2sig[nd.uid] = signal; + + } + storage.Seek (oldpos, SeekOrigin.Begin); + { + int uid = empty.reasons[0]; + sharp_assert (involved.Contains(uid)); + sharp_assert (uid2lits.Contains(uid)); + sharp_assert (uid2sig.Contains(uid)); + int [] lits = (int[])uid2lits[uid]; + int signal = (int)uid2sig[uid]; + + int count = (int)involved[uid] - 1 ; + if ( count == 0) + { + uid2lits.Remove(uid); + uid2sig.Remove(uid); + involved.Remove(uid); + } + else + involved[uid] = count; + + for (int i=1; i< empty.reasons.Length; ++i) + { + uid = empty.reasons[i]; + sharp_assert (involved.Contains(uid)); + sharp_assert (uid2lits.Contains(uid)); + sharp_assert (uid2sig.Contains(uid)); + int [] lits1 = (int[]) uid2lits[uid]; + int signal1 = (int)uid2sig[uid]; + + count = (int)involved[uid] - 1 ; + if ( count == 0) + { + uid2lits.Remove(uid); + uid2sig.Remove(uid); + involved.Remove(uid); + } + else + involved[uid] = count; + + int pivot = find_pivot (lits, lits1); + lits = resolve(lits, lits1); + + if ( (solver.variable(pivot).flag(a_flag)) + && (!solver.variable(pivot).flag(b_flag))) + { + signal = solver.bor (signal, signal1); + } + else + { + signal = solver.band (signal, signal1); + } + } + sharp_assert (lits.Length == 0); + sharp_assert (involved.Count == 0); + sharp_assert (uid2lits.Count == 0); + sharp_assert (uid2sig.Count == 0); + //solver.dump_file.WriteLine ("{0} = CONSTRAINT", signal); + //solver.dump_file.Close(); + + solver.free_flag(a_flag); + solver.free_flag(b_flag); + //solver.free_flag(c_flag); + return signal; + } + } + // gretay -- change end + + } +} diff --git a/base/Applications/Benchmarks/sharpSAT/main.cs b/base/Applications/Benchmarks/sharpSAT/main.cs new file mode 100644 index 0000000..3f4d3a5 --- /dev/null +++ b/base/Applications/Benchmarks/sharpSAT/main.cs @@ -0,0 +1,699 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +/////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Collections; +using System.Text; +using System.IO; +using SharpSAT; +//using Microsoft.Zap; +namespace SharpSATTest +{ + public class SATSolverTests : SATCommon + { + /* a helper function */ + static private string getToken(string [] tokens, ref int index) + { + for (; index < tokens.Length; ) + { + ++index; + if (tokens[index - 1] != String.Empty) + return tokens[index -1]; + } + return null; + } + + /* this demonstrate the structure interface */ + static void test_structure_solver (string[] args) + { + SATSolver solver = new SATSolver(); + int a = solver.CreatePI(); + int b = solver.CreatePI(); + int c = solver.CreatePI(); + //int d = solver.CreatePI(); + int xor_a_b = solver.Xor(a, b); + int not_a = solver.Not(a); + int not_b = solver.Not(b); + int and_a_not_b = solver.And (a, not_b); + int and_b_not_a = solver.And (b, not_a); + int xor_a_b_p = solver.Or(and_a_not_b, and_b_not_a); + int miter = solver.Xor(xor_a_b, xor_a_b_p); + SATStatus r = solver.TestSAT(miter); + System.Console.WriteLine ("Test Right {0}", r.ToString()); + + int and_a_b = solver.And (a, b); + int xor_a_b_wrong = solver.Or (and_a_not_b, and_a_b); + int miter1 = solver.Xor(xor_a_b, xor_a_b_wrong); + r = solver.TestSAT(miter1); + System.Console.WriteLine ("Test Wrong {0}", r.ToString()); + + int and_a_b_c = solver.And (solver.And(a,b), c); + + int flag = solver.AllocFlag (); + solver.MarkTransitiveFanins(and_a_b_c, flag); + for (int i=0, sz=solver.NumPI(); i< sz; ++i) + { + int node_id = solver.NthPI(i); + bool flagset = solver.IsNodeFlagSet (node_id, flag); + if (flagset) + System.Console.WriteLine ("PI {0} is in the transitive fanin", i); + else + System.Console.WriteLine ("PI {0} is NOT in the transitive fanin", i); + } + solver.ClearFlag(flag); + + + MyHashtable nameMap = new MyHashtable(); + nameMap.Add(0, "PrimaryIn 0"); + System.Console.WriteLine(solver.TreeToString(miter1, nameMap)); + System.Console.WriteLine(solver.TreeToString(xor_a_b, nameMap)); + + System.Console.WriteLine ("Press Return..."); + System.Console.ReadLine(); + } + + /* this demonstrate the clause interface, it reads in a CNF file and + * Solve it, just as a regular SAT solver should do */ + static void test_clause_solver (string[] args) + { + SATSolver solver = new SATSolver(); + + // NB: on Singularity, args[0] is the exe image name + if (args.Length != 2) + { + System.Console.WriteLine ("Simple SAT Solver using the C# interface"); + System.Console.WriteLine ("Usage: Solve CNF_file "); + return; + } + StreamReader input = null; + try + { + input = new StreamReader(args[1]); + } + catch(Exception e) + { + Console.WriteLine (e.ToString()); + } + + string line; + System.Console.WriteLine ("Solving {0}", args[1]); + while (true) + { + line = input.ReadLine(); + if (line == null) + break; + string [] tokens = line.Split(new char[] {' ','\t'}); + int index = 0; + string token = getToken (tokens, ref index); + if (token == "c") + continue; + if (token == "p") + { + token = getToken (tokens, ref index); + if (token != "cnf") + { + System.Console.WriteLine("Unrecognized Header"); + return; + } + else + { + token = getToken (tokens, ref index); + solver.SetNumVariables (int.Parse(token)); + continue; + } + } + else + { + ArrayList lits = new ArrayList(); + while (token != null && int.Parse(token) != 0) + { + lits.Add (int.Parse(token)); + token = getToken (tokens, ref index); + } + + + if (lits.Count> 0) + { + int [] clause = new int [lits.Count]; + for (int k=0; k< lits.Count; ++k) + { + clause[k] = (int)lits[k]; + if (clause[k] > 0) + clause[k] += clause[k]; + else + clause[k] = 1 - clause[k] - clause[k]; + } + solver.AddClause ( clause ); + } + } + } + input.Close(); + SATStatus result = solver.Solve(); + if (result == SATStatus.SATISFIABLE) + { + System.Console.WriteLine ("SAT"); + for (int i=1; i<= solver.GetNumVariables(); ++i) + { + if (solver.VariableValue(i)==1) + { + Console.Write ("{0} ", i); + } + else if (solver.VariableValue(i)==0) + { + Console.Write ("-{0} ", i); + } + else + { + Console.Write ("({0}) ", i); + } + if (i % 10 == 0) + { + Console.WriteLine (""); + } + } + } + else if (result == SATStatus.UNSATISFIABLE) + System.Console.WriteLine ("UNSAT"); + + System.Console.WriteLine ("Num Variables {0}", solver.num_variables() ); + System.Console.WriteLine ("Num Orig. Clauses {0}", solver.stats.num_orig_clauses ); + System.Console.WriteLine ("Num Learned Clauses {0}", solver.stats.num_learned_clauses); + System.Console.WriteLine ("Num Learned Literals {0}", solver.stats.num_learned_literals); + System.Console.WriteLine ("Num Garbage Collection {0}", solver.stats.num_garbage_collections); + System.Console.WriteLine ("Num Deleted Clauses {0}", solver.stats.num_deleted_clauses ); + System.Console.WriteLine ("Num Deleted Literals {0}", solver.stats.num_deleted_literals ); + System.Console.WriteLine ("Num Decisions {0}", solver.stats.num_decisions ); + System.Console.WriteLine ("Num Backtracks {0}", solver.stats.num_backtracks ); + System.Console.WriteLine ("Num Implications {0}", solver.stats.num_implications ); + System.Console.WriteLine ("Total Runtime {0}", solver.stats.total_cpu_time ); + System.Console.WriteLine ("Instance is {0}", SATCommon.StatusToString(result)); + } + + public static void log_execution(string [] args) + { + SATSolver solver = new SATSolver(); + if (args.Length != 1) + { + System.Console.WriteLine ("Simple SAT Solver using the C# interface"); + System.Console.WriteLine ("Usage: Solve CNF_file "); + return; + } + FileInfo file = new FileInfo (args[0]); + StreamReader input = file.OpenText(); + string line; + IntVector nodes = new IntVector(4); + while (true) + { + line = input.ReadLine(); + if (line == null) + break; + string [] tokens = line.Split(new char[] {' ','\t'}); + int index = 0; + string token = getToken (tokens, ref index); + int k = int.Parse (token); + token = getToken (tokens, ref index); + sharp_assert (token == "="); + token = getToken (tokens, ref index); + if (token == "INIT_VARS") + { + solver.SetNumVariables(k); + solver.ConvertVarsToPI(); + nodes.resize ( k + k + 2); + for (int i=0; i < k + k + 2; ++i) + nodes[i] = i; + } + else if (token == "CONSTRAINT") + { + solver.Constraint(nodes[k]); + SATStatus status = solver.Solve(); + if (status == SATStatus.UNSATISFIABLE) + Console.WriteLine("UNSAT"); + else + Console.WriteLine("SAT"); + } + else if (token == "PI") + { + continue; + } + else if (token == "CL") + { + IntVector lits = new IntVector(4); + token = getToken(tokens, ref index); + while ( token != null ) + { + lits.push_back (int.Parse(token)); + token = getToken(tokens, ref index); + } + solver.AddClause(lits.ToArray()); + } + else if (token == "AND") + { + token = getToken (tokens, ref index); + int i1 = int.Parse (token); + token = getToken (tokens, ref index); + int i2 = int.Parse (token); + int r = solver.And (nodes[i1], nodes[i2]); + if (nodes.size() < k + 2) + nodes.resize (k + 2); + nodes[k] = r; + nodes [k ^ 1] = (r^1); + } + else if (token == "XOR") + { + token = getToken (tokens, ref index); + int i1 = int.Parse (token); + token = getToken (tokens, ref index); + int i2 = int.Parse (token); + int r = solver.Xor (nodes[i1], nodes[i2]); + if (nodes.size() < k + 1) + nodes.resize (k + 1); + nodes[k] = r; + nodes [k ^ 1] = (r^1); + } + else + fatal ("Unrecognized Symbol"); + } + } + + static Random rand; + + static int [] randclause (int begin, int end) + { + IntVector cls = new IntVector(4); + while (cls.empty()) + { + double r = rand.NextDouble(); + int a = (int) (r * (end - begin)) + begin; + r = rand.NextDouble(); + if (r < 0.5) + a = a + a; + else + a = a + a + 1; + + r = rand.NextDouble(); + int b = (int) (r * (end - begin)) + begin; + r = rand.NextDouble(); + if (r < 0.5) + b = b + b; + else + b = b + b + 1; + + r = rand.NextDouble(); + int c = (int) (r * (end - begin)) + begin; + r = rand.NextDouble(); + if (r < 0.5) + c = c + c; + else + c = c + c + 1; + + if ((a>>1) != (b>>1)) + { + cls.push_back (a); + cls.push_back (b); + if ((a>>1) != (c>>1) && (b>>1) != (c>>1)) + cls.push_back (c); + } + else + { + cls.push_back (b); + if ((b>>1) != (c>>1)) + cls.push_back (c); + } + } + return cls.ToArray(); + } + + static bool test_interpolant_clauses (int n_vars, int n_cls, int span, int randseed) + { + rand = new Random(randseed); + int [] [] a_clauses; + int [] [] b_clauses; + a_clauses = new int [n_cls][]; + b_clauses = new int [n_cls][]; + for (int i=0; i< n_cls; ++i) + a_clauses[i] = randclause ( 1, n_vars/2 + span); + for (int i=0; i< n_cls; ++i) + b_clauses[i] = randclause ( n_vars/2 - span, n_vars + 1); + + SATSolver solver = new SATSolver(); + solver.SetNumVariables(n_vars); + int a_gid = solver.AllocGID(); + int b_gid = solver.AllocGID(); + //1. Test if A is satisfiable + for (int i=0; i< n_cls; ++i) + solver.AddClause (a_clauses[i], a_gid); + if (solver.Solve() != SATStatus.SATISFIABLE) + { + Console.Write ("A SAT"); + return false; + } + solver.DeleteGroup(a_gid); + //1. Test if B is satisfiable + for (int i=0; i< n_cls; ++i) + solver.AddClause (b_clauses[i], b_gid); + if (solver.Solve() != SATStatus.SATISFIABLE) + { + Console.Write ("B SAT"); + return false; + } + //3. Generate Interpolant + a_gid = solver.AllocGID(); + for (int i=0; i< n_cls; ++i) + solver.AddClause (a_clauses[i], a_gid); + Console.Write("Interpolant "); + int interpolant = solver.GenInterpolantFromClauseGroups ( a_gid, b_gid); + if (interpolant == -1 ) + { + Console.Write("AB SAT" ); + return false; + } + solver.Reference(interpolant); + //now test IB Unsatisfiable + Console.Write("IB "); + solver.DeleteGroup (a_gid); + sharp_assert (solver.stats.num_orig_clauses == n_cls); + int c = solver.Constraint(interpolant); + SATStatus status = solver.Solve(); + if (status != SATStatus.UNSATISFIABLE) + sharp_assert (false); + + //4. test AI Satisfiable + Console.Write("AI "); + solver.DeleteGroup (b_gid); + a_gid = solver.AllocGID(); + for (int i=0; i< n_cls; ++i) + solver.AddClause (a_clauses[i], a_gid); + status = solver.Solve(); + if (status != SATStatus.SATISFIABLE) + assert(false); + //5. test AI' Unsat (i.e. A=>I) + Console.Write("AI' "); + solver.ReleaseConstraint (c); + c = solver.Constraint(solver.Not(interpolant)); + status = solver.Solve(); + if (status != SATStatus.UNSATISFIABLE) + sharp_assert (false); + solver.ReleaseConstraint (c); + return true; + } + + static int build_struct (SATSolver solver, int [][] clauses) + { + int sig = solver.one(); + for (int i=0; i< clauses.Length; ++i) + { + int s = solver.zero(); + foreach (int lit in clauses[i]) + s = solver.Or(s, lit); + sig = solver.And(sig, s); + } + return sig; + } + + static bool test_interpolant_structure (int n_vars, int n_cls, int span, int randseed) + { + rand = new Random(randseed); + int [] [] a_clauses; + int [] [] b_clauses; + a_clauses = new int [n_cls][]; + b_clauses = new int [n_cls][]; + for (int i=0; i< n_cls; ++i) + a_clauses[i] = randclause ( 1, n_vars/2 + span); + for (int i=0; i< n_cls; ++i) + b_clauses[i] = randclause ( n_vars/2 - span, n_vars + 1); + + SATSolver solver = new SATSolver(); + solver.SetNumVariables(n_vars); + solver.ConvertVarsToPI(); + int s_a = build_struct(solver, a_clauses); + int s_b = build_struct(solver, b_clauses); + solver.Reference(s_a); + solver.Reference(s_b); + //1. Test if A is satisfiable + int c_a = solver.Constraint(s_a); + if (solver.Solve() != SATStatus.SATISFIABLE) + { + Console.Write ("A SAT"); + return false; + } + solver.ReleaseConstraint(c_a); + //2. Test if B is satisfiable + int c_b = solver.Constraint(s_b); + if (solver.Solve() != SATStatus.SATISFIABLE) + { + Console.Write ("B SAT"); + return false; + } + solver.ReleaseConstraint(c_b); + //now get interpolant I + Console.Write("Interpolant "); + int interpolant = solver.GenInterpolantFromSignals ( s_a, s_b); + if (interpolant == -1) + { + Console.Write ("AB SAT"); + return false; + } + solver.Reference (interpolant); + //3. test IB Unsatisfiable + Console.Write("IB "); + c_b = solver.Constraint(s_b); + int c_i = solver.Constraint(interpolant); + SATStatus status = solver.Solve(); + if (status != SATStatus.UNSATISFIABLE) + sharp_assert (false); + solver.ReleaseConstraint (c_b); + //4. test AI Satisfiable + Console.Write("AI "); + c_a = solver.Constraint (s_a); + status = solver.Solve(); + if (status != SATStatus.SATISFIABLE) + assert(false); + //5. test AI' Unsat (i.e. A=>I) + Console.Write("AI' "); + solver.ReleaseConstraint (c_i); + solver.Constraint(solver.Not(interpolant)); + status = solver.Solve(); + if (status != SATStatus.UNSATISFIABLE) + sharp_assert (false); + return true; + } + + static int build_irregular_struct (SATSolver solver, int [][] clauses,int randseed) + { + Random rand = new Random(randseed); + + int sig = solver.one(); + for (int i=0; i< clauses.Length; ++i) + { + int s = solver.zero(); + foreach (int lit in clauses[i]) + { + if (rand.NextDouble() > 0.2) + s = solver.Or(s, lit); + else + s = solver.Xor(s, lit); + } + + if (rand.NextDouble() > 0.15) + sig = solver.And(sig, s); + else + sig = solver.Xor(sig, s); + } + return sig; + } + + static bool test_existential_quantification ( int n_cls, int n_vars, int n_qvar, int rseed) + { + rand = new Random(rseed); + int [] [] clauses = new int [n_cls][]; + for (int i=0; i< n_cls; ++i) + clauses[i] = randclause ( 1, n_vars + 1); + int [] qvars = new int [n_qvar]; + for (int i=1; i<= n_qvar; ++i) + qvars[i-1] = i + i; + + SATSolver solver = new SATSolver(); + solver.SetNumVariables(n_vars); + solver.ConvertVarsToPI(); + int s = build_irregular_struct(solver, clauses, 1); + int q1 = solver.expand_exist_quantify(s, qvars); + //int q2 = solver.enum_exist_quantify(s, qvars); + int q2 = solver.enum_exist_quantify_smart(s, qvars); + + SATStatus status = solver.solve(); + sharp_assert (status == SATStatus.SATISFIABLE); + int notequ = solver.Xor(q1, q2); + solver.Constraint(notequ); + status = solver.Solve(); + sharp_assert (status == SATStatus.UNSATISFIABLE); + return true; + } + + public static bool UnitTest() + { + SATSolver solver = new SATSolver(); + + int ab = solver.NthPI(0); + int bc = solver.NthPI(1); + int ac = solver.NthPI(2); + + int not_ab = solver.Not(ab); + int not_bc = solver.Not(bc); + solver.Not(ac); + + int fafb = solver.NthPI(3); + int not_fafb = solver.Not(fafb); + + int fbfc = solver.NthPI(4); + int not_fbfc = solver.Not(fbfc); + + // ((a=b && b != c) || (a!=b && b=c) || (a!=b && a=c)) && f(a)!=f(b) && f(b)!=f(c) + int d1 = solver.And(ab, not_bc); + int d2 = solver.And(bc, not_ab); + int d3 = solver.And(ac, not_ab); + + int c1 = solver.Or(d1,d2); + int c2 = solver.Or(c1,d3); + + int c3 = solver.And(c2,not_fafb); + int c4 = solver.And(c3, not_fbfc); + + int formula = c4; + int[] ret = solver.FindSatAssignment(formula); + if(ret == null) return false; + + int[] clause = new int[2]; + clause[0] = solver.Not(ab); + clause[1] = fafb; + solver.AddClause(clause); + ret = solver.FindSatAssignment(formula); + if(ret == null) return false; + return true; + } + + public static void print_model(int [] m) + { + Console.WriteLine ("Model Is " ); + foreach (int e in m) + { + if ( (e&1) == 1) + Console.Write ("-"); + Console.Write( (e/2) + " "); + } + Console.WriteLine(""); + } + + public static bool test_small_model() + { + SATSolver solver = new SATSolver(); + + int a = solver.NthPI(0); + int b = solver.NthPI(1); + int c = solver.NthPI(2); + int d = solver.NthPI(3); + + int ab = solver.And(a, b); + int cd = solver.And(c, d); + int abcd = solver.And(ab, cd); + int constraint = solver.Constraint(abcd); + solver.Solve(); + int [] model = solver.FindSmallModel(); + print_model (model); + solver.ReleaseConstraint(constraint); + + int not_abcd = solver.Not(abcd); + constraint = solver.Constraint(not_abcd); + solver.Solve(); + model = solver.FindSmallModel(); + print_model (model); + solver.ReleaseConstraint(constraint); + + int e = solver.CreatePI(); + int f = solver.CreatePI(); + int exf = solver.Xor (e, f); + int and_exf_abcd = solver.And(exf, abcd); + constraint = solver.Constraint(and_exf_abcd); + solver.Solve(); + model = solver.FindSmallModel(); + print_model (model); + solver.ReleaseConstraint(constraint); + + int not_and_exf_abcd = solver.Not(and_exf_abcd); + constraint = solver.Constraint(not_and_exf_abcd); + solver.Solve(); + model = solver.FindSmallModel(); + print_model (model); + solver.ReleaseConstraint(constraint); + return true; + } + + public static void test_quantification_edge_case () + { + int n_cls = 100; + int n_vars = 50; + int n_qvar = 10; + rand = new Random(10); + int [] [] clauses = new int [n_cls][]; + for (int i=0; i< n_cls; ++i) + clauses[i] = randclause ( 1, n_vars + 1); + int [] qvars = new int [n_qvar]; + for (int i=1; i<= n_qvar; ++i) + qvars[i-1] = i + i; + + SATSolver solver = new SATSolver(); + solver.SetNumVariables(n_vars); + solver.ConvertVarsToPI(); + build_irregular_struct(solver, clauses, 1); + + int t = solver.GetOne(); + int f = solver.GetZero(); + int s1 = solver.And (t, 10); + int s2 = solver.And (f, 10); + int [] bounded = new int[2]; + bounded[0] = 2; + bounded[1] = 3; + int result = solver.EnumExistQuantify (s1, bounded); + result = solver.EnumExistQuantify (s2, bounded); + Console.WriteLine(result); + } + + public static void Main(string [] args) + { +// bool r = UnitTest(); +// sharp_assert (r == true); +// +// NetList net = new NetList(); +// net.read_blif(args[0]); +// net.write_blif(args[0] + ".out"); + +// test_clause_solver(args); +// return; +// Console.WriteLine("Test Clause and Structure Based Interpolant Generation"); +// for (int i=0; i< 100; ++i) +// { +// Console.Write ("Test {0}\tCLAUSE: ", i); +// r = test_interpolant_clauses (100, 200, 45, i) ; +// if (r == false) +// Console.Write ("*"); +// Console.Write("\t STURCT:"); +// r = test_interpolant_structure (100, 200, 45, i) ; +// if (r == false) +// Console.Write ("*"); +// Console.WriteLine(""); +// } +// for (int i=0 ; i < 100; ++i) +// { +// Console.WriteLine ("Test {0} ", i); +// test_existential_quantification(50, 30, 20, i); +// } +// test_small_model(); +// test_quantification_edge_case(); + test_clause_solver (args); + } + } +} diff --git a/base/Applications/Benchmarks/sharpSAT/sat_solver.cs b/base/Applications/Benchmarks/sharpSAT/sat_solver.cs new file mode 100644 index 0000000..6516d44 --- /dev/null +++ b/base/Applications/Benchmarks/sharpSAT/sat_solver.cs @@ -0,0 +1,376 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +/////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Collections; +using System.Text; +using System.IO; +//using Microsoft.Zap; +namespace SharpSAT +{ + //This class implements the C# interface for a SAT solver + public class SATSolver : SharpSATSolver + { + [Microsoft.Contracts.NotDelayed] + public SATSolver() {} + + /* + * This part is the conventional clause based SAT solver + * formula is represented in Conjunctive Normal Form (CNF) + * which is a conjunction of clauses, each of which is a + * disjunction of literals + * + * Variables are indexed from 1 up to NumVariables. + * The number of variables can be set upfront using + * SetNumVariables or dynamically increased in the + * solving process. */ + public double SessionCpuTime () { return base.session_cpu_time();} + + public double TotalCpuTime() { return base.total_cpu_time(); } + + + #region Managing Clause Database + + #region Managing Clause Groups + + public int AllocGID () { return base.alloc_gid(); } + + public void FreeGID (int gid) { base.free_gid(gid);} + + public int MergeGroup (int g1, int g2) { return base.merge_clause_group (g1, g2); } + + public void DeleteGroup (int gid) { base.delete_clause_group(gid); } + + #endregion + + public void SetNumVariables(int a) { base.set_num_variables(a); } + + public int GetNumVariables() { return base.num_variables(); } + + public int AddVariable() { return base.add_variable(); } + + public int AddClause( int[] lits, int gid, bool do_check) { return base.add_clause (lits, gid, do_check); } + + public int AddClause ( int[] lits ) { return base.add_clause (lits, 0, true /*check */); } + + public int AddClause (int[] lits, int gid) { return base.add_clause (lits, gid, true /*check */); } + + public int AddClauseNoCheck ( int[] lits ) { return base.add_clause (lits, 0, false /*check */); } + + public int AddClauseNoCheck ( int[] lits, int gid ) { return base.add_clause (lits, gid, false /*check */);} + #endregion + + #region Solving Instance + + public void SetBranchable(int vid) { base.set_branchable(vid, true); } + + public void UnsetBranchable(int vid) { base.set_branchable(vid, false); } + + public int VariableValue(int vid) { return base.var_value(vid); } + + public int LiteralValue(int lit) { int v = base.lit_value( lit ); return ((v&1) == v)? v: 2; } + + public SATStatus Solve() { return base.solve(); } + + public SATStatus ContinueSolve() { return base.solve(); } + + public void Reset() { base.reset(); } + + public void Restart() { base.restart();} + #endregion + + #region Unsat Core and Interpolants + //public void EnableTraceGen() { base.enable_rtrace(true); } + + //public void DisableProofGen() { base.enable_rtrace(false);} + + // return null if instance is SAT + public UnsatCore GenUnsatCore() { return base.gen_unsat_core(); } + + // return -1 if instance is SAT + public int GenInterpolantFromClauseGroups (int a_gid, int b_gid) + { return base.gen_interpolant_from_clauses(a_gid, b_gid); } + // return -1 if and(a,b) is SAT + public int GenInterpolantFromSignals ( int signal_a, int signal_b) + { + if (signal_a == zero() || signal_b == zero()) + throw new Exception("One of the Input is Zero for Interpolation"); + return base.gen_interpolant_from_signals(signal_a, signal_b); + } + + // gretay - change start + // return -1 if and(a,b) is SAT + public int GenInterpolantFromSignalsEx( int signal_a, int signal_b) + { + if (signal_a == zero() || signal_b == zero()) + throw new Exception("One of the Input is Zero for Interpolation"); + return base.gen_interpolant_from_signals_ex(signal_a, signal_b); + } + public void SetInterpolant(int cl_uid, int i) + { + base.set_interpolant(cl_uid, i); + } + // gretay - change end + + #endregion + + /* given two Boolean formulas represented by s1 and s2, return the logic formula + * corresponding to AND(s1,s2), OR(s1,s2)... etc + */ + public int Constraint (int s) { return base.constraint(s); } + + public void ReleaseConstraint(int c) { base.release_constraint(c); } + + #region Structure Interface + public int GetOne () { return base.one() ; } + + public int GetZero () { return base.zero(); } + + public int CreatePI() { return base.new_pi(); } + + public int NthPI(int n) { return base.nth_pi(n); } + + public void ConvertVarsToPI() { base.convert_vars_to_pi(); } + + public int And(int a, int b) { return base.band(a, b); } + + public int Or(int a, int b) { return base.bor(a, b); } + + public int Not(int a) { return base.bnot(a); } + + public int Xor(int a, int b) { return base.bxor(a, b); } + + public int Equ(int a, int b) { return base.bequ(a, b); } + + public int Imp(int a, int b) { return base.bimp(a, b); } + + public bool IsNegated(int s) { return IS_NEGATED(s); } + + public int NonNegated(int s) { return NON_NEGATED(s); } + + public void Reference(int a) { base.reference(a); } + + public void Deref(int a) { base.deref(a); } + + public int NumPI() { return base.num_pi(); } + + public int PiVarValue (int k) { return base.pi_var_value(k); } + + //note: start from 0, up to NumPI - 1 + public int PrimaryInput(int k) { return base.nth_pi(k); } + + public int LeftChild(int sig) { return base.left_child(sig); } + + public int RightChild(int sig) { return base.right_child(sig); } + + public NodeType NdType (int sig) { return base.node_type(sig); } + + public int NodeToPI (int sig) { return base.node_to_pi(sig); } + + public int AllocFlag () { return base.alloc_flag(); } + + public void ClearFlag(int flag_id) { base.clear_flag_for_all(flag_id); } + + public bool IsNodeFlagSet(int s, int flag_id) { return base.is_flag_set(s, flag_id); } + + /* orig[] and replace[] should have the same size. Given a Boolean formula + * represented by s, function compose will generate a new Boolean formula + * that rename all orig[i] to replace[i] in s. + */ + public int Compose (int s, int [] orig, int [] replace ) + { + return base.compose(s, orig, replace); + } + + /* Mark the transitive fanins and fanouts of a signal s. After marking + * nodes belong to the fanin/fanout set are marked for the flag. A node + * can be tested for whether it belongs to the set using IsNodeFlagSet() + */ + + public void MarkTransitiveFanins(int s, int flag) + { + base.mark_transitive_fanins(s, flag); + } + + public void MarkTransitiveOuts(int s, int flag) + { + base.mark_transitive_fanouts(s, flag); + } + #endregion + + #region TestSAT + //two examples of how to use the interface + + /* Test if logic formula represented by s is satisfiable (i.e. exist a + * primary inputs assignment such that s evaluate to true. + */ + + public SATStatus TestSAT (int s) + { + if (s == GetZero()) + return SATStatus.UNSATISFIABLE; + else if (s == GetOne()) + return SATStatus.SATISFIABLE; + + int c = Constraint(s); + SATStatus status = Solve(); + ReleaseConstraint (c); + return status; + } + + /* Test if logic formula represented by s is satisfiable. If it is, + * return the satisfiable primary input assignments, otherwise return + * null. Notice this function has about the same complexity as + * TestSAT(), so you should avoid calling testSAT first and then based + * on the result call FindSATAssignment. If you don't know whether s is + * satisfiable, call FindSatAssignment directly, and based on the return + * value you should know if s is satisfiable or not. + */ + public int[] FindSatAssignment (int s) + { + int[] pi_values = null; + + if (s == GetZero()) + return null; + else if (s == GetOne()) + { + pi_values = new int[NumPI()]; + for (int i=0; i< pi_values.Length; ++i) + pi_values[i] = 2; + return pi_values; + } + else + { + int c = Constraint(s); + SATStatus status = Solve(); + if (status == SATStatus.SATISFIABLE) + { + pi_values = new int[NumPI()]; + for (int i=0; i< NumPI(); ++i) + { + int l = LiteralValue(PrimaryInput(i)); + if (l != 0 && l != 1) + pi_values[i] = 2; + else + pi_values[i] = l; + } + } + ReleaseConstraint(c); + return pi_values; + } + } + #endregion + + public int DecisionLevel() { return d_level(); } + + public int [] AssignmentAtLevel(int l ) { return assignment_stack(l).ToArray(); } + + public ObjVector AssignmentStack() { return assignment_stack(); } + + public void MakeDecision (int svar) { base.make_decision(svar); } + + public void SetHookObject (SATHook hk) { base.hook = hk; } + + //(a & b & c => d) reasons[!a, !b, !c] imply=d + // reasons can be null + public void AddImplication (int [] reasons, int imply) { base.add_new_implication(reasons, imply); } + + public int EnumExistQuantify (int s, int [] bound) { return base.enum_exist_quantify_smart (s, bound); } + + public int [] FindSmallModel () { return base.find_small_model(); } + + #region ToString Methods + /* return the string representation of this particular node + */ + public string ToString (int sig, MyHashtable nameMap) + { + string result = sig.ToString() + "\t= "; + if (IsNegated(sig)) + { + int t = NonNegated(sig); + result += "Not(" + + t.ToString() + ")\n" + + ToString (t, nameMap); + } + else + { + NodeType tp = NdType(sig); + switch (tp) + { + case NodeType.UNKNOWN: + case NodeType.FREE: + case NodeType.CONSTANT: + case NodeType.VARIABLE: + result += "ERROR"; + break; + case NodeType.AND: + case NodeType.XOR: + int l = LeftChild(sig); + int r = RightChild(sig); + string lstr, rstr; + lstr = l.ToString(); + rstr = r.ToString(); + + if (tp == NodeType.AND) + result += "AND (" + lstr + ", " + rstr + ")"; + else + result += "XOR (" + lstr + ", " + rstr + ")"; + break; + case NodeType.PI: + int sig_pi = NodeToPI(sig); + if (sig_pi != -1) + { + if (nameMap.Contains(sig_pi)) + result += nameMap[sig_pi]; + else + result += "PI" + sig_pi.ToString(); + } + else + result += "ERROR"; + break; + } + result += "\n"; + } + return result; + } + + /* return the string representation of the whole + * tree rooted at this particular node + */ + public string TreeToString (int sig, MyHashtable nameMap) + { + MyHashtable inqueue = new MyHashtable(); + Queue todo = new Queue(); + todo.Enqueue (sig); + StringBuilder result = new StringBuilder(); + while (todo.Count != 0) + { + int nd = (int)todo.Dequeue(); + int l = LeftChild(nd); + int r = RightChild(nd); + NodeType tp = NdType(nd); + if (tp == NodeType.AND || tp == NodeType.XOR) + { + if (!inqueue.Contains(l)) + { + todo.Enqueue(l); + inqueue.Add (l, null); + } + if (!inqueue.Contains(r)) + { + todo.Enqueue(r); + inqueue.Add (r, null); + } + } + result.Append (ToString(nd, nameMap)); + } + return result.ToString(); + } + } + #endregion +} diff --git a/base/Applications/Benchmarks/sharpSAT/sharpSAT.csproj b/base/Applications/Benchmarks/sharpSAT/sharpSAT.csproj new file mode 100644 index 0000000..c200a52 --- /dev/null +++ b/base/Applications/Benchmarks/sharpSAT/sharpSAT.csproj @@ -0,0 +1,40 @@ + + + + + + + Exe + sharpsat + NONULLCHECK + + + + + + + + + + + + + + + + + + + + + + + diff --git a/base/Applications/Benchmarks/sharpSAT/sharp_stl.cs b/base/Applications/Benchmarks/sharpSAT/sharp_stl.cs new file mode 100644 index 0000000..d555666 --- /dev/null +++ b/base/Applications/Benchmarks/sharpSAT/sharp_stl.cs @@ -0,0 +1,230 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +/////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Collections; +using System.Diagnostics; +//using Microsoft.Zap; +namespace SharpSAT +{ + public class IntVector : SATCommon + { + private int [] elements; + private int numElements; + + [Microsoft.Contracts.NotDelayed] + public IntVector(int sz) + { + numElements = 0; + elements = new int[sz]; + } + + [Microsoft.Contracts.NotDelayed] + public IntVector (IntVector cp) + { + numElements = cp.numElements; + elements = new int[cp.elements.Length]; + Array.Copy(cp.elements, elements, numElements); + } + + public void sort () + { + Array.Sort(elements, null, 0, numElements); + } + public int binary_search(int v) + { + return Array.BinarySearch(elements,0,numElements,v); + } + + public void push_back(int v) + { + if (numElements == elements.Length) + { + int [] old = elements; + elements = new int [numElements + numElements]; + Array.Copy (old, elements, numElements); + } + elements[numElements] = v; + ++ numElements; + } + + public int[] ToArray() + { + int [] result = new int [numElements]; + Array.Copy(elements, result, numElements); + return result; + } + + public int this [int idx] + { + get {sharp_assert (idx < numElements); return elements[idx];} + set {sharp_assert (idx < numElements); elements[idx] = value;} + } + + public void clear() { numElements = 0; } + public void pop_back() { --numElements; } + public int size() { return numElements; } + public void resize (int k ) + { + int l = elements.Length; + while (k > l) + l += l; + if (l > elements.Length) + { + int [] old = elements; + elements = new int [l]; + Array.Copy (old, elements, numElements); + } + numElements = k; + return; + } + + public int back + { + get { return elements[numElements - 1]; } + set { elements[numElements - 1] = value; } + } + public bool empty() { return numElements == 0; } + } + + + public class ObjVector + { + private object [] elements; + private int numElements; + + public ObjVector(int n) + { + numElements = 0; + elements = new object [n]; + } + + public void push_back(object v) + { + if (numElements == elements.Length) + { + object [] old = elements; + elements = new object [numElements + numElements]; + Array.Copy (old, elements, numElements); + } + elements[numElements] = v; + ++ numElements; + } + + public object this [int idx] + { + get {return elements[idx];} + set {elements[idx] = value;} + } + + public void clear() + { + for (int i=0; i< numElements; ++i) + elements[i] = null; + numElements = 0; + } + public void pop_back() { elements[--numElements] = null; } + public int size() { return numElements; } + public object back + { + get {return elements[numElements - 1]; } + set { elements[numElements - 1] = value; } + } + public bool empty() { return numElements == 0; } + } + + public class ClsVector + { + private Clause [] elements; + private int numElements; + + public ClsVector(int n) + { + numElements = 0; + elements = new Clause [n]; + } + + public void push_back(Clause v) + { + if (numElements == elements.Length) + { + Clause [] old = elements; + elements = new Clause [numElements + numElements]; + Array.Copy (old, elements, numElements); + } + elements[numElements] = v; + ++ numElements; + } + + public Clause this [int idx] + { + get {return elements[idx];} + set {elements[idx] = value;} + } + + public void clear() + { + for (int i=0; i< numElements; ++i) + elements[i] = null; + numElements = 0; + } + public void pop_back() { elements[--numElements] = null; } + public int size() { return numElements; } + public Clause back + { + get {return elements[numElements - 1]; } + set { elements[numElements - 1] = value; } + } + public bool empty() { return numElements == 0; } + } + + public class VarVector + { + private Variable [] elements; + private int numElements; + + public VarVector(int n) + { + numElements = 0; + elements = new Variable [n]; + } + + public void push_back(Variable v) + { + if (numElements == elements.Length) + { + Variable [] old = elements; + elements = new Variable [numElements + numElements]; + Array.Copy (old, elements, numElements); + } + elements[numElements] = v; + ++ numElements; + } + + public Variable this [int idx] + { + get {return elements[idx];} + set {elements[idx] = value;} + } + + public void clear() + { + for (int i=0; i< numElements; ++i) + elements[i] = null; + numElements = 0; + } + public void pop_back() { elements[--numElements] = null; } + public int size() { return numElements; } + public Variable back + { + get {return elements[numElements - 1]; } + set { elements[numElements - 1] = value; } + } + public bool empty() { return numElements == 0; } + } +} diff --git a/base/Applications/CHello/CHello.csproj b/base/Applications/CHello/CHello.csproj new file mode 100644 index 0000000..63ef4a0 --- /dev/null +++ b/base/Applications/CHello/CHello.csproj @@ -0,0 +1,25 @@ + + + + + + + Exe + CHello + + + + + + + + + diff --git a/base/Applications/CHello/CHello.sg b/base/Applications/CHello/CHello.sg new file mode 100644 index 0000000..4af8025 --- /dev/null +++ b/base/Applications/CHello/CHello.sg @@ -0,0 +1,77 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: CHello.cs +// +// Note: Simple Singularity test program. +// +using System; +using System.Runtime.CompilerServices; +using System.Threading; + +using Microsoft.Singularity; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.V1.Services; +using Microsoft.Singularity.Io; + +namespace Microsoft.Singularity.Applications +{ + public class CHello + { + + public static ServiceContract.Imp OpenDevice(String! devname) + { + ServiceContract.Exp! exp; + ServiceContract.Imp! imp; + ServiceContract.NewChannel(out imp, out exp); + + // get NS endpoint + DirectoryServiceContract.Imp ns = DirectoryService.NewClientEndpoint(); + + bool success = false; + ns.SendBind(Bitter.FromString2(devname),exp); + switch receive + { + case ns.AckBind(): + Console.WriteLine("Received AckBind from namespace."); + success = true; + break; + case ns.NakBind(rejected, error): + delete rejected; + Console.WriteLine("Received NakLookup from namespace."); + break; + case ns.ChannelClosed(): + Console.WriteLine("Channel closed to nameserver."); + break; + } + + if (!success) + { + Console.WriteLine("Bind of {0} failed\n", devname); + delete imp; + delete ns; + return null; + } + + delete ns; + return imp; + } + + public static int Main(String[] args) + { + Console.WriteLine("Hello World!"); + + ServiceContract.Imp device = OpenDevice("/dev/disk0"); + if (device == null) { + Console.WriteLine("Couldn't open disk0"); + return 1; + } + delete device; + Console.WriteLine("Opened disk0"); + return 0; + } + } +} diff --git a/base/Applications/CHello2/CHello2.csproj b/base/Applications/CHello2/CHello2.csproj new file mode 100644 index 0000000..bd1b041 --- /dev/null +++ b/base/Applications/CHello2/CHello2.csproj @@ -0,0 +1,29 @@ + + + + + + + Exe + CHello2 + + + true + true + + + + + + + + + diff --git a/base/Applications/CHello2/CHello2.sg b/base/Applications/CHello2/CHello2.sg new file mode 100644 index 0000000..aec2237 --- /dev/null +++ b/base/Applications/CHello2/CHello2.sg @@ -0,0 +1,708 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: CHello.cs +// +// Note: Simple Singularity test program. +// +using System; +using System.Runtime.CompilerServices; +using System.Threading; + +using Microsoft.Singularity; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.V1.Services; +using Microsoft.Singularity.Io; + +namespace Microsoft.Singularity.Applications +{ + public class CHello + { + public static int Main(String[] args) + { + Console.WriteLine("Hello World!"); + + ProtocolTester.UnitTest_LDPC o = new ProtocolTester.UnitTest_LDPC(); + + o.Run(); + + return 0; + } + } +} + +namespace Microsoft.SPOT +{ + /// + public abstract class Trace + { + /// + [System.Diagnostics.ConditionalAttribute("TINYCLR_TRACE")] + static public void Print( string text ) + { + Debug.Print( text ); + } + } + + /// + public abstract class Debug + { + static public void Print( string text ) + { + Console.WriteLine( text ); + } + + static public void DumpBuffer( byte[] buf, bool fCRC, bool fOffset ) + { + if(buf == null) return; + + int offset = 0; + int len = buf.Length; + + while(len > 0) + { + int row = len > 16 ? 16 : len; + int i; + + if(fOffset) Console.Write( "{0:X8}:", offset ); + + for(i=0; i<16; i++) + { + if(i= 0x7F) c = (byte)'.'; + + Console.Write( "{0}", (char)c ); + } + + offset += row; + len -= row; + + Console.WriteLine(); + } + + Console.WriteLine(); + } + } + + public abstract class Math + { + static System.Random s_rnd = new System.Random(); + + static public int Random( int modulo ) + { + return s_rnd.Next( modulo ); + } + } +} + +namespace Microsoft.SPOT.Hardware +{ + public abstract class Radio + { + static public void XorData( byte[]! left, byte[]! right ) + { + for(int i=0; i + { + T[]! elements; + int count; + + public CreateNonNullArray( int n ) + { + this.elements = new T[n]; + this.count = 0; + base(); + } + + public void InitNext( T elem ) + { + if(this.count < elements.Length) + { + this.elements[this.count++] = elem; + } + else + { + throw new InvalidOperationException( "Too many elements initialized" ); + } + } + + public T[]! GetArray() + { + if(count != elements.Length) + { + throw new InvalidOperationException("Not all elements initialized"); + } + + return this.elements; + } + } + + public class LDPC + { + public static T[]![]! ConstructArray( int i, int j ) + { + CreateNonNullArray nna = new CreateNonNullArray( i ); + + for(int k=0; k < i; k++) + { + nna.InitNext( new T[j] ); + } + + return nna.GetArray(); + } + + static public byte[]![]! Solve( byte[][] dataPackets, byte[][] eccPackets, int[] eccIndex, int totalEccPackets, int totalDataPackets, int missedDataPackets, int receivedEccPackets, int pktLen ) + { + // dataPackets x0 = actual N - k data packets received (blanks in the missing locations) + // eccPackets rhs = actual kp EC packets received + // eccIndex gotec = array contains indices of EC packet received + // totalEccPackets M = total length of EC stream + // totalDataPackets N = total length of data stream + // missedDataPackets kk = number of data packets missed + // receivedEccPackets kp = number of EC packets received + // AA = M * N matrix used to get the EC packets at encoder + + if(dataPackets == null) throw new NullReferenceException(); + if(eccPackets == null) throw new NullReferenceException(); + if(eccIndex == null) throw new NullReferenceException(); + + int maxMN = (totalEccPackets > totalDataPackets) ? totalEccPackets : totalDataPackets; + bool[] pseudo = new bool[maxMN]; + int i; + int j; + int k; + + for(i=0; i < maxMN; i += 5) pseudo[i] = true; + for(i=0; i < maxMN; i += 7) pseudo[i] = true; + for(i=0; i < maxMN; i += 13) pseudo[i] = true; + for(i=0; i < maxMN; i += 17) pseudo[i] = true; + for(i=0; i < maxMN; i += 19) pseudo[i] = true; + for(i=0; i < maxMN; i += 33) pseudo[i] = true; + for(i=0; i < maxMN; i += 37) pseudo[i] = true; + + //bool[][] A = new bool[receivedEccPackets][]; + //for(i=0; i < receivedEccPackets; i++) + //{ + // A[i] = new bool[missedDataPackets]; + //} // The actual matrix to be inverted (submatrix of AA) + bool[]![]! A = ConstructArray( receivedEccPackets, missedDataPackets ); + + int[]! miss = new int[missedDataPackets + 1]; // Indices of the missing data packets + + int c = 0; + + for(i = 0; i < missedDataPackets; i++) + { + while(c < totalDataPackets && dataPackets[c] != null) + { + c++; + } + + //Microsoft.SPOT.Debug.Print( "Missing: " + c ); + miss[i] = c++; + } + // Get miss array + miss[missedDataPackets] = -1; + + for(i=0; i < receivedEccPackets; i++) + { + byte[] t = eccPackets[i]; if(t == null) throw new NullReferenceException(); + + t = (byte[])t.Clone(); if(t == null) throw new NullReferenceException(); + + eccPackets[i] = t; + + // What's the actual system we have to solve + + for(j=0; j < missedDataPackets; j++) + { + int idx = eccIndex[i] + miss[j]; + + //A[i][j] = AA[eccIndex[i]][miss[j]]; + A[i][j] = pseudo[ idx < maxMN ? idx : idx - maxMN ]; + } + } + + for(j = 0; j < totalDataPackets; j++) + { + byte[] dataPacket = dataPackets[j]; + + if(dataPacket != null) + { + // Packet j is not a missing packet + for(i = 0; i < receivedEccPackets; i++) + { + int idx = eccIndex[i] + j; + + if(pseudo[ idx < maxMN ? idx : idx - maxMN ]) /*AA[eccIndex[i]][j]*/ + { + //Microsoft.SPOT.Debug.Print( "XOR: eccPackets[" + i + "], dataPackets[" + j + "]" ); + byte[] eccPacket = eccPackets[i]; + + if(eccPacket != null) + { + Microsoft.SPOT.Hardware.Radio.XorData( eccPacket, dataPacket ); + } + } + } + } + } + + //DumpMatrix( "Beginning:", A, kp, kk ); + + // Now set up some variables and do the LU decomposition + + //byte[][] y = new byte[missedDataPackets+1][]; // Intermediate solution + //byte[][] xhat = new byte[missedDataPackets+1][]; + // + // + //for(i=0; i < missedDataPackets+1; i++) + //{ + // y [i] = new byte[ pktLen ]; + // xhat[i] = new byte[ pktLen ]; + //} + byte[]![]! y = ConstructArray( missedDataPackets+1, missedDataPackets+1 ); + byte[]![]! xhat = ConstructArray( missedDataPackets+1, missedDataPackets+1 ); + + int i2; + int j2; + int p; + + //DumpMatrix( "Beginning:", A, kp, kk ); + + for(k = 0; k < missedDataPackets; k++) + { + p = k; + + // Find a remaining row with non-zero k-th element + while(A[p][k] == false) + { + p++; + + if(p == receivedEccPackets) + { + //Microsoft.SPOT.Debug.Print( "Non-triangular matrix?" ); + //return null; + throw new Exception( "Non-triangular matrix?" ); + } + } + + + if(p != k) + { + //Microsoft.SPOT.Debug.Print( "Swap: " + p + " " + k ); + // Swap row k and row p + for(j2 = 0; j2 < missedDataPackets; j2++) + { + bool temp = A[k][j2]; + A[k][j2] = A[p][j2]; + A[p][j2] = temp; + } + + byte[] packetTemp = eccPackets[k]; + eccPackets[k] = eccPackets[p]; + eccPackets[p] = packetTemp; + + //DumpMatrix( "After:", A, kp, kk ); + } + + for(i2 = k + 1; i2 < receivedEccPackets; i2++) + { + if(A[i2][k] == A[k][k]) + { + //Microsoft.SPOT.Debug.Print( "Mix rows: " + i2 + " " + k ); + for(j2 = k + 1; j2 < missedDataPackets; j2++) + { + A[i2][j2] ^= A[k][j2]; + } + + //DumpMatrix( "After:", A, kp, kk ); + } + } + } + //DumpMatrix( "After:", A, kp, kk ); + + ////////////////////////////////////////////////////////// + + // Solve Ly = Pb + + for(i2 = 0; i2 < missedDataPackets; i2++) + { + y[i2] = (byte[]!)eccPackets[i2]; + + for(j2 = 0; j2 < i2; j2++) + { + //y[i2] = (sbyte) (((y[i2] ^ (A[i2][j2] * y[j2])) & 0x000000ff)); + + if(A[i2][j2]) + { + //Microsoft.SPOT.Debug.Print( "XOR: y[" + i2 + "], y[" + j2 + "]" ); + Microsoft.SPOT.Hardware.Radio.XorData( y[i2], y[j2] ); + } + } + } + + // Now solve Ux = y + for(i2 = missedDataPackets - 1; i2 >= 0; i2--) + { + xhat[i2] = y[i2]; + + for(j2 = i2 + 1; j2 < missedDataPackets; j2++) + { + //xhat[i2] = (sbyte) (((xhat[i2] ^ (A[i2][j2] * xhat[j2])) & 0x000000ff)); + if(A[i2][j2]) + { + //Microsoft.SPOT.Debug.Print( "XOR: xhat[" + i2 + "], xhat[" + j2 + "]" ); + Microsoft.SPOT.Hardware.Radio.XorData( xhat[i2], xhat[j2] ); + } + } + } + + for(i2 = 0; i2 < missedDataPackets; i2++) + { + // Rogue value to indicate non-invertible + if(A[i2][i2] == false) + { + //return null; + throw new Exception( "Non-invertible matrix?" ); + } + } + + return xhat; + } + + static public byte[][] GenerateEC( byte[][] dataPackets, int totalEccPackets, int totalDataPackets, int pktLen ) + { + int maxMN = (totalEccPackets > totalDataPackets) ? totalEccPackets : totalDataPackets; + int i; + int j; + + if(dataPackets == null) throw new NullReferenceException(); + + bool[] pseudo = new bool[maxMN]; + + for(i=0; i < maxMN; i += 5) pseudo[i] = true; + for(i=0; i < maxMN; i += 7) pseudo[i] = true; + for(i=0; i < maxMN; i += 13) pseudo[i] = true; + for(i=0; i < maxMN; i += 17) pseudo[i] = true; + for(i=0; i < maxMN; i += 19) pseudo[i] = true; + for(i=0; i < maxMN; i += 33) pseudo[i] = true; + for(i=0; i < maxMN; i += 37) pseudo[i] = true; + + byte[][] eccPackets = new byte[totalEccPackets][]; + + for(i=0; i < totalEccPackets; i++) + { + eccPackets[i] = new byte[ pktLen ]; + } + + for(i=0; i < totalEccPackets; i++) + { + // Generate the EC stream + + for(j=0; j < totalDataPackets; j++) + { + //ec[i] = (sbyte) (((ec[i] ^ (AA[i][j] * x[j])) & 0x000000ff)); + + int idx = i + j; + + if(pseudo[ idx < maxMN ? idx : idx - maxMN ]) /*AA[i][j]*/ + { + byte[] eccPacket = eccPackets[i]; + byte[] dataPacket = dataPackets[j]; + + if(eccPacket != null && dataPacket != null) + { + Microsoft.SPOT.Hardware.Radio.XorData( eccPacket, dataPacket ); + } + } + } + } + + return eccPackets; + } + } +} + +namespace ProtocolTester +{ + public class UnitTest_LDPC + { + // main program written by hpleung + // Procedure: + // 1. Generate Random Data Unit + // 2. Generate Error Correction Unit + // 3. Inject Errors in The Random Data Unit + // 4. Decode + // 5. Make sure after decoding data is fully received + // Run it with run.exe nDataPacket nErrorCorrection nPercentageLoss nIteration + // + public void Run() + { + //for quick correctness verification + Microsoft.SPOT.Debug.Print( "LPDC Test Started" ); + +// for(int i=0; i<100; i++) +// { +// RunPass( 40, 40, 40, 106 ); +// } +// return; + for(int nPacketLength=10; nPacketLength <= 120; nPacketLength = nPacketLength + 10) + { + RunPass( nPacketLength, nPacketLength, 40, 106 ); + } + } + + public void RunPass( int nDataPacketCount, int nErrorCorrectionCount, int nPercentageLoss, int nPacketSize ) + { + byte[][] arrDataPacket = new byte[nDataPacketCount][]; + byte[][] arrDataReceived = new byte[nDataPacketCount][]; + byte[][] arrErrorCorrectionStream = null; + int nDataLossCount = 0; + int i; + + //randomly generate some data + PopulatePacket( arrDataPacket, nPacketSize ); + + for(i=0; i= nPacketToLossFix) + { + arrDataReceived[i] = arrDataPacket[i]; + } + else + { + arrDataReceived[i] = null; + } + } +#else + int nPacketToGet = nDataPacketCount - nPacketToLossFix; + while(nPacketToGet > 0) + { + i = Microsoft.SPOT.Math.Random( nDataPacketCount - 1 ); + //Microsoft.SPOT.Debug.Print( "Picked " + i ); + + if(arrDataReceived[i] == null) + { + arrDataReceived[i] = arrDataPacket[i]; + nPacketToGet--; + } + } +#endif + + for(i=0; i (nDataLossCount + 5) * 100) + { + nErrorPacketToReceive = (int)((nDataLossCount * 108)/100) ; + } + else + { + nErrorPacketToReceive = nDataLossCount + 5; + } + + if(nErrorPacketToReceive > nErrorCorrectionCount) + { + nErrorPacketToReceive = nErrorCorrectionCount; + } + + int[]! arrECPacketReceived = new int [nErrorPacketToReceive]; + byte[][] arrRHS = new byte[nErrorPacketToReceive][]; + + // Randomly Pick up Error Packets + for(i=0; i + + + + + + Exe + Cadgen99 + true + + + + + + + + + + + diff --git a/base/Applications/Cadgen99/cadgen99.sg b/base/Applications/Cadgen99/cadgen99.sg new file mode 100644 index 0000000..cf297c4 --- /dev/null +++ b/base/Applications/Cadgen99/cadgen99.sg @@ -0,0 +1,411 @@ + + +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: cadgen.sg +// +// Note: +// Ported literally SpecWeb99 source code. +// +// Strongly avoid writing programs like this. +// +// This file compiles under CSC for testing on Windows and SGC +// on Singularity. + + +using System; +using System.IO; + + +using FileSystem.Utils; +using Microsoft.SingSharp; +using Microsoft.SingSharp.Runtime; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using System.Text; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications +{ + [ConsoleCategory(HelpMessage="Generate the custom ads file for SPECWeb99", DefaultAction=true)] + internal class Parameters + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [StringParameter( "d", Mandatory=true, HelpMessage="Directory in which to gen files")] + internal string directory; + + [LongParameter( "e", Mandatory=true, HelpMessage="pttime")] + internal long pttime; + + [LongParameter( "t", Mandatory=true, HelpMessage="max number of threads")] + internal long maxthread; + + [LongParameter( "exp1", Mandatory=true, HelpMessage="expiredAd1")] + internal long expiredAd1; + + [LongParameter( "exp2", Mandatory=true, HelpMessage="expiredAd2")] + internal long expiredAd2; + + reflective internal Parameters(); + + internal int AppMain() { + CadGen99.AppMain(this); + return 0; + } + } + + +/////////////////////////////////////// +// Quick and dirty abstraction of file operations +////////////////////////////////////// + +public class FILE +{ + private TRef! connRef; + private long filePos; + private string! path; + + public static FILE CreateFile(string! path) + { + if (FileUtils.CreateFile(path) != 0) { + return null; + } + + return OpenFile(path); + } + + public static FILE OpenFile(string! path) + { + FileContract.Imp conn = FileUtils.OpenFile(path); + + if (conn != null) { + return new FILE(conn, path); + } + else { + return null; + } + } + + private FILE([Claims] FileContract.Imp:Ready! conn, string! thePath) + { + connRef = new TRef(conn); + filePos = 0; + path = thePath; + base(); + } + + public int Write(string! str) + { + byte[] bytes = Encoding.ASCII.GetBytes(str); + return Write(bytes, 0, bytes.Length); + } + + public int Write(byte[]! buf, int offset, int length) + { + FileContract.Imp conn = connRef.Acquire(); + byte[]! in ExHeap bytes = Bitter.FromByteArray(buf, offset, length); + + try { + long bytesWritten; + int error; + conn.SendWrite(bytes, 0, filePos, bytes.Length); + conn.RecvAckWrite(out bytes, out bytesWritten, out error); + delete bytes; + filePos += bytesWritten; + + if (error != 0) { + return 0; + } + } + finally { + connRef.Release(conn); + } + + return buf.Length; + } + + public int Read(byte[]! buf, int offset, int maxLength) + { + FileContract.Imp conn = connRef.Acquire(); + byte[]! in ExHeap bytes = new[ExHeap] byte[maxLength]; + + try { + long bytesRead; + int error; + conn.SendRead(bytes, 0, filePos, bytes.Length); + conn.RecvAckRead(out bytes, out bytesRead, out error); + + filePos += bytesRead; + + if (error != 0) { + delete bytes; + return 0; + } + + Bitter.ToByteArray(bytes, 0, maxLength, buf, offset); + delete bytes; + } + finally { + connRef.Release(conn); + } + + return buf.Length; + } + + public int Size + { + // TODO + get { + long size; + NodeType nodeType; + ErrorCode error; + DirectoryServiceContract.Imp! rootNS = DirectoryService.NewClientEndpoint(); + bool ok = FileUtils.GetAttributes(path, rootNS, out size, out nodeType, out error); + delete rootNS; + + if (!ok) { + throw new Exception("Failed to get attributes"); + } else { + return unchecked((int)size); + } + } + } + + public void Close() + { + FileContract.Imp conn = connRef.Acquire(); + + try { + conn.SendClose(); + } + finally { + connRef.Release(conn); + } + } +} + + +public class CadGen99 +{ + // Constants from client.h + private const int CAD_SEARCH_INTERVAL = 24; + private const int CADFILE_ENTRIES = 360; + private const int MAX_CAD_WEIGHT = 75; + + private const string AdsFile = "Custom.Ads"; + + private static void Usage() + { + Console.WriteLine("cadgen99 -C -e -t "); + Console.WriteLine("All arguments are mandatory."); + Console.WriteLine("Expired ads beyond 1 and 2 can be supplied but are ignored per SpecWeb source."); + Console.WriteLine("Output written to: /{0}", AdsFile); + Console.WriteLine("NB better exist."); + } + + internal static void AppMain(Parameters! config) + { + + string! directory; + int pttime = 0; + int maxthread = 0; + + int [] expired = new int[2]; + + pttime = (int) config.pttime; + maxthread = (int) config.maxthread; + expired[0] = (int) config.expiredAd1; + expired[1] = (int) config.expiredAd2; + directory = config.directory; + + if (pttime == 0) { + pttime = 1800; + } + + // XXX : cadgen99 uses time(...) which is time in seconds + // since since January 1, 1970. DateTime(1970, 1, 1). + + TimeSpan delta1970 = DateTime.Now - new DateTime(1970, 1, 1); + int ts = ((int)delta1970.TotalSeconds) + (pttime * 2); + int exp_ts = ts - 31622400; + + int [] demographic = new int [CADFILE_ENTRIES]; + int [] weight = new int [CADFILE_ENTRIES]; + int [] minmatch = new int [CADFILE_ENTRIES]; + int [] expired_date = new int [CADFILE_ENTRIES]; + + // + // Cut-and-paste from cadgen99.c with minor edits + // (in-place type declarations and commenting out unused variables) + // + int my_n = CAD_SEARCH_INTERVAL; + int match1 = (maxthread + CAD_SEARCH_INTERVAL) % my_n; + + int j; + int i; + for (j = 0; j> 4) & 0xf; + int c2 = (k >> 8) & 0xf; + // int c1 = (k >> 12) & 0xf; // XXX not used in test + + int gender = (k) % 2; + if ( gender == 1 ) gender = 0x20000000; + else gender = 0x10000000; + + int age = (k) % 4; + if ( age == 0 ) age = 0x08000000; + else if ( age == 1 ) age = 0x04000000; + else if ( age == 2 ) age = 0x02000000; + else if ( age == 3 ) age = 0x01000000; + + int area = (c4 + c2) % 4; + if ( area == 0 ) area = 0x00800000; + else if ( area == 1 ) area = 0x00400000; + else if ( area == 2 ) area = 0x00200000; + else if ( area == 3 ) area = 0x00100000; + + int interest1 = (c4 + c3) % 10; + if (interest1 == 0) interest1 = 0x00080000; + if (interest1 == 1) interest1 = 0x00040000; + if (interest1 == 2) interest1 = 0x00020000; + if (interest1 == 3) interest1 = 0x00010000; + if (interest1 == 4) interest1 = 0x00008000; + if (interest1 == 5) interest1 = 0x00004000; + if (interest1 == 6) interest1 = 0x00002000; + if (interest1 == 7) interest1 = 0x00001000; + if (interest1 == 8) interest1 = 0x00000800; + if (interest1 == 9) interest1 = 0x00000400; + + + int interest2 = c4 % 10; + if (interest2 == 0) interest2 = 0x00000200; + else if (interest2 == 1) interest2 = 0x00000100; + else if (interest2 == 2) interest2 = 0x00000080; + else if (interest2 == 3) interest2 = 0x00000040; + else if (interest2 == 4) interest2 = 0x00000010; + else if (interest2 == 5) interest2 = 0x00000020; + else if (interest2 == 6) interest2 = 0x00000008; + else if (interest2 == 7) interest2 = 0x00000004; + else if (interest2 == 8) interest2 = 0x00000002; + else if (interest2 == 9) interest2 = 0x00000001; + + int combined = gender | age | area | interest1 | interest2; + int wts=k*k; + wts = wts % 1048576; + if (wts == 0) wts = 0x27104; + int match = MAX_CAD_WEIGHT; + + demographic[j] = combined; + weight[j] = wts; + minmatch[j] = match; + expired_date[j] = ts; + } + + for (j=0; j < CADFILE_ENTRIES; j++) { + if (j == match1) { + minmatch[j] = 1; + weight[j] = 0x3ffff; + demographic[j] = demographic[j] | 0x3ff; + match1 = match1 + my_n; + } + } + + /* Mark two ranges as expired */ + j = expired[0]; + for (i=0; i CADFILE_ENTRIES - 1) + expired_date[j-CADFILE_ENTRIES] = exp_ts; + else + expired_date[j] = exp_ts; + j = j+1; + } + j = expired[1]; + for (i=0; i CADFILE_ENTRIES - 1) + expired_date[j-CADFILE_ENTRIES] = exp_ts; + else + expired_date[j] = exp_ts; + j = j+1; + } + + GenerateOutput(directory, demographic, weight, minmatch, expired_date); + } + +#if SINGULARITY + + private static void GenerateOutput(string /*!*/ directory, + int [] /*!*/ demographic, + int [] /*!*/ weight, + int [] /*!*/ minmatch, + int [] /*!*/ expired_date) + { + FILE fp; + + string path; + if (directory == "") { + path = AdsFile; + } + else if (directory[directory.Length - 1] == '/') { + path = directory + AdsFile; + } + else { + path = directory + "/" + AdsFile; + } + + fp = FILE.CreateFile(path); + if (fp == null) { + Console.WriteLine("Can't open file \"" + path + "\""); + return; + } + + for (int j = 0; j < CADFILE_ENTRIES; j++) { + fp.Write( + String.Format("{0,5:d} {1,8:X} {2,8:X} {3,3:d} {4,10:d}\n", + j, demographic[j], weight[j], + minmatch[j], expired_date[j]) + ); + } + fp.Close(); + } + +#else + + private static void GenerateOutput(string directory, + int [] demographic, + int [] weight, + int [] minmatch, + int [] expired_date) + { + for (int j = 0; j < CADFILE_ENTRIES; j++) { + Console.WriteLine("{0,5:d} {1,8:X} {2,8:X} {3,3:d} {4,10:d}", + j, demographic[j], weight[j], + minmatch[j], expired_date[j]); + } + } + +#endif + +} + +#if SINGULARITY +} +#endif diff --git a/base/Applications/ChildPing/ChildPing.csproj b/base/Applications/ChildPing/ChildPing.csproj new file mode 100644 index 0000000..2dc2914 --- /dev/null +++ b/base/Applications/ChildPing/ChildPing.csproj @@ -0,0 +1,31 @@ + + + + + + + Exe + ChildPing + + + + + + + + + + + + + diff --git a/base/Applications/ChildPing/ChildPing.sg b/base/Applications/ChildPing/ChildPing.sg new file mode 100644 index 0000000..f0846a9 --- /dev/null +++ b/base/Applications/ChildPing/ChildPing.sg @@ -0,0 +1,96 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: ChildPing.sg +// +// Note: Simple ping-pong test child app #1 +// + +using Microsoft.SingSharp; +using Microsoft.SingSharp.Runtime; +using Microsoft.Singularity; +using Microsoft.Singularity.Diagnostics.Contracts; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.PingPong.Contracts; +using System; +using System.Diagnostics; + +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +[assembly: Transform(typeof(WebAppResourceTransform))] + +namespace Microsoft.Singularity.PingPong +{ + [Category("PingPong")] + internal sealed class Parameters + { + [Endpoint] + public readonly TRef pingRef; + + reflective private Parameters(); + + } + + public class ChildPing + { + internal static int AppMain(Parameters! config) + { + PingContract.Exp conn = ((!)config.pingRef).Acquire(); + if (conn == null) { + throw new Exception("ChildPing: Unable to acquire handle to the the Ping Contract"); + } + +#if false + Endpoint * in ExHeap ep = Process.GetStartupEndpoint(0); + PingContract.Exp conn = ep as PingContract.Exp; + if (conn == null) { + // Wrong contract type! + delete ep; + return; + } +#endif + // Start up and connect to the ChildPong image! + PongContract.Imp! childImp; + PongContract.Exp! childExp; + PongContract.NewChannel(out childImp, out childExp); + + string[] args = new string[1]; + args[0] = "ChildPong.x86"; + Process child = new Process(args, (Endpoint * in ExHeap)childExp); + child.Start(); + + childImp.RecvPongReady(); + conn.SendPingReady(); + + try { + while (true) { + switch receive { + case conn.StartPingPong(int numReps) : + for (int i = 0; i < numReps; ++i) { + int data; + childImp.SendPing(42); + childImp.RecvPong(out data); + } + + conn.SendDone(); + break; + + case conn.ChannelClosed(): + return -1; + } + } + } + finally { + delete conn; + delete childImp; + } + return 0; + } + } +} diff --git a/base/Applications/ChildPong/ChildPong.csproj b/base/Applications/ChildPong/ChildPong.csproj new file mode 100644 index 0000000..bd474c0 --- /dev/null +++ b/base/Applications/ChildPong/ChildPong.csproj @@ -0,0 +1,31 @@ + + + + + + + Exe + ChildPong + + + + + + + + + + + + + diff --git a/base/Applications/ChildPong/ChildPong.sg b/base/Applications/ChildPong/ChildPong.sg new file mode 100644 index 0000000..2af2bee --- /dev/null +++ b/base/Applications/ChildPong/ChildPong.sg @@ -0,0 +1,77 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: ChildPong.sg +// +// Note: Simple ping-pong second child process +// + +using Microsoft.SingSharp; +using Microsoft.SingSharp.Runtime; +using Microsoft.Singularity; +using Microsoft.Singularity.Diagnostics.Contracts; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.PingPong.Contracts; +using System; +using System.Diagnostics; + +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +[assembly: Transform(typeof(WebAppResourceTransform))] + +namespace Microsoft.Singularity.PingPong +{ + [Category("PingPong")] + internal sealed class Parameters + { + [Endpoint] + public readonly TRef pongRef; + + reflective private Parameters(); + + } + + public class ChildPong + { + internal static int AppMain(Parameters! config) + { + PongContract.Exp conn = ((!)config.pongRef).Acquire(); + if (conn == null) { + throw new Exception("ChildPing: Unable to acquire handle to the the Pong Contract"); + } +#if false + Endpoint * in ExHeap ep = Process.GetStartupEndpoint(0); + PongContract.Exp conn = ep as PongContract.Exp; + if (conn == null) { + // Wrong contract type! + delete ep; + return; + } +#endif + conn.SendPongReady(); + + try { + while(true) { + switch receive { + case conn.Ping(int data): + conn.SendPong(data); + break; + + case conn.ChannelClosed(): + return -1; + } + } + } + finally { + delete conn; + } + return 0; + } + } +} diff --git a/base/Applications/Contracts/Counter.Contracts/Counter.Contracts.csproj b/base/Applications/Contracts/Counter.Contracts/Counter.Contracts.csproj new file mode 100644 index 0000000..89e2d72 --- /dev/null +++ b/base/Applications/Contracts/Counter.Contracts/Counter.Contracts.csproj @@ -0,0 +1,32 @@ + + + + + + + Library + Counter.Contracts + + + + + + + + + + + + + + diff --git a/base/Applications/Contracts/Counter.Contracts/CounterContract.sg b/base/Applications/Contracts/Counter.Contracts/CounterContract.sg new file mode 100644 index 0000000..abfac1e --- /dev/null +++ b/base/Applications/Contracts/Counter.Contracts/CounterContract.sg @@ -0,0 +1,57 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Contracts\Test.Contracts\CounterContract.sg +// +// Note: +// +using System; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.ServiceManager; + +namespace Microsoft.Singularity.Services +{ + contract CounterContract : ServiceContract + { + public const string ModuleName = "/Counter"; + + out message Success(); + + in message Increment(); + out message AckIncrement(int num); + out message NakIncrement(); + + in message BeginCount(); + out message Current(int num); + in message Next(); + in message End(); + out message Terminated(); + + override state Start : one { + Success! -> Ready; + } + + state Ready : one { + Increment? -> (AckIncrement! + or NakIncrement! + ) -> Ready; + + BeginCount? -> Count; + } + + state Count : one { + Current! -> AckCount; + Terminated! -> Ready; + } + + state AckCount : one { + Next? -> Count; + End? -> Ready; + } + } +} diff --git a/base/Applications/CredentialsControl/CredentialsControl.csproj b/base/Applications/CredentialsControl/CredentialsControl.csproj new file mode 100644 index 0000000..5cdaf56 --- /dev/null +++ b/base/Applications/CredentialsControl/CredentialsControl.csproj @@ -0,0 +1,32 @@ + + + + + + + Exe + cred + true + + + + + + + + + + + + + + + diff --git a/base/Applications/CredentialsControl/CredentialsControl.sg b/base/Applications/CredentialsControl/CredentialsControl.sg new file mode 100644 index 0000000..cd13566 --- /dev/null +++ b/base/Applications/CredentialsControl/CredentialsControl.sg @@ -0,0 +1,512 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Applications/CredentialsControl/CredentialsControl.sg +// +// Note: Command-line tool for controlling the Credentials Manager Service. +// + +using System; +using System.Collections; +using System.Diagnostics; +using Microsoft.Contracts; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +using Microsoft.SingSharp; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Security; + +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications +{ + + [ConsoleCategory(DefaultAction=true)] + internal class DefaultCommand + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal DefaultCommand(); + + internal int AppMain() + { + Console.WriteLine("Use -? for a list of commands."); + return 0; + } + } + + [ConsoleCategory(Action="add", HelpMessage="Adds credentials (user id and password) to the credentials store.")] + internal class AddCredentialsCommand + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal AddCredentialsCommand(); + + [BoolParameter("replace", Mandatory=false, HelpMessage="If specified, will replace existing credentials with the same name.", Default=true)] + public bool ReplaceExistingCredentials; + + [StringParameter("username", Mandatory=true, Position=0, HelpMessage="The [domain\\]username of the credentials.")] + public string UserName; + + [StringParameter("password", Mandatory=true, Position=1, HelpMessage="The password for this account.")] + public string Password; + + [StringParameter("tag", Mandatory=false, HelpMessage="A tag that can be used to distinguish different instances of the same account name.")] + public string Tag; + + [BoolParameter("default", Mandatory=false, HelpMessage="If specified, then the credentials will be registered as the default credentials.", Default=true)] + public bool AddDefaultProtocolMapping; + + internal int AppMain() + { + try + { + assert this.UserName != null; + assert this.Password != null; + + if (this.Tag == null) + this.Tag = ""; + + CredentialsManager.AddCredentials(this.UserName, this.Tag, this.Password, this.ReplaceExistingCredentials); + Console.WriteLine("Credentials successfully added to credentials store."); + + const string Wildcard = "*"; + + if (this.AddDefaultProtocolMapping) + { + CredentialsManager.AddProtocolMapping( + Wildcard, + Wildcard, + Wildcard, + Wildcard, + this.UserName, + this.Tag, + true); + Console.WriteLine("Default protocol mapping added."); + } + + return 0; + + } catch (Exception! ex) { + Util.ShowException(ex); + return -1; + } + } + } + + [ConsoleCategory(Action="del", HelpMessage="Deletes credentials from the credentials store.")] + internal class DeleteCredentialsCommand + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal DeleteCredentialsCommand(); + + [StringParameter("username", Mandatory=true, Position=0, HelpMessage="The [domain\\]username of the credentials.")] + public string UserName; + + [StringParameter("tag", Mandatory=false, HelpMessage="A tag that can be used to distinguish different instances of the same account name.")] + public string Tag; + + internal int AppMain() + { + try { + assert this.UserName != null; + + if (this.Tag == null) + this.Tag = ""; + + CredentialsManager.DeleteCredentials(this.UserName, this.Tag); + Console.WriteLine("Credentials deleted."); + return 0; + + } catch (Exception ex) { + Util.ShowException(ex); + return -1; + } + } + } + + [ConsoleCategory(Action="delall", HelpMessage="Deletes all credentials from the credentials store.")] + internal class DeleteAllCredentialsCommand + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal DeleteAllCredentialsCommand(); + + internal int AppMain() + { + try { + + CredentialsManager.DeleteAllCredentials(); + Console.WriteLine("All credentials deleted."); + return 0; + + } catch (Exception ex) { + Util.ShowException(ex); + return -1; + } + } + } + + + [ConsoleCategory(Action="list", HelpMessage="Shows a list of the credentials in the credentials store.")] + internal class ListCredentialsCommand + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal ListCredentialsCommand(); + + internal int AppMain() + { + try { + + CredentialsManagerContract.Imp! manager = CredentialsManager.ConnectService(); + try { + + manager.SendEnumerateCredentials(); + + switch receive { + case manager.CredentialsList(list): + + if (list.Length == 0) { + Console.WriteLine("No entries in credentials store."); + } else { + + const string format = "{0,-20} {1,-20}"; + + Console.WriteLine(format, "User name", "Tag"); + Console.WriteLine(format, "=========", "==="); + + for (int i = 0; i < list.Length; i++) { + expose(list[i]) { + string! username = Bitter.ToString2(list[i].CredentialsName); + string! tag = Bitter.ToString2(list[i].Tag); + Console.WriteLine(format, username, tag); + } + } + } + + delete list; + return 0; + + case manager.RequestFailed(error): + Util.ShowCredError(error); + return 1; + } + } finally { + delete manager; + } + + } catch (Exception ex) { + Util.ShowException(ex); + return -1; + } + } + } + + [ConsoleCategory(Action="addmap", HelpMessage="Add a mapping from a protocol tuple to credentials.")] + internal class AddProtocolMappingCommand + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal AddProtocolMappingCommand(); + + [StringParameter("app", HelpMessage="The application protocol, such as 'smb' or 'http'.", Mandatory=true, Position=0)] + string ApplicationProtocol; + + [StringParameter("service", HelpMessage="The remote service name, such as 'fooserver.example.com' or '192.168.0.1',", Mandatory=false, Position=1)] + string ServiceAddress; + + [StringParameter("authp", HelpMessage="The authentication protocol, such as 'ntlm'.", Mandatory=true, Position=2)] + string AuthenticationProtocol; + + [StringParameter("realm", HelpMessage="The authentication realm, such as 'yourdomain'.", Mandatory=true, Position=3)] + string Realm; + + [StringParameter("username", HelpMessage="The username (credentials name) to map to.", Mandatory=true, Position=4)] + string CredentialsName; + + [StringParameter("tag", HelpMessage="The credentials tag, which can be used to disambiguate between credentials with the same name.", Mandatory=false, Position=5, Default="")] + string Tag; + + [BoolParameter("replace", HelpMessage="If specified, then any existing entry will be replaced.", Default=true)] + bool ReplaceExistingEntry; + + internal int AppMain() + { + try { + + CredentialsManager.AddProtocolMapping( + this.ApplicationProtocol, + this.ServiceAddress, + this.AuthenticationProtocol, + this.Realm, + this.CredentialsName, + this.Tag, + this.ReplaceExistingEntry); + Console.WriteLine("The protocol mapping has been added."); + return 0; + + } catch (Exception ex) { + Util.ShowException(ex); + return -1; + } + } + } + + [ConsoleCategory(Action="delmap", HelpMessage="Delete a mapping from a protocol tuple to credentials.")] + internal class DeleteProtocolMappingCommand + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal DeleteProtocolMappingCommand(); + + [StringParameter("app", HelpMessage="The application protocol, such as 'smb' or 'http'.", Mandatory=true, Position=0)] + string ApplicationProtocol; + + [StringParameter("service", HelpMessage="The remote service name, such as 'fooserver.example.com' or '192.168.0.1',", Mandatory=false, Position=1)] + string ServiceAddress; + + [StringParameter("authp", HelpMessage="The authentication protocol, such as 'ntlm'.", Mandatory=true, Position=2)] + string AuthenticationProtocol; + + [StringParameter("realm", HelpMessage="The authentication realm, such as 'yourdomain'.", Mandatory=true, Position=3)] + string Realm; + + internal int AppMain() + { + try { + + CredentialsManager.DeleteProtocolMapping( + this.ApplicationProtocol, + this.ServiceAddress, + this.AuthenticationProtocol, + this.Realm); + Console.WriteLine("The protocol mapping has been deleted."); + return 0; + + } catch (Exception ex) { + Util.ShowException(ex); + return -1; + } + } + } + + [ConsoleCategory(Action="delmapall", HelpMessage="Delete all protocol mappings.")] + internal class DeleteAllProtocolMappingsCommand + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal DeleteAllProtocolMappingsCommand(); + + internal int AppMain() + { + try { + + CredentialsManager.DeleteAllProtocolMappings(); + Console.WriteLine("All protocol mappings have been deleted."); + return 0; + + } catch (Exception ex) { + Util.ShowException(ex); + return -1; + } + } + } + + [ConsoleCategory(Action="listmap", HelpMessage="Shows a list of all protocol mappings.")] + internal class ListProtocolMappingsCommand + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal ListProtocolMappingsCommand(); + + internal int AppMain() + { + try { + + CredentialsManagerContract.Imp! manager = CredentialsManager.ConnectService(); + try { + + manager.SendEnumerateProtocolMappings(); + + switch receive { + + case manager.ProtocolMappings(list): + Console.WriteLine("Protocol mappings:"); + + const string format = "{0,-10} {1,-10} {2,-10} {3,-10} {4,-10} {5,-10}"; + + Console.WriteLine(format, "App Prot.", "Service", "Auth Prot.", "Realm", "Credentials", "Tag"); + Console.WriteLine(format, "=========", "=======", "==========", "=====", "===========", "==="); + + for (int i = 0; i < list.Length; i++) { + string! applicationProtocol; + string! serviceName; + string! authenticationProtocol; + string! realm; + string! credentialsName; + string! tag; + + expose(list[i]) { + // expose(list[i].ProtocolTuple) { + applicationProtocol = Bitter.ToString2(list[i].ProtocolTuple.ApplicationProtocol); + serviceName = Bitter.ToString2(list[i].ProtocolTuple.ServiceAddress); + authenticationProtocol = Bitter.ToString2(list[i].ProtocolTuple.AuthenticationProtocol); + realm = Bitter.ToString2(list[i].ProtocolTuple.Realm); + // } + // expose(list[i].CredentialsId) { + credentialsName = Bitter.ToString2(list[i].CredentialsId.CredentialsName); + tag = Bitter.ToString2(list[i].CredentialsId.Tag); + // } + } + + Console.WriteLine(format, + applicationProtocol, + serviceName, + authenticationProtocol, + realm, + credentialsName, + tag); + } + + delete list; + + return 0; + + case manager.RequestFailed(error): + Util.ShowCredError(error); + return 1; + } + + + + } finally { + delete manager; + } + } catch (Exception ex) { + Util.ShowException(ex); + return -1; + } + } + } + + [ConsoleCategory(Action="testmap", HelpMessage="Test a protocol mapping. Specify a protocol tuple, and the command will show you which credentials would be selected.")] + internal class TestProtocolMappingCommand + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [StringParameter("app", HelpMessage="The application protocol, such as 'smb' or 'http'.", Mandatory=true, Position=0)] + string ApplicationProtocol; + + [StringParameter("service", HelpMessage="The remote service name, such as 'fooserver.example.com' or '192.168.0.1',", Mandatory=true, Position=1)] + string ServiceAddress; + + [StringParameter("authp", HelpMessage="The authentication protocol, such as 'ntlm'.", Mandatory=true, Position=2)] + string AuthenticationProtocol; + + [StringParameter("realm", HelpMessage="The authentication realm, such as 'yourdomain'.", Mandatory=true, Position=3)] + string Realm; + + reflective internal TestProtocolMappingCommand(); + + internal int AppMain() + { + try { + + string! credentialsName; + string! tag; + + Console.WriteLine("Checking:"); + Console.WriteLine(" Application Protocol = " + this.ApplicationProtocol); + Console.WriteLine(" Service Address = " + this.ServiceAddress); + Console.WriteLine(" Authentication Protocol = " + this.AuthenticationProtocol); + Console.WriteLine(" Authentication Realm = " + this.Realm); + Console.WriteLine(""); + + if (CredentialsManager.FindMatchingProtocolMapping( + this.ApplicationProtocol, + this.ServiceAddress, + this.AuthenticationProtocol, + this.Realm, + true, + out credentialsName, + out tag)) + { + Console.WriteLine("Credentials selected: {0} {1}", credentialsName, tag); + return 0; + } else { + Console.WriteLine("No mappings found that match the specified protocol tuple."); + return 1; + } + + } catch (Exception ex) { + Util.ShowException(ex); + return -1; + } + } + } + + + class Util + { + public static void ShowException(Exception! chain) + { + for (Exception ex = chain; ex != null; ex = ex.InnerException) { + Console.WriteLine(ex.GetType().FullName + ": " + ex.Message); + } + } + + public static void ShowCredError(CredError error) + { + Console.WriteLine("Error: " + CredentialsManager.CredErrorToString(error)); + } + } +} diff --git a/base/Applications/Date/Date.cs b/base/Applications/Date/Date.cs new file mode 100644 index 0000000..41f76f6 --- /dev/null +++ b/base/Applications/Date/Date.cs @@ -0,0 +1,63 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Date.cs +// +// Note: Simple Singularity test program. +// +using System; +using Microsoft.Singularity.V1.Services; + + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications { + [ConsoleCategory(HelpMessage="Show attributes associated with a file", DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal Parameters(); + + internal int AppMain() { + return Date.AppMain(this); + } + } + + public class Date + { + private static void ConsoleWriteDateTime(string preamble, DateTime dt) + { + Console.WriteLine("{0}{1:d4}/{2:d2}/{3:d2} {4:d2}:{5:d2}:{6:d2}.{7:d3}", + preamble, dt.Year, dt.Month, dt.Day, + dt.Hour, dt.Minute, dt.Second, dt.Millisecond); + } + + private static void ConsoleWriteTimeSpan(string preamble, TimeSpan sp) + { + Console.WriteLine("{0}{1:d5} days {2:d2}:{3:d2}:{4:d2}.{5:d3}", + preamble, sp.TotalDays, + sp.Hours, sp.Minutes, sp.Seconds, sp.Milliseconds); + } + + //[ShellCommand("date", "Display date and time")] + internal static int AppMain(Parameters! config) + { + ConsoleWriteTimeSpan("Kernel: ", ProcessService.GetUpTime()); + ConsoleWriteDateTime("UTC: ", DateTime.UtcNow); + return 0; + } + } +} diff --git a/base/Applications/Date/Date.csproj b/base/Applications/Date/Date.csproj new file mode 100644 index 0000000..4b75e27 --- /dev/null +++ b/base/Applications/Date/Date.csproj @@ -0,0 +1,25 @@ + + + + + + + Exe + Date + + + + + + + + + diff --git a/base/Applications/Godot/GOdot.csproj b/base/Applications/Godot/GOdot.csproj new file mode 100644 index 0000000..0b7b3d1 --- /dev/null +++ b/base/Applications/Godot/GOdot.csproj @@ -0,0 +1,26 @@ + + + + + + + Exe + Godot + true + + + + + + + + + diff --git a/base/Applications/Godot/Godot.cs b/base/Applications/Godot/Godot.cs new file mode 100644 index 0000000..d2cf674 --- /dev/null +++ b/base/Applications/Godot/Godot.cs @@ -0,0 +1,178 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Godot.cs +// +// Note: Singularity wait primitives test program. +// +using Microsoft.Singularity.V1.Services; +using Microsoft.Singularity.V1.Threads; +using System; +using System.Runtime.CompilerServices; +using System.Threading; + + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications { + [ConsoleCategory(HelpMessage="Show attributes associated with a file", DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [LongParameter( "t", Default=2, HelpMessage="Number of Waiters (threads)")] + internal long numberOfWaiters; + + reflective internal Parameters(); + + internal int AppMain() { + return Godot.AppMain(this); + } + } + + public class Godot + { + private static Mutex! mutex; + private static WaitHandle[]! waiters; + private static WaitHandle[]! others; + private static String[]! names; + private static WaiterThread[] threadDetails; + private static Thread[] threads; + + private class WaiterThread { + private uint myIndex; + + public WaiterThread(uint index) { + myIndex = index; + } + + public void Go() + { + String myName = names[myIndex]; + + Console.Write("Enter Thread {0}\n", myName); + + Console.Write(" {0}: signaling auto-reset event\n", myName); + ((AutoResetEvent!)waiters[myIndex]).Set(); + + for (uint Loop = 0; Loop < 5; Loop++) { + Console.Write(" {0}: waiting for mutex\n", myName); + mutex.WaitOne(); + Console.Write(" {0}: got mutex\n", myName); + + Thread.Sleep(1000); + + Console.Write(" {0}: releasing mutex\n", myName); + mutex.ReleaseMutex(); + Thread.Yield(); + } + + // + // Tell other waiters we're done. + // + Console.Write(" {0}: signaling manual-reset event\n", myName); + ((ManualResetEvent!)others[myIndex]).Set(); + + // + // Wait for other waiter. + // + Console.Write(" {0}: waiting for other waiters\n", myName); + foreach (WaitHandle! other in others) { + other.WaitOne(); + } + Console.Write(" {0}: heard from other waiters\n", myName); + + Console.Write("Exit Thread {0}\n", myName); + } + } + + public static void Usage() + { + Console.WriteLine("\nUsage: godot [NumberOfWaitThreads]\n\n"); + } + + internal static int AppMain(Parameters! config) + { + uint numberOfWaiters = (uint) config.numberOfWaiters; + + Console.Write("\nStarting wait test with {0} wait threads\n\n", + numberOfWaiters); + + names = new String[4]; + names[0] = "Estragon"; + names[1] = "Vladimir"; + names[2] = "Lucky"; + names[3] = "Pozzo"; + + // + // Create some synchronization primitives to test. + // + mutex = new Mutex(true); + waiters = new WaitHandle[numberOfWaiters]; + others = new WaitHandle[numberOfWaiters]; + for (uint Loop = 0; Loop < numberOfWaiters; Loop++) { + waiters[Loop] = new AutoResetEvent(false); + others[Loop] = new ManualResetEvent(false); + } + + Console.Write("Created synchronization primitives\n\n"); + + // + // Fire up the waiters. + // + threads = new Thread[numberOfWaiters]; + threadDetails = new WaiterThread[numberOfWaiters]; + for (uint Loop = 0; Loop < numberOfWaiters; Loop++) { + threadDetails[Loop] = new WaiterThread(Loop); + threads[Loop] = new Thread( + new ThreadStart(threadDetails[Loop].Go)); + ((!)threads[Loop]).Start(); + } + + // + // Wait for the waiters to tell us they're about to start waiting. + // + Console.Write("Waiting for all waiters to start\n"); + foreach (WaitHandle! waiter in waiters) { + waiter.WaitOne(); + } + + // + // Release the Mutex to the wolves. + // + Console.Write("About to release mutex\n"); + mutex.ReleaseMutex(); + Console.Write("Mutex released\n"); + + // + // Wait for the threads to die. + // +#if false +#if NOT_YET + Console.Write("Waiting for all waiters to terminate\n"); + for (uint Loop = 0; Loop < numberOfWaiters; Loop++) { + threads[Loop].Join(); + } +#else + Console.Write("Waiting for 30 sec while threads play\n"); + Thread.Sleep(30000); +#endif +#endif + + Console.Write("Goodbye\n"); + return 0; + } + } +} diff --git a/base/Applications/Hello/Hello.cs b/base/Applications/Hello/Hello.cs new file mode 100644 index 0000000..ec68e8e --- /dev/null +++ b/base/Applications/Hello/Hello.cs @@ -0,0 +1,23 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Hello.cs +// +// Note: Simple Singularity test program. +// +using System; + +namespace Microsoft.Singularity.Applications +{ + public class Hello + { + public static int Main(String[] args) + { + Console.WriteLine("Hello World!"); + return 0; + } + } +} diff --git a/base/Applications/Hello/Hello.csproj b/base/Applications/Hello/Hello.csproj new file mode 100644 index 0000000..c9d9812 --- /dev/null +++ b/base/Applications/Hello/Hello.csproj @@ -0,0 +1,25 @@ + + + + + + + Exe + Hello + + + + + + + + + diff --git a/base/Applications/HelloMp/HelloMp.cs b/base/Applications/HelloMp/HelloMp.cs new file mode 100644 index 0000000..6ced2be --- /dev/null +++ b/base/Applications/HelloMp/HelloMp.cs @@ -0,0 +1,25 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: HelloMp.cs +// +// Note: Simple Singularity test program. +// +using System; + +namespace Microsoft.Singularity.Applications +{ + public class HelloMp + { + public static int Main(String[] args) + { + Console.WriteLine("If you see this message, it means you haven't"); + Console.WriteLine("run Applications/HelloMpAsm/load-hack.cmd"); + Console.WriteLine("Please run the command AFTER msb Distro\\small.proj"); + return 0; + } + } +} diff --git a/base/Applications/HelloMp/HelloMp.csproj b/base/Applications/HelloMp/HelloMp.csproj new file mode 100644 index 0000000..8867b2a --- /dev/null +++ b/base/Applications/HelloMp/HelloMp.csproj @@ -0,0 +1,16 @@ + + + + + + Exe + HelloMp + + + + + + + + + diff --git a/base/Applications/HelloMpAsm/HelloMpAsm.cpp b/base/Applications/HelloMpAsm/HelloMpAsm.cpp new file mode 100644 index 0000000..f4cb8ba --- /dev/null +++ b/base/Applications/HelloMpAsm/HelloMpAsm.cpp @@ -0,0 +1,30 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// + + +int main () +{ + __asm { + //call printhellomp; + // myloop: jmp myloop; + // jmp mydone; + //printhellomp: + mov ebx, 0xb8000; + add ebx, 7680; + mov [ebx+0], 0x0020; + mov [ebx+1], 0x00e0; + mov [ebx+2], 0x0048; + mov [ebx+3], 0x00e0; + mov [ebx+4], 0x0069; + mov [ebx+5], 0x00e0; + mov [ebx+6], 0x0021; + mov [ebx+7], 0x00e0; + mov [ebx+8], 0x0020; + mov [ebx+9], 0x00e0; + // ret; + // mydone: + } + // return 0x9876543; +} diff --git a/base/Applications/HelloMpAsm/README b/base/Applications/HelloMpAsm/README new file mode 100644 index 0000000..00a2466 --- /dev/null +++ b/base/Applications/HelloMpAsm/README @@ -0,0 +1,20 @@ + +Notes: + + HelloMpAsm depends on HelloMp + + +HelloMp.cpp + + contains the assembly code that prints "Hi!" to the screen + directly (through 0xb800 physical address). + +build-hellomp.cmd + + Creates obj/HelloMpAsm.exe in local obj/ directory. + +load-hack.cmd + + After building the entire distribution, run load-hack.cmd so that + the standard HelloMp executable (HelloMp.x86 from Applications/HelloMp) + will be overwritten with HelloMpAsm.exe, then use network boot. diff --git a/base/Applications/HelloMpAsm/build-hellomp.cmd b/base/Applications/HelloMpAsm/build-hellomp.cmd new file mode 100644 index 0000000..d99c6c6 --- /dev/null +++ b/base/Applications/HelloMpAsm/build-hellomp.cmd @@ -0,0 +1,9 @@ + +mkdir obj + +cl.exe /nologo /c /Oxs /GFy /Gd /Gy /W3 /Zi /Zl /GS- /I..\include /FAsc /Faobj\HelloMpAsm.lst /Fdobj\HelloMpAsm.pdb /Foobj\HelloMpAsm.obj HelloMpAsm.cpp + +link /nologo /out:obj\HelloMpAsm.exe obj\HelloMpAsm.obj /pdb:obj\HelloMpAsm.pdb /map:obj\HelloMpAsm.map /fixed /entry:main /incremental:no /machine:ix86 /subsystem:native /ignore:4078 /merge:.rdata=.data /merge:.bss=.data /merge:.data=.text + +rename obj\hellompasm.pdb a +rename obj\a HelloMpAsm.pdb diff --git a/base/Applications/HelloMpAsm/load-hack.cmd b/base/Applications/HelloMpAsm/load-hack.cmd new file mode 100644 index 0000000..52f22a9 --- /dev/null +++ b/base/Applications/HelloMpAsm/load-hack.cmd @@ -0,0 +1,6 @@ + +copy obj\HelloMpAsm.exe ..\..\Distro\obj\Prototype.MarkSweep.x86\HelloMp.x86 + +copy obj\HelloMpAsm.exe ..\..\Distro\obj\Prototype.ApicMP.Min.MarkSweep.Prototype.MarkSweep\Singularity\Binaries\HelloMp.x86 + +copy obj\HelloMpAsm.exe ..\..\Distro\obj\Debug.ApicMP.Min.MarkSweep.Debug.MarkSweep\Singularity\Binaries\HelloMp.x86 diff --git a/base/Applications/IoLibtest/IoLibTest.csproj b/base/Applications/IoLibtest/IoLibTest.csproj new file mode 100644 index 0000000..decf47a --- /dev/null +++ b/base/Applications/IoLibtest/IoLibTest.csproj @@ -0,0 +1,32 @@ + + + + + + + Exe + IoLibTest + + + + + + + + + + + + + + + + diff --git a/base/Applications/IoLibtest/IoLibtest.sg b/base/Applications/IoLibtest/IoLibtest.sg new file mode 100644 index 0000000..bc90132 --- /dev/null +++ b/base/Applications/IoLibtest/IoLibtest.sg @@ -0,0 +1,27 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// + +using System; +using System.IO; + +namespace Microsoft.Singularity.Applications +{ + public class IoLibTest + { + public static void Main(string[] args) + { + if (args != null && args.Length >1) { + try { + File.Delete(args[1]); + } + catch (Exception e) { + Console.WriteLine("error deleting {0}, msg={1}", args[1], e.Message); + } + } + return ; + } + } +} + diff --git a/base/Applications/Lisp/Lisp.cs b/base/Applications/Lisp/Lisp.cs new file mode 100644 index 0000000..c7f0e71 --- /dev/null +++ b/base/Applications/Lisp/Lisp.cs @@ -0,0 +1,133 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Lisp.cs +// +// Note: Simple Singularity test program. +// +using System; +using ProtoLisp; + +using Microsoft.Singularity.Channels; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications { + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [StringArrayParameter( "args", HelpMessage="arg bucket")] + internal string[] args; + + reflective internal Parameters(); + + internal int AppMain() { + return Lisp.AppMain(this); + } + } + + public class Lisp + { + // Returns true if the arguments were valid, false for illegal args + private static bool GetLispArgs(string[]! args, out bool helpArg, out bool traceArg, out string exprArg) + { + traceArg = false; + helpArg = false; + exprArg = ""; + + for (int i = 0; i < args.Length; ++i) + { + string! args_i = (!)args[i]; + + if ((args_i.Length > 0) && (args_i[0] == '/')) + { + string arg = args_i.Substring(1); + + if (arg.Equals("trace")) + { + traceArg = true; + continue; + } + else if (arg.Equals("help") || arg.Equals("?")) + { + helpArg = true; + continue; + } + } + else + { + // A non-switch must be the last argument + if (i == (args.Length - 1)) + { + exprArg = args_i; + continue; + } + } + + // If we fall out, we have illegal arguments. + return false; + } + + // If we didn't abort, everything was OK + return true; + } + + internal static int AppMain(Parameters! config) + { + bool trace, help; + string expr; + string[] args = config.args; + + + if (args== null || args.Length <= 0) + { + Console.WriteLine("ProtoLisp interpreter."); + Console.WriteLine("Usage: lisp [flags] "); + Console.WriteLine("Run \"lisp /help\" or \"lisp /?\" for more details"); + return 0; + } + + bool validUsage = GetLispArgs(args, out help, out trace, out expr); + + if ((!validUsage) || (help)) + { + Console.WriteLine("ProtoLisp is an extremely basic Lisp-like interpreter.\n"); + Console.WriteLine("Usage: lisp [flags] LISPEXPRESSION\n"); + Console.WriteLine("Flags:"); + Console.WriteLine(" /? or /help : Print this message"); + Console.WriteLine(" /trace : Print verbose traces from the interpreter\n"); + Console.WriteLine("The following classic Lisp primitives are available:\n"); + Console.WriteLine(" atom, eq, car, cdr, cons, cond\n"); + Console.WriteLine("In addition,"); + Console.WriteLine(" - Variables are lexically scoped, not dynamically scoped."); + Console.WriteLine(" - (define X Y) binds the name \"X\" to the value \"Y\""); + Console.WriteLine(" in the global context"); + Console.WriteLine(" - (lambda (ARGLIST) (BODYEXPRESSION)) creates a \"closure\" by"); + Console.WriteLine(" capturing the ambient lexical scope."); + Console.WriteLine(" - (defun NAME (ARGLIST) (BODYEXPR) is sugar for"); + Console.WriteLine(" (define NAME (lambda (ARGLIST) (BODYEXPR)))\n"); + Console.WriteLine(" - The arithmetic operators *, +, -, / are available. Math is"); + Console.WriteLine(" performed with integers."); + } + else + { + ProtoLisp.Engine engine = new ProtoLisp.Engine(); + System.Console.Write(engine.EvalAll(expr, true, trace)); + } + + return 0; + } + } +} diff --git a/base/Applications/Lisp/Lisp.csproj b/base/Applications/Lisp/Lisp.csproj new file mode 100644 index 0000000..e6b9471 --- /dev/null +++ b/base/Applications/Lisp/Lisp.csproj @@ -0,0 +1,32 @@ + + + + + + + Exe + Lisp + + + + + + + + + + + + + + + + diff --git a/base/Applications/Login/Login.csproj b/base/Applications/Login/Login.csproj new file mode 100644 index 0000000..6b0962f --- /dev/null +++ b/base/Applications/Login/Login.csproj @@ -0,0 +1,33 @@ + + + + + + + Exe + Login + true + + + + + + + + + + + + + + + + diff --git a/base/Applications/Login/Login.sg b/base/Applications/Login/Login.sg new file mode 100644 index 0000000..53416f8 --- /dev/null +++ b/base/Applications/Login/Login.sg @@ -0,0 +1,244 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// + +using System; +using System.Text.RegularExpressions; +using System.Threading; + +using Microsoft.Contracts; +using Microsoft.SingSharp; +using Microsoft.SingSharp.Reflection; + +using Microsoft.Singularity; +using Microsoft.Singularity.Security; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Configuration; + +[assembly: ApplicationPublisherAttribute("singularity.microsoft.com")] +[assembly: AssertPrivilegeAttribute("$truncate-history-privilege.localhost")] +[assembly: AssertPrivilegeAttribute("$trusted-auth-privilege.localhost")] +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications.Login +{ + [ConsoleCategory(HelpMessage="Login", DefaultAction=true)] + internal class Parameters + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal Parameters(); + + internal int AppMain() { + return Login.AppMain(this); + } + } + + /// + /// Simple login process implementation. + /// Asks the user for its user name and starts a new instance of itself under + /// the new role. The new instance invokes the shell. + /// + + // See WaitForChildThread below + internal contract WaitForChildContract { + out message Finish(); + state Start: one {Finish! -> Done;} + state Done: one {} + } + + public class Login + { + /// + /// Regular expression specifying a valid user name + /// + public const string Arc = @"[a-zA-Z1-90_\.]+"; + /// + /// The name of the shell process + /// + public const string Shell = "shell"; + private Regex! nameRegex = new Regex(Arc); + + internal static int AppMain(Parameters! config) + { + Login login = new Login(); + return login.Run(); + } + + internal int Run() + { + for(;;){ + Console.Write("login: "); + string line = Console.ReadLine(); + if (line != null && nameRegex.IsMatch(line)){ + return RunShell(line); + } + } + } + + internal int RunShell(string! username) + { + int exitCode = 0; + string path; + try { + Process process = new Process(Shell, null, username); + UnicodePipeContract.Imp! stdInImp; + UnicodePipeContract.Exp! stdInExp; + UnicodePipeContract.NewChannel(out stdInImp, out stdInExp); + UnicodePipeContract.Imp! stdOutImp; + UnicodePipeContract.Exp! stdOutExp; + UnicodePipeContract.NewChannel(out stdOutImp, out stdOutExp); + process.SetStartupEndpoint(0, (Endpoint * in ExHeap) stdInExp); + process.SetStartupEndpoint(1, (Endpoint * in ExHeap) stdOutImp); + process.Start(); + exitCode = WaitForShell(process, stdInImp, stdOutExp); + if (exitCode != 0) { + Console.WriteLine("-- Exit code: {0}", exitCode); + } + } + catch (ProcessCreateException) { + Console.WriteLine("Can't create shell"); + } + catch (Exception e) { + Console.Write("Can't start shell: Exception '{0}' caught.", e.Message); + } + return exitCode; + } + + /// + /// Copy and echo characters from shell stdin to job stdin, + /// and from job stdout to shell stdout. + /// + /// Known limitation: if the child process opens + /// its own keyboard channel, the shell may never see the control-c + /// message. + /// + private int WaitForShell(Process! process, + [Claims] UnicodePipeContract.Imp:READY! childStdIn, + [Claims] UnicodePipeContract.Exp:READY! childStdOut) + { + WaitForChildContract.Imp! waitImp; + WaitForChildContract.Exp! waitExp; + WaitForChildContract.NewChannel(out waitImp, out waitExp); + + PipeLookAhead cinput = ConsoleInput.AcquireInput(); + + ESet childStdInAck = + new ESet(); + ESet childStdInReady = + new ESet(); + ESet childStdOutReady = + new ESet(); + + char[] in ExHeap exChar = new [ExHeap] char[1]; + try { + WaitForChildThread.StartWaiting(process, + new TRef(waitExp)); + + childStdInReady.Add(childStdIn); + childStdOutReady.Add(childStdOut); + + bool done = false; + while (!done) { + // invariant exChar != null && childStdInReady.Head(ep) || + // exChar == null && childStdInReady.Empty + switch receive { + + case cinput.Char(ch) && childStdInReady.Head(ep): + // we have a char and childStdIn is ready + assert exChar != null; + // echo character + //Console.Write(ch); + exChar[0] = (char) ch; + ep.SendWrite(exChar,0,1); + exChar = null; + childStdInAck.Add(ep); + continue; + + case ep.AckWrite(buffer) in childStdInAck: + assert exChar == null; + exChar = buffer; + childStdInReady.Add(ep); + continue; + + case waitImp.Finish(): + //Console.WriteLine("finish"); + done = true; + break; + + case ep.Write(buffer, index, count) in childStdOutReady: + string s = Bitter.ToString2(buffer, index, count); + Console.Write(s); + ep.SendAckWrite(buffer); + childStdOutReady.Add(ep); + continue; + + case ep.ChannelClosed() in childStdInAck: + delete ep; + continue; + + case ep.ChannelClosed() in childStdOutReady: + delete ep; + continue; + } + } + } + finally { + childStdInReady.Dispose(); + childStdInAck.Dispose(); + childStdOutReady.Dispose(); + ConsoleInput.ReleaseInput(cinput); + delete waitImp; + delete exChar; + } + int exitCode = process.ExitCode; + process.Dispose(true); + return exitCode; + } + + // [Hawblitzel] TODO: better ways to wait on a child process + private class WaitForChildThread + { + private Process! process; + private TRef! expRef; + + private WaitForChildThread(Process! process, + TRef! expRef) + { + this.process = process; + this.expRef = expRef; + base(); + } + + public static void StartWaiting(Process process, + TRef! expRef) + { + if (process == null) { + WaitForChildContract.Exp exp = expRef.Acquire(); + exp.SendFinish(); + delete exp; + return; + } + + WaitForChildThread wft = new WaitForChildThread(process, expRef); + Thread t = new Thread(new ThreadStart(wft.Wait)); + t.Start(); + } + + private void Wait() + { + process.Join(); + WaitForChildContract.Exp exp = expRef.Acquire(); + exp.SendFinish(); + delete exp; + } + } + } +} diff --git a/base/Applications/MapPointProxy/Base64Decoder.cs b/base/Applications/MapPointProxy/Base64Decoder.cs new file mode 100644 index 0000000..f8ca523 --- /dev/null +++ b/base/Applications/MapPointProxy/Base64Decoder.cs @@ -0,0 +1,160 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +/////////////////////////////////////////////////////////////////////////////// + +using System; +using Microsoft.Contracts; + +internal class Base64Decoder +{ + private string fSourceStr; + private int fCurStrIndex; + private bool fDone; + + private int fBits; + private int fBitsFilled; + + private const string CharsBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + private static readonly byte[] MapBase64 = ConstructMapBase64(); + private const int MaxValidChar = (int)'z'; + private const byte Invalid = unchecked((byte)-1); + + public Base64Decoder(string! sourceString, int startIndex) + { + fSourceStr = sourceString; + fCurStrIndex = startIndex; + fDone = false; + Reset(); + } + + [Delayed] + public void Reset() + { + fBits = 0; + fBitsFilled = 0; + } + + public byte[] Pump(int maxStrIndex, int maxReturnSize) + { + if ((fDone) || (fSourceStr == null)) + { + return null; + } + + int charsConsumed; + + byte[] retval = InternalPump(fSourceStr, fCurStrIndex, maxStrIndex, maxReturnSize, + out charsConsumed, out fDone); + + fCurStrIndex += charsConsumed; + + return retval; + } + + private byte[] InternalPump(string! sourceStr, int startIndex, int maxIndex, int maxReturnSize, + out int charsConsumed, out bool done) + { + // walk hex digits pairing them up and shoving the value of each pair into a byte + byte[] newChunk = new byte[maxReturnSize]; + int bytePos = 0; + int charPos = startIndex; + int b = fBits; + int bFilled = fBitsFilled; + + while ( charPos < maxIndex && bytePos < maxReturnSize ) + { + char ch = sourceStr[charPos]; + + // end? + if ( ch == '=' ) { + done = true; + break; + } + + charPos++; + + // ignore white space + if (char.IsWhiteSpace(ch)) { + continue; + } + + int digit; + if ( ch > 122 || ( digit = MapBase64[ch] ) == Invalid ) { + throw new Exception("Invalid Base64 character: " + ch); + } + + b = ( b << 6 ) | digit; + bFilled += 6; + + if ( bFilled >= 8 ) { + // get top eight valid bits + newChunk[bytePos++] = (byte)( ( b >> ( bFilled - 8 ) ) & 0xFF ); + bFilled -= 8; + + if ( bytePos == maxReturnSize ) { + break; + } + } + } + + if (bytePos < maxReturnSize) + { + if ( charPos < maxIndex && sourceStr[charPos] == '=' ) { + bFilled = 0; + + // ignore padding chars + do { + charPos++; + } while ( charPos < maxIndex && sourceStr[charPos] == '=' ); + + // ignore whitespace after the padding chars + if ( charPos < maxIndex ) { + while ( charPos < maxIndex ) { + if ( ! char.IsWhiteSpace(sourceStr[charPos++]) ) + throw new Exception("Invalid Base64 character: " + sourceStr[charPos - 1]); + } + } + } + } + + fBits = b; + fBitsFilled = bFilled; + charsConsumed = charPos - startIndex; + + if (bytePos < maxReturnSize) + { + byte[] trimmed = new byte[bytePos]; + Buffer.BlockCopy(newChunk, 0, trimmed, 0, bytePos); + newChunk = trimmed; + + // We ran out of characters, so we're done + done = true; + + } + else + { + done = false; + } + + return newChunk; + } + + private static byte[] ConstructMapBase64() + { + byte[] mapBase64 = new byte[MaxValidChar + 1]; + + for ( int i = 0; i < mapBase64.Length; i++ ) { + mapBase64[i]= Invalid; + } + + for ( int i = 0; i < CharsBase64.Length; i++ ) { + mapBase64[(int)CharsBase64[i]] = (byte)i; + } + + return mapBase64; + } +} diff --git a/base/Applications/MapPointProxy/ByteBuffer.cs b/base/Applications/MapPointProxy/ByteBuffer.cs new file mode 100644 index 0000000..340c112 --- /dev/null +++ b/base/Applications/MapPointProxy/ByteBuffer.cs @@ -0,0 +1,134 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +/////////////////////////////////////////////////////////////////////////////// + +using System; + +public class ByteBuffer +{ + private byte[] fData; + private int fSize; // Amount of fData actually available to the user + + public ByteBuffer(int initialSize) + { + fData = new byte[initialSize]; + fSize = initialSize; + } + + public ByteBuffer() + { + } + + public void EnsureSize(int overallSize) + { + // Asking for less space than you have does nothing + if (overallSize < fSize) + { + return; + } + + // Asking for zero when we're empty does nothing + if (overallSize == 0) + { + return; + } + + if ((fData == null) || (fData.Length < overallSize)) + { + // Not enough room in our current array. Double until we're big enough. + int newSize = (fData == null) ? overallSize : fData.Length; + while (newSize < overallSize) { newSize *= 2; } + byte[] newBuffer = new byte[newSize]; + + if (fData != null) + { + int bytesToCopy = overallSize < fSize ? overallSize : fSize; + Buffer.BlockCopy(fData, 0, newBuffer, 0, bytesToCopy); + } + + fData = newBuffer; + } + + fSize = overallSize; + } + + public void Add(byte[] newData, int offset, int length) + { + int previousSize = fSize; + EnsureSize(previousSize + length); + Buffer.BlockCopy(newData, offset, fData, previousSize, length); + } + + public void Add(byte newByte) + { + int previousSize = fSize; + EnsureSize(previousSize + 1); + fData[previousSize] = newByte; + } + + // WARNING; Do not rely on this being accessible across calls to + // Add() or EnsureSize()!! Do not index out of bounds!! UNSAFE! + public byte[] UnderlyingBuffer + { + get { return fData; } + } + + public byte[] TrimAndCopy(int trimLength) + { + return TrimAndCopy(0, trimLength); + } + + public byte[] TrimAndCopy(int offset, int trimLength) + { + byte[] retval = new byte[trimLength]; + Buffer.BlockCopy(fData, offset, retval, 0, trimLength); + return retval; + } + + public int Size + { + get + { + if (fData != null) + { + return fSize; + } + else + { + return 0; + } + } + } + + public byte this[int index] + { + get + { + ValidateIndex(index); + return fData[index]; + } + + set + { + ValidateIndex(index); + fData[index] = value; + } + } + + private void ValidateIndex(int index) + { + if (fData == null) + { + throw new IndexOutOfRangeException("Buffer currently empty"); + } + + if ((index < 0) || (index >= fSize)) + { + throw new IndexOutOfRangeException(); + } + } +} diff --git a/base/Applications/MapPointProxy/HttpAuthenticator.cs b/base/Applications/MapPointProxy/HttpAuthenticator.cs new file mode 100644 index 0000000..31ffcb1 --- /dev/null +++ b/base/Applications/MapPointProxy/HttpAuthenticator.cs @@ -0,0 +1,166 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +/////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Diagnostics; +using System.Text; +using Microsoft.Singularity.Crypto; + +public class HttpAuthenticator +{ + private HttpRequest fRequest; + private string fUsername, fPassword; + private MD5 fMD5; + + public HttpAuthenticator(HttpRequest request, string username, string password) + { + fRequest = request; + fUsername = username; + fPassword = password; + fMD5 = new MD5(); + } + + public HttpResponse GetResponse() + { + // First try the original request + HttpResponse response = fRequest.GetResponse(); + + if (response == null) + { + throw new Exception("Initial HTTP request failed"); + } + + int status = response.StatusCode; + + if (status != 401) + { + // No authentication was actually required + return response; + } + else + { + // Authentication is required. Go spelunking for the crypto challenge. + string challenge = response.GetHeader("WWW-Authenticate"); + + if (challenge == null) + { + throw new Exception("401 without a WWW-Authenticate header"); + } + + if (!challenge.StartsWith("Digest")) + { + throw new Exception("Invalid WWW-Authenticate header"); + } + + string realm = GetTaggedQuotedString(challenge, "realm"); + string nonce = GetTaggedQuotedString(challenge, "nonce"); + string opaque = GetTaggedQuotedString(challenge, "opaque"); + string algorithm = GetTaggedQuotedString(challenge, "algorithm"); + + if ((algorithm != null) && (!algorithm.ToLower().Equals("md5"))) + { + throw new Exception("Unknown authentication scheme"); + } + + if ((realm == null) || (nonce == null)) + { + throw new Exception("Missing essential elements of WWW-Challenge"); + } + + // Compute the crypto response + string authResponse = "Digest username=\"" + fUsername + + "\",realm=\"" + realm + + "\",nonce=\"" + nonce + + "\",uri=\"" + fRequest.Resource + + "\",response=\""; + + // + // The crypto response is specified (RFC 2069) as: + // + // MD5( concat(A1, ":", B)) + // where A1 is: MD5( concat( username, ":", realm, ":", password) ) + // and B is: concat( nonce, ":", A2) + // and A2 is: MD5( concat (method, ":", digest-uri) ) + // Where MD5(X) is a string of hex digits representing the MD5 digest of X. + // Got all that? + // + + // Form A1 = MD5(username : realm : password) + string a1 = MD5(fUsername + ":" + realm + ":" + fPassword); + + // Form A2 = md5(method : digest-uri) + string a2 = MD5(fRequest.Method + ":" + fRequest.Resource); + + // Form B = nonce : A2 + string b = nonce + ":" + a2; + + // Form the unhashed final answer as MD5(A1 : B) + authResponse += MD5(a1 + ":" + b) + "\""; + + // Echo the server's opaque string if present. + if (opaque != null) + { + authResponse += ",opaque=\"" + opaque + "\""; + } + + fRequest.AddHeader("Authorization", authResponse); + + // Rerun the request + response = fRequest.GetResponse(); + + if ((response != null) && (response.StatusCode == 401)) + { + // Authentication failed; credentials must be bad + throw new Exception("Bad credentials"); + } + + // Looks like it worked after authentication + return response; + } + } + + private string GetTaggedQuotedString(string! baseString, string tagName) + { + string tagPreamble = tagName + "=\""; + int tagStart = baseString.IndexOf(tagPreamble); + + if (tagStart == -1) + { + return null; + } + + int tagEnd = tagStart + tagPreamble.Length; + int quoteEnd = baseString.IndexOf('"', tagEnd); + + if (quoteEnd == -1) + { + throw new Exception("Malformed tagged+quoted string"); + } + + return baseString.Substring(tagEnd, quoteEnd - tagEnd); + } + + private string MD5(string! hashValue) + { + byte[] vals = Encoding.ASCII.GetBytes(hashValue); + byte[] result = (!)fMD5.Hash(vals); + return ToHexString(result); + } + + private string ToHexString(byte[]! vals) + { + string retval = String.Empty; + + for (int i = 0; i < vals.Length; ++i) + { + retval += vals[i].ToString("x2"); + } + + return retval; + } +} diff --git a/base/Applications/MapPointProxy/HttpRequest.cs b/base/Applications/MapPointProxy/HttpRequest.cs new file mode 100644 index 0000000..df0a214 --- /dev/null +++ b/base/Applications/MapPointProxy/HttpRequest.cs @@ -0,0 +1,768 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +/////////////////////////////////////////////////////////////////////////////// + +/* + * This helper class assists in forming HTTP requests and retrieving the + * resulting data. + */ + +using System; +using System.Collections; +using System.Collections.Specialized; +using System.Diagnostics; +using System.Globalization; +using System.Net; +using System.Net.Sockets; +using System.Text; + +public class HttpRequest +{ + private string fRequestUri, fHost, fResource, fMethod, fContentType; + private int fHostPort; + private byte[] fRequestData; + private Hashtable fRequestHeaders; + private long fTimeout; // Zero for infinite + + // CONSTANTS + private static string proxyHost = null; + private static int proxyPort = 0; + const int readIncrementSize = 1024 * 2; // 2Kbytes + const int bodySizeGuess = 5 * 1024; // 5KBytes + + public static void ConfigureProxy(string host, int port) + { + proxyHost = host; + proxyPort = port; + } + + public HttpRequest(string! uri) + { + fRequestUri = uri; + + // Parse the URI into a host-part and a path-part. + const string httpPrefix = "http://"; + if (!uri.StartsWith(httpPrefix)) + { + throw new ArgumentException("URI must begin with 'http://'"); + } + + int startIndex = httpPrefix.Length; + int firstSlash = uri.IndexOf('/',startIndex); + + string fHost; + if (firstSlash != -1) + { + fHost = uri.Substring(startIndex, firstSlash - startIndex); + fResource = uri.Substring(firstSlash); + } + else + { + // Host is the entire Uri + fHost = uri.Substring(startIndex); + fResource = String.Empty; + } + + int firstColon = fHost.IndexOf(':'); + + if (firstColon != -1) + { + fHostPort = Int32.Parse(fHost.Substring(firstColon + 1)); + } + else + { + fHostPort = 80; // default + } + + this.fRequestHeaders = new Hashtable(); + this.fMethod = "GET"; + this.fHost = fHost; + } + + public void AddHeader(string! headerName, string headerValue) + { + fRequestHeaders[headerName] = headerValue; + } + + public string Method + { + get { return fMethod; } + set { fMethod = value; } + } + + public string ContentType + { + get { return fContentType; } + set { fContentType = value; } + } + + public byte[] RequestData + { + get { return fRequestData; } + set { fRequestData = value; } + } + + public long Timeout + { + get { return fTimeout; } + set { fTimeout = value; } + } + + public string Resource + { + get { return fResource; } + } + + // Perform the HTTP hit and return the result! + public HttpResponse GetResponse() + { + // + // Step 1: Connect to the remote server + // + Socket httpSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, + ProtocolType.Tcp); + + string serverName, requestUri; + int serverPort; + + if (proxyPort > 0) + { + serverName = proxyHost; + serverPort = proxyPort; + requestUri = fRequestUri; // Use the full URI + } + else + { + serverName = fHost; + serverPort = fHostPort; + requestUri = fResource; // Use just the resource + } + + IPAddress serverAddress; + + try + { + serverAddress = IPAddress.Parse(serverName); + } + catch(Exception) + { + // Hostname didn't parse as an IP address; try to resolve it + IPHostEntry! entry = (!)Dns.Resolve(serverName); + IPAddress[]! addresses = (!)entry.AddressList; + + if (addresses.Length == 0) + { + throw new Exception("Couldn't resolve host name"); + } + + serverAddress = addresses[0]; + } + + IPEndPoint serverEndpoint = new IPEndPoint(serverAddress, serverPort); + + // Connect to the remote server + httpSocket.Connect(serverEndpoint); + + // + // Step 2: Formulate and transmit the request line and any supporting data + // + // Send the request line + string requestLine = fMethod + " " + requestUri + " HTTP/1.1\r\nHost: " + + fHost + "\r\nConnection: Close\r\n"; + + // Send an indication of the request data content type and size, if appropriate + if (fRequestData != null) + { + requestLine += "Content-Length: " + fRequestData.Length + "\r\n" + + "Content-Type: " + fContentType + "\r\n"; + } + + // Add any user-specified headers + foreach (string! headerName in fRequestHeaders.Keys) + { + requestLine += headerName + ": " + fRequestHeaders[headerName] + "\r\n"; + } + + requestLine += "\r\n"; + byte[] requestBytes = Encoding.ASCII.GetBytes(requestLine); + httpSocket.Send(requestBytes); + + // Send any request data + if (fRequestData != null) + { + httpSocket.Send(fRequestData); + } + + // Signal we're done sending + httpSocket.Shutdown(SocketShutdown.Send); + + // + // Step 3: Parse the response line and headers + // + + // Pump the response into an HttpHeadersParser + ByteBuffer scratchBuffer = new ByteBuffer(); + HttpHeadersParser headerParser = new HttpHeadersParser(scratchBuffer); + bool doneWithout100Continue = false, doneWithHeaders = false; + int nextWritePos = 0; + HttpResponse response = null; + + do + { + while(!doneWithHeaders) + { + // Make 2K available for each read + scratchBuffer.EnsureSize(nextWritePos + readIncrementSize); + int numReadBytes = httpSocket.Receive(scratchBuffer.UnderlyingBuffer, nextWritePos, + scratchBuffer.Size - nextWritePos, SocketFlags.None); + + if (numReadBytes == 0) + { + // We ran out of data before we finished parsing headers. + throw new Exception("Unexpected end of data"); + } + + nextWritePos += numReadBytes; + + if (headerParser.Pump(nextWritePos)) + { + // Finished parsing headers! + response = headerParser.GetResponse(); + doneWithHeaders = true; + } + } + + if (response == null) + { + throw new Exception("HTTP response data unexpectedly null"); + } + + // Special case: if we see a 100-continue, we want to carefully start + // over at the next chunk of data! + if (response.StatusCode == 100) + { + // Switch to a new scratch buffer that will contain the data + // following the 100-continue. + int remainderBeginning = headerParser.BodyDataOffset; + int remainderLength = nextWritePos - remainderBeginning; + ByteBuffer newScratch = new ByteBuffer(); + ByteBuffer oldScratch = scratchBuffer; + + // Reset parsing by creating a new parser + headerParser = new HttpHeadersParser(newScratch); + + // Switch over! + scratchBuffer = newScratch; + nextWritePos = remainderLength; + + if (remainderLength > 0) + { + // Copy the beginning of the next data chunk into newScratch + newScratch.EnsureSize(remainderLength); + Buffer.BlockCopy(oldScratch.UnderlyingBuffer, remainderBeginning, + newScratch.UnderlyingBuffer, 0, remainderLength); + + // Make sure the fragment we were already holding gets pumped in + if (headerParser.Pump(nextWritePos)) + { + // Interestingly, we're already done + response = headerParser.GetResponse(); + if (response == null) + { + throw new Exception("HTTP response data unexpectedly null"); + } + Debug.Assert(response.StatusCode != 100); + doneWithout100Continue = true; + } + else + { + // Go back and carry on + doneWithHeaders = false; + } + } + else + { + // The chunk we were chewing on exactly contained the 100-continue, + // so we definitely need to go back and read some more... + doneWithHeaders = false; + } + } + else + { + // The response was not 100-continue, so we're all done + doneWithout100Continue = true; + } + } + while(!doneWithout100Continue); + + // + // Step 4: Process the body data + // + // Now figure out how we're going to deal with the actual body + // of the response. We almost certainly already have an initial + // chunk of the body data in the scratchBuffer, since we read the + // headers in 2K chunks + // + int bodyScratchBeginning = headerParser.BodyDataOffset; + int scratchBodyLength = nextWritePos - bodyScratchBeginning; + + string transferEncoding = response.GetHeader("Transfer-Encoding"); + if (transferEncoding != null && + transferEncoding.ToLower().Equals("chunked")) + { + // Chunked encoding is special: the beginning of the body data + // already specifies some chunk information. Run this through our + // chunk decoder to straighten it out. + byte[] initialBodyChunk = scratchBuffer.TrimAndCopy(bodyScratchBeginning, scratchBodyLength); + ChunkedEncodingParser chunkParser = new ChunkedEncodingParser(initialBodyChunk, httpSocket); + ByteBuffer bodyData = chunkParser.Run(); + response.BodyData = bodyData.TrimAndCopy(bodyData.Size); + } + else + { + ByteBuffer bodyBuffer; + + // Non-chunked encoding. First, move the beginning of the body + // data to a new ByteBuffer for sanity. + // Separate out any initial body data into a new ByteBuffer, for sanity + int bodySize = (response.ContentLength > 0) ? response.ContentLength : bodySizeGuess; + + // Hard to imagine how this would happen... + if (bodySize < scratchBodyLength) + { + bodySize = scratchBodyLength; + } + + bodyBuffer = new ByteBuffer(bodySize); + Buffer.BlockCopy(scratchBuffer.UnderlyingBuffer, bodyScratchBeginning, + bodyBuffer.UnderlyingBuffer, 0, scratchBodyLength); + int nextBodyPos = scratchBodyLength; + + if (response.ContentLength > 0) + { + // Read until we've gotten exactly the expected number of bytes + int bodyDataLeft = response.ContentLength - scratchBodyLength; + + while (bodyDataLeft > 0) + { + int numReadBytes = httpSocket.Receive(bodyBuffer.UnderlyingBuffer, nextBodyPos, + bodyDataLeft, SocketFlags.None); + + if (numReadBytes == 0) + { + throw new Exception("Connection closed unexpectedly"); + } + + nextBodyPos += numReadBytes; + bodyDataLeft -= numReadBytes; + } + } + else + { + // No indicated ContentLength; Just read until the connection gets closed! + int numReadBytes = 0; + + // Read until the remote side closes + do + { + bodyBuffer.EnsureSize(bodyBuffer.Size + readIncrementSize); + numReadBytes = httpSocket.Receive(bodyBuffer.UnderlyingBuffer, nextBodyPos, + bodyBuffer.Size - nextBodyPos, SocketFlags.None); + nextBodyPos += numReadBytes; + } + while (numReadBytes > 0); + } + + response.BodyData = bodyBuffer.TrimAndCopy(nextBodyPos); + } + + // All done! + httpSocket.Close(); + + return response; + } + + private class HttpHeadersParser + { + // The buffer we are chewing on + ByteBuffer fBuffer; + + // The response we are forming + private HttpResponse fResponse; + private int fContentLength; + + // Working state + private State fState; + private int fPosition; + private int fBufferLimit; // One more than the last usable index in the buffer + + private enum State + { + BeforeStatusLine, + ParsingHeaders, + Complete + } + + public HttpHeadersParser(ByteBuffer buffer) + { + fBuffer = buffer; + fResponse = new HttpResponse(); + } + + public bool Pump(int newBufferLimit) + { + bool allDone = false, outOfRoom = false; + + while ((!allDone) && (!outOfRoom)) + { + PumpInternal(newBufferLimit, out allDone, out outOfRoom); + } + + return allDone; + } + + private void PumpInternal(int newBufferLimit, out bool allDone, out bool outOfRoom) + { + fBufferLimit = newBufferLimit; + + if (fState == State.Complete) + { + // We've already completed + allDone = true; + outOfRoom = false; + return; + } + + int CRLFOffset = FindNextCRLF(fPosition, fBufferLimit); + + if (fState == State.BeforeStatusLine) + { + if (CRLFOffset != -1) + { + HandleStatusLine(fPosition, CRLFOffset - fPosition); + fState = State.ParsingHeaders; + fPosition = CRLFOffset + 2; + allDone = false; + outOfRoom = false; + return; + } + else + { + // We couldn't see another CRLF before the end of the + // usable part of the buffer, so we're out of room. + allDone = false; + outOfRoom = true; + return; + } + } + else if (fState == State.ParsingHeaders) + { + // Special case: if the unprocessed part starts with CRLF it + // means we are looking at the end of the headers, since we consume + // the trailing CRLF on a single header line when parsing. + if (CRLFOffset == fPosition) + { + fState = State.Complete; + fPosition += 2; + allDone = true; + outOfRoom = false; + return; + } + else if (CRLFOffset != -1) + { + HandleHeaderLine(fPosition, CRLFOffset - fPosition); + fPosition = CRLFOffset + 2; + allDone = false; + outOfRoom = false; + return; + } + else + { + // We couldn't see another CRLF before the end of the + // usable part of the buffer, so we're out of room. + allDone = false; + outOfRoom = true; + return; + } + } + + // Someone must have added a state or mucked up the code + allDone = false; + outOfRoom = false; + Debug.Assert(false); + } + + public HttpResponse GetResponse() + { + if (fState == State.Complete) + { + return fResponse; + } + else + { + // Not allowed to have half-baked results! + return null; + } + } + + public int BodyDataOffset + { + get + { + if (fState == State.Complete) + { + return fPosition; + } + else + { + // No answer if we're not done processing + return -1; + } + } + } + + public int ContentLength + { + get + { + if (fState == State.Complete) + { + return fContentLength; + } + else + { + // Not available if we're not done processing + return -1; + } + } + } + + private void HandleStatusLine(int startOffset, int length) + { + string status = Encoding.ASCII.GetString(fBuffer.UnderlyingBuffer, startOffset, length); + const string HTTP11 = "HTTP/1.1 "; + + if (!status.StartsWith(HTTP11)) + { + throw new Exception("Response was not HTTP/1.1"); + } + + int secondSpace = status.IndexOf(' ', HTTP11.Length); + string statusString; + + if (secondSpace == -1) + { + // Assume this means there is a status code with no explanation string + statusString = status.Substring(HTTP11.Length); + } + else + { + // Grab just the status code + statusString = status.Substring(HTTP11.Length, secondSpace - HTTP11.Length); + } + + int statusCode = Int32.Parse(statusString); + fResponse.StatusCode = statusCode; + } + + private void HandleHeaderLine(int startOffset, int length) + { + string header = Encoding.ASCII.GetString(fBuffer.UnderlyingBuffer, startOffset, length); + int firstColon = header.IndexOf(':'); + + if (firstColon == -1) + { + throw new Exception("Malformed header string"); + } + + string headerName = header.Substring(0, firstColon); + string headerValue = header.Substring(firstColon + 1).Trim(); + + if (headerName.ToLower().Equals("content-length")) + { + fContentLength = Int32.Parse(headerValue); + } + else + { + fResponse.AddHeader(headerName, headerValue); + } + } + + private int FindNextCRLF(int startOffset, int limitOffset) + { + int offset = startOffset; + + while (offset < limitOffset) + { + if (fBuffer[offset] == (byte)'\r') + { + if ((offset + 1 < limitOffset) && (fBuffer[offset + 1] == (byte)'\n')) + { + return offset; + } + } + + offset++; + } + + return -1; + } + } + + private class ChunkedEncodingParser + { + // This buffer is what we start with; it has an initial + // fragment of the body data + private byte[] fInitialFragment; + private int fFragmentOffset; // How far into fInitialFragment we are + private Socket fSocket; // Socket to read additional data from + private byte[] fSingleByte; + + public ChunkedEncodingParser(byte[] initialFragment, Socket readSocket) + { + fInitialFragment = initialFragment; + fSocket = readSocket; + fSingleByte = new byte[1]; + } + + public ByteBuffer! Run() + { + ByteBuffer bodyData = new ByteBuffer(); + int chunkSize = 0; + + while(true) + { + ByteBuffer! chunkLine = ReadToCRLF(); + string! chunkString = (!)Encoding.ASCII.GetString(chunkLine.UnderlyingBuffer, 0, chunkLine.Size); + chunkString = (!)chunkString.Trim(); + int firstSemi = chunkString.IndexOf(';'); + + if (firstSemi != -1) + { + // Use only the portion before the semicolon + chunkSize = Int32.Parse(chunkString.Substring(0, firstSemi), + NumberStyles.AllowHexSpecifier); + } + else + { + // No semicolon; use the entire line + chunkSize = Int32.Parse(chunkString, NumberStyles.AllowHexSpecifier); + } + + if (chunkSize == 0) + { + // We're done! Don't bother reading the trailer + return bodyData; + } + + // Read in the amount indicated by the chunk header. It may take multiple passes + // to do this. + int writeOffset = bodyData.Size; + bodyData.EnsureSize(bodyData.Size + chunkSize); + + while(chunkSize > 0) + { + int numBytesRead = MassRead(bodyData.UnderlyingBuffer, writeOffset, chunkSize); + chunkSize -= numBytesRead; + writeOffset += numBytesRead; + } + + // Peel off the CRLF that trails a chunk + ByteBuffer emptyLine = ReadToCRLF(); + if (emptyLine.Size != 0) + { + throw new Exception("Malformed HTTP/1.1 chunk -- no trailing lone CRLF"); + } + } + } + + private ByteBuffer! ReadToCRLF() + { + ByteBuffer retval = new ByteBuffer(); + InnerReadToCRLF(retval); + return retval; + } + + private void InnerReadToCRLF(ByteBuffer buffer) // buffer can be null + { + // Read characters into buffer until we see a CRLF (don't include) + byte nextByte = GetNextByte(); + + while(true) + { + if (nextByte == (byte)'\r') + { + nextByte = GetNextByte(); + + if (nextByte == (byte)'\n') + { + // Done + return; + } + else + { + if (buffer != null) + { buffer.Add((byte)'\r'); } + + // Don't read again; nextByte might + // be the first byte of CRLF. + } + } + else + { + if (buffer != null) + { buffer.Add(nextByte); } + nextByte = GetNextByte(); + } + } + } + + private void DiscardToCRLF() + { + InnerReadToCRLF(null); + } + + private byte GetNextByte() + { + if (fFragmentOffset < fInitialFragment.Length) + { + return fInitialFragment[fFragmentOffset++]; + } + else + { + int received = fSocket.Receive(fSingleByte, 0, 1, SocketFlags.None); + if (received == 1) + { + return fSingleByte[0]; + } + else + { + throw new Exception("Connection closed unexpectedly"); + } + } + } + + private int MassRead(byte[] buffer, int offset, int maxLength) + { + if (fFragmentOffset < fInitialFragment.Length) + { + // Still data left in the original fragment; return as much + // of that as possible. + int initialFragmentLeft = fInitialFragment.Length - fFragmentOffset; + int amountToUse = maxLength <= initialFragmentLeft ? maxLength : initialFragmentLeft; + Buffer.BlockCopy(fInitialFragment, fFragmentOffset, buffer, offset, amountToUse); + fFragmentOffset += amountToUse; + return amountToUse; + } + else + { + // No data left in the initial fragment; read from the network. + return fSocket.Receive(buffer, offset, maxLength, SocketFlags.None); + } + } + } +} diff --git a/base/Applications/MapPointProxy/HttpResponse.cs b/base/Applications/MapPointProxy/HttpResponse.cs new file mode 100644 index 0000000..ca574f2 --- /dev/null +++ b/base/Applications/MapPointProxy/HttpResponse.cs @@ -0,0 +1,63 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +/////////////////////////////////////////////////////////////////////////////// + +using System.Collections.Specialized; + +public class HttpResponse +{ + private string fContentType; + private byte[] fBodyData; + private StringDictionary fHeaders; + private int fStatusCode; + + internal HttpResponse() + { + fHeaders = new StringDictionary(); + } + + public int ContentLength + { + get + { + if (fBodyData != null) + { + return fBodyData.Length; + } + else + { return 0; } + } + } + + public string ContentType + { + get { return fContentType; } + set { fContentType = value; } + } + + public byte[] BodyData + { + get { return fBodyData; } + set { fBodyData = value; } + } + + public int StatusCode + { + get { return fStatusCode; } + set { fStatusCode = value; } + } + + public string GetHeader(string! headerName) + { + return fHeaders[headerName.ToLower()]; + } + + public void AddHeader(string! headerName, string! headerValue) + { + fHeaders[headerName.ToLower()] = headerValue; + } +} diff --git a/base/Applications/MapPointProxy/MapPointProxy.csproj b/base/Applications/MapPointProxy/MapPointProxy.csproj new file mode 100644 index 0000000..49a79db --- /dev/null +++ b/base/Applications/MapPointProxy/MapPointProxy.csproj @@ -0,0 +1,43 @@ + + + + + + + Exe + MapPoint + true + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/base/Applications/MapPointProxy/MapPointProxy.sg b/base/Applications/MapPointProxy/MapPointProxy.sg new file mode 100644 index 0000000..cc9016a --- /dev/null +++ b/base/Applications/MapPointProxy/MapPointProxy.sg @@ -0,0 +1,325 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: MapPointProxy.sg +// +// Note: A simple proxy module for the MapPoint web service +// + +using System; +using System.Diagnostics; +using System.Text; +using System.Collections; +using Microsoft.SingSharp; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.MapPointProxy.Contracts; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Xml; +using System; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +using Microsoft.Singularity.Security; + +[assembly: Transform(typeof(ApplicationResourceTransform))] +[assembly: ApplicationPublisherAttribute("singularity.microsoft.com")] +[assembly: AssertPrivilegeAttribute("$register-privilege.localhost")] + +namespace Microsoft.Singularity.Applications +{ + [ConsoleCategory(HelpMessage="Mappoint proxy service", DefaultAction=true)] + internal class Parameters + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef nsRef; + + [StringParameter( "proxy", Mandatory=true, Position=0, HelpMessage="Proxy IP address")] + internal string ipAddress; + + reflective internal Parameters(); + + internal int AppMain() { + return MapPointProxy.AppMain(this); + } + } + + public class MapPointProxy + { + internal static int AppMain(Parameters! config) + { + string proxyHost = config.ipAddress; //null; //"172.31.40.21"; // msr-proxy + + // Configure proxy connection. + if (proxyHost != null) { + Console.WriteLine("MapPoint: HTTP Proxy: {0} port {1}", proxyHost, 80); + Console.WriteLine("MapPoint: Alternate proxy can be set on command line."); + HttpRequest.ConfigureProxy(proxyHost, 80); + } + else { + Console.WriteLine("MapPoint: No HTTP Proxy configured."); + Console.WriteLine("MapPoint: Proxy can be set on command line."); + } + + // Here is the channel we use to communicate with + // the NameServer + ServiceProviderContract.Imp! nsImp; + ServiceProviderContract.Exp! nsExp; + ServiceProviderContract.NewChannel(out nsImp, out nsExp); + + DirectoryServiceContract.Imp ds = config.nsRef.Acquire(); + if (ds == null) { + throw new Exception("Unable to acquire handle to the Directory Service root"); + } + ds.RecvSuccess(); + + try + { + ds.SendRegister(Bitter.FromString2(MapPointProxyContract.ModuleName), nsImp); + + switch receive + { + case ds.AckRegister() : + // All is well. + break; + + case ds.NakRegister(ServiceProviderContract.Imp:Start rejectedEP, error) : + // All is very much not well; abort. + Console.WriteLine("Failed to register the MapPoint proxy module as " + + MapPointProxyContract.ModuleName); + delete nsExp; + delete rejectedEP; + return -1; + + case ds.ChannelClosed(): + Console.WriteLine("epNS channel closed"); + delete nsExp; + return -1; + } + } + finally + { + delete ds; + } + + // Here is the set of client channels we service + ESet epSet = new ESet(); + + while(true) + { + switch receive + { + // ------------------------------- Requests for new connections + + case nsExp.Connect(ServiceContract.Exp:Start! newEp) : + { + // We expect people top give us MapPointProxyContract.Exp instances + MapPointProxyContract.Exp newMapClient = newEp as MapPointProxyContract.Exp; + + if (newMapClient == null) + { + // Invalid contract type. Fail. + nsExp.SendNackConnect(newEp); + } + else + { + // Signal ready and start servicing this contract + nsExp.SendAckConnect(); + newMapClient.SendMapPointReady(); + epSet.Add(newMapClient); + } + } + break; + + // ------------------------------- Requests on existing connections + // + // Don't forget that we're selecting endpoints + // from the epSet endpoint-set. In each case that we + // receive a message from one of those endpoints, we + // need to remember to put the endpoint back into epSet + // if we want to keep listening to it. + // + case ep.GetMap(char[]! in ExHeap centerLat, char[]! in ExHeap centerLong, + int zoom, MapPointProxyContract.PushPin[] in ExHeap pushPins) in epSet : + { + string! xml = BuildXml(centerLat, centerLong, zoom, pushPins); + + delete centerLat; + delete centerLong; + delete pushPins; + + string base64Data = GetBase64MapData(xml); + + if (base64Data != null) + { + ep.SendMapDataBegin(); + Base64Decoder decoder = new Base64Decoder(base64Data, 0); + byte[] chunk; + + while((chunk = decoder.Pump(base64Data.Length, 4096)) != null) + { + ep.SendMapDataChunk(Bitter.FromByteArray(chunk)); + ep.RecvAck(); + } + + ep.SendDone(); + } + else + { + ep.SendFailed(); + } + + epSet.Add(ep); + } + break; + + case nsExp.ChannelClosed() && epSet.Empty() : + // The namespace channel is closed and we have no more client + // channels, so pack up and go home. + delete nsExp; + epSet.Dispose(); + return -1; + + case ep.ChannelClosed() in epSet : + // Dispose of channels when our clients close them + delete ep; + break; + } + } + return 0; + } + + private static string GetIcon(ref MapPointProxyContract.PushPin pushPin) + { + expose(pushPin) + { + return Bitter.ToString(pushPin.icon); + } + } + + private static string GetLabel(ref MapPointProxyContract.PushPin pushPin) + { + expose(pushPin) + { + return Bitter.ToString(pushPin.label); + } + } + + private static string GetLatitude(ref MapPointProxyContract.PushPin pushPin) + { + expose(pushPin) + { + return Bitter.ToString(pushPin.latitude); + } + } + + private static string GetLongitude(ref MapPointProxyContract.PushPin pushPin) + { + expose(pushPin) + { + return Bitter.ToString(pushPin.longitude); + } + } + + private static string! BuildXml(char[]! in ExHeap centerLat, char[]! in ExHeap centerLong, + int zoom, MapPointProxyContract.PushPin[] in ExHeap pushPins) + { + string retval = "MapPoint.NADefaultColorDefaultColorDefaultColor50040000"; + + retval += zoom.ToString(); + retval += ""; + + if (pushPins != null) + { + for (int i = 0; i < pushPins.Length; ++i) + { + expose(pushPins[i]) { + MapPointProxyContract.PushPin pushPin = pushPins[i]; + retval += "MapPoint.Icons"; + + pushPin.UnExpose(); + string icon = GetIcon(ref pushPin); + string label = GetLabel(ref pushPin); + string latitude = GetLatitude(ref pushPin); + string longitude = GetLongitude(ref pushPin); + pushPin.Expose(); + pushPins[i] = pushPin; + + if (icon != null) + { + retval += icon; + } + + retval += ""; + retval += latitude; + retval += ""; + retval += longitude; + retval += "falsefalse"; + } + } + } + + retval += ""; + retval += Bitter.ToString2(centerLat); + retval += ""; + retval += Bitter.ToString2(centerLong); + retval += ""; + + return retval; + } + + private static string GetBase64MapData(string! xml) + { + HttpRequest request = new HttpRequest("http://renderv3.bay.staging.mappoint.net/Render-30/RenderService.asmx"); + + request.AddHeader("SOAPAction", "\"http://s.mappoint.net/mappoint-30/GetMap\""); + request.ContentType = "text/xml; charset=utf-8"; + request.RequestData = Encoding.ASCII.GetBytes(xml); + request.Method = "POST"; + + XmlNode bitsNode = null; + + try + { + HttpAuthenticator authenticator = new HttpAuthenticator(request, "7356", "0[[{NmN?UU5?U"); + HttpResponse! response = (!)authenticator.GetResponse(); + + XmlReader xmlReader = new XmlReader(); + ArrayList! nodes = (!)xmlReader.Parse(response.BodyData); + bitsNode = ((XmlNode!)nodes[0]).GetNestedChild(new string[]{"soap:Body", "GetMapResponse", "GetMapResult", "MapImage", "MimeData", "Bits"}); + } + catch(Exception) + { + // Ignore and return null + } + + if (bitsNode != null) + { + return bitsNode.Text; + } + else + { + return null; + } + } + } +} diff --git a/base/Applications/MapPointProxy/README.txt b/base/Applications/MapPointProxy/README.txt new file mode 100644 index 0000000..8c2b51e --- /dev/null +++ b/base/Applications/MapPointProxy/README.txt @@ -0,0 +1,66 @@ +From: Mark Aiken +Sent: Wednesday, September 14, 2005 8:29 PM +Subject: MapPoint (aka Caffeinate Me!) Demo instructions + +OK here’s a reprise of the demo instructions to make sure they’re up-to-date: + +Build steps (things that are not built by a normal “msb Distro\BVT.proj” at the root) +- Build Applications\Network +- Build Applications\WebApps +- Build Applications\Cassini [after building Applications\Webapps] +- Build Applications\MapPointProxy +- Build Applications\SeattleTrafficProxy +- Don’t forget msb the distro again to recreate the ISO + +Singularity machine setup: +- Be connected to the Internet. +- Mount the ISO image in the VPC cd-rom drive. + +Singularity runtime steps, with direct Internet access: + (type at the shell as shown) +- netstack & +- ipconfig /dev/nic0 dhcp start + [You should see a success message giving Singularity’s IP address] +- mappoint & +- seattletraffic & +- cassini /app:MapDemoWebApp + [You should see some startup spew from Cassini] + +Singularity runtime step, with http proxy: +- netstack & +- ipconfig /dev/nic0 dhcp start + [You should see a success message giving Singularity’s IP address] +- mappoint 157.54.58.20 & + [You should replace with address of http proxy, if not on corpnet] + [If the demo stalls after displaying "served /MapControl.js", it means + the mappoint proxy can't reach mappoint servers (possibly because you + have have the wrong http proxy.] +- seattletraffic & +- cassini /app:MapDemoWebApp [You should see some startup spew from Cassini] + +Client-side steps: + +- Open IE +- Make sure IE is configured correctly to reach the Internet; + the VE demos rely on IE being able to fetch image segments from the + Internet. +- Make sure IE is configured correctly to retrieve local content directly + from the Singularity box. +- Go to http://SingularitysIPAddressHere/ve.aspx for the Virtual Earth demo. + +Other notes: +- On some laptops with wireless, it work to boot with PXE assigned to the + wireless interface. This may have to do with MAC address spoofing being + unsupported over wireless. Use the wired connection instead. + +Disclaimers: +- Responses from the MapPoint staging servers are sometimes up to 15 seconds + or so in arriving. Obviously, this is unrelated to Singularity performance. + This manifests as a very noticeable delay in rendering the coffee-demo maps. +- I’ve seen the demos fall over in GC stack walks and in the memory allocator, + suggesting we still have heap-corruption issues. For best results, bring up + the Singularity machine fresh and present the demo right away to minimize + heap pressure. +- A good strategy is to start the VPC, then pause it (from the menu or by + typing right-alt-P), then resume it as you're ready to show the demo (from + the menu or by typing right-alt-P). diff --git a/base/Applications/More/More.cs b/base/Applications/More/More.cs new file mode 100644 index 0000000..223b1ce --- /dev/null +++ b/base/Applications/More/More.cs @@ -0,0 +1,283 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: More +// +// Note: A text pager contributed by Valerie See (vsee) +// + +using System; +using System.Collections; +using System.Diagnostics; +using System.IO; + +using Pipe = Microsoft.Singularity.Io.Tty2006; +using FileSystem.Utils; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; + +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Configuration; +using Microsoft.Singularity.Channels; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications +{ + [ConsoleCategory(HelpMessage="Display a screen full of text", DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef nsRef; + + [Endpoint] + public readonly TRef keyboardRef; + + [StringArrayParameter( "files", HelpMessage="Files to be listed.")] + internal string[] fileSet; + + reflective internal Parameters(); + + internal int AppMain() { + return More.AppMain(this); + } + } + + class More + { + internal static int pageCounter; + internal static Terminal! terminal; + internal static long fileSize; + internal static long bytesRead; + + internal static int GetKey(KeyboardDeviceContract.Imp! keyboard) + { + keyboard.SendGetKey(); + switch receive { + case keyboard.AckKey(ikey): + return (int) ikey; + break; + case keyboard.NakKey(): + return -1; + break; + case keyboard.ChannelClosed(): + Tracing.Log(Tracing.Debug, "Keyboard channel closed"); + return -1; + } + return -1; + } + + [ Conditional("DEBUG_MORE") ] + static void DebugPrint(string format, params object [] args) + { + DebugStub.Print(String.Format(format, args)); + } + + [ Conditional("DEBUG_MORE") ] + static void DebugWriteLine(string format, params object [] args) + { + DebugPrint(format, args); + DebugStub.Print("\n"); + } + + [ Conditional("DEBUG_MORE") ] + static void DebugReadLine() + { + Console.ReadLine(); + } + + internal static int AppMain(Parameters! config) { + // constants + + //int szLineCount = 0; + int displayfile = 0; + int consoleWidth = 0; + int consoleHeight = 0; + pageCounter = 0; + + terminal = new Terminal(); + + DirectoryServiceContract.Imp dsRoot = (config.nsRef).Acquire(); + if (dsRoot == null) { + throw new Exception("Unable to acquire handle to the Directory Service root"); + } + + dsRoot.RecvSuccess(); + + KeyboardDeviceContract.Imp keyboard = (config.keyboardRef).Acquire(); + if (dsRoot == null) { + throw new Exception("Unable to acquire handle to the keyboard"); + } + keyboard.RecvSuccess(); + + // FIXFIX need to dynamically get window size + consoleHeight = 47; // allow for "activity" line on top of Singularity console.... + consoleWidth = 79; + + assume config.fileSet != null; + string szSrcLine; + bool ok; + if (config.fileSet.Length <= 0 ) { + //stdin + while ( (szSrcLine = Console.ReadLine()) != null ) { + ok = PageText(szSrcLine, keyboard, consoleHeight, consoleWidth, true); + if (!ok) break; + } + delete keyboard; + delete dsRoot; + return 0; + } + + for (displayfile = 0; displayfile < config.fileSet.Length; displayfile++) { + string filename = config.fileSet[displayfile]; + if (filename == null) continue; + + // check that file exists + ErrorCode error; + NodeType nodeType; + ok = FileUtils.GetAttributes(filename, dsRoot, out fileSize, out nodeType, out error); + if (ok) { + if ( nodeType == NodeType.IoMemory || nodeType == NodeType.File ) { + // Open file RO for now + FileStream fsInput = new FileStream(dsRoot, filename, FileMode.Open, FileAccess.Read); + StreamReader srInput = new StreamReader(fsInput); + while ((szSrcLine = srInput.ReadLine()) != null) + { + ok = PageText(szSrcLine, keyboard, consoleHeight, consoleWidth, false); + if (!ok) break; + } + srInput.Close(); + fsInput.Close(); + + // Display the file by pages + // TODO: change PageText to return between pages so can recheck for + // screen dimension changes (?) + + if (displayfile <= config.fileSet.Length - 2) // offset by 2 due to index offset plus increment hasn't happened yet + { + Console.WriteLine(""); + Console.Write("-- for next file --"); + int key; + do { + key = Console.Read(); + if (key == -1) { + delete keyboard; + delete dsRoot; + return 0; + } + } while ((char)key != '\n'); + } + } + else if (nodeType == NodeType.Directory) { + // check that it's not a directory + Console.WriteLine("\n{0} - is a directory.", filename); + } + } // ok + else { + // not a directory, but file doesn't exist, print error message + Console.WriteLine("\n{0} - file not found.", filename); + } + } + delete keyboard; + delete dsRoot; + return 0; + } + + ////////////////////////////////////////////////////////////// + // Write out prompt and wait for input + // After acquiring the input remove the prompt from the console + ////////////////////////////////////////////////////////////// + + static int GetInput( KeyboardDeviceContract.Imp! keyboard, + int PAGELENGTH, bool processingStdin) + { + double temp = 0; + int counter = 0; + int key; + if (processingStdin) { + Console.Write("-- -- "); + key = GetKey(keyboard); + if ((char)key == '\n' ) Console.Write("\n"); + } else { + temp = (double) (bytesRead * 100) / (double)fileSize; + Console.Write("-- ({0}%) -- ", (int)temp ); + key = Console.Read(); + } + // get rid of the -- line + if ((char)key == '\n' ){ + terminal.GenerateAndSendEscapeSequence(Pipe.EscapeCodes.UP); + } + Console.Write("\r"); + terminal.GenerateAndSendEscapeSequence(Pipe.EscapeCodes.ERASE_FROM_CURSOR); + + if (key == -1) return -1; + switch (Char.ToLower((char)key )) { + case 'q': + return -1; + default: + if ((char)key == '\n') counter = PAGELENGTH ; // advance by 1 + break; + } + return counter; + } + + // PageText - display text a page at a time + static bool PageText(string! workString, KeyboardDeviceContract.Imp! keyboard, + int PAGELENGTH, int PAGEWIDTH, bool processingStdin) + { + string[] lines; + + int remainder = 0; + int linesinline = 0; + + // Split the line into the requisite number of lines + // needed based on page width + + if ( workString.Length <= PAGEWIDTH ) { + lines = new string[1]; + lines[0] = workString; + } + else { + int fullLines = workString.Length / PAGEWIDTH; + remainder = workString.Length % PAGEWIDTH; + linesinline = fullLines; + + if (remainder != 0) linesinline++; + lines = new string[linesinline]; + + int pos = 0; + for (int i=0; i < fullLines; i++) { + lines[i] = workString.Substring(pos,PAGEWIDTH); + pos += PAGEWIDTH; + } + if (remainder != 0) { + lines[fullLines] = workString.Substring(pos); + } + } + + // write the lines out pausing where necessary + for (int i=0; i < lines.Length; i++) { + string s = lines[i]; + assert s!= null; + Console.WriteLine(s); + pageCounter++; + bytesRead += s.Length; + if (pageCounter >= PAGELENGTH) { + pageCounter = GetInput(keyboard, PAGELENGTH, processingStdin); + if (pageCounter == -1) return false; + } + } + lines = null; + return true; + } // end of PageText + } +} diff --git a/base/Applications/More/More.csproj b/base/Applications/More/More.csproj new file mode 100644 index 0000000..f8e380a --- /dev/null +++ b/base/Applications/More/More.csproj @@ -0,0 +1,31 @@ + + + + + + + Exe + more + true + + + + + + + + + + + + + + diff --git a/base/Applications/More/readme.txt b/base/Applications/More/readme.txt new file mode 100644 index 0000000..a65f6b2 --- /dev/null +++ b/base/Applications/More/readme.txt @@ -0,0 +1,33 @@ +More - a simple pager + +Syntax: more [filename1 filename2 ... filenameN] + +Notes: + +This is a very simple version of more. At present, +it pages on the key (versus spacebar or +anything else). It will exit on the "q" or "Q" +followed by at the page prompt. Multiple +files can be given on the command line; however, +I have not implemented wildcard expansion, so +you do actually have to give it the real names +for now. + +It will provide error messages on files that are +not found or on directories (which in Singularity, +are acting like "files not found" - today, I have +left that as is). + +The console height and width are being treated as +fixed constants for now. Some obvious "to-dos" +include: + + TODO: Dynamically determine height/width + TODO: Recheck display size between pages + in case size has changed. (Lower pri). + TODO: Implement other functionality like + skipping forward in the file, moving + backward (a' la less), handle wild- + cards in filenames. + +5/9/2006 \ No newline at end of file diff --git a/base/Applications/NameSpace/AtomicTestDSP/AtomicTestDSP.csproj b/base/Applications/NameSpace/AtomicTestDSP/AtomicTestDSP.csproj new file mode 100644 index 0000000..3271fd2 --- /dev/null +++ b/base/Applications/NameSpace/AtomicTestDSP/AtomicTestDSP.csproj @@ -0,0 +1,45 @@ + + + + + + + Exe + AtomicTestDSP + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/base/Applications/NameSpace/AtomicTestDSP/DirAclCoreSupport.sg b/base/Applications/NameSpace/AtomicTestDSP/DirAclCoreSupport.sg new file mode 100644 index 0000000..2c86321 --- /dev/null +++ b/base/Applications/NameSpace/AtomicTestDSP/DirAclCoreSupport.sg @@ -0,0 +1,101 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: DirAclCoreSupport.sg +// +// Note: +// + +using System; +using System.Text; +using System.Threading; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Security; +using Microsoft.Singularity.Directory; + +namespace Microsoft.Singularity.Directory +{ + + public class DirAclCoreSupport : IAclCoreSupport + { + private UTF8Encoding! encoder = new UTF8Encoding(); + private TRef cachedRootNS = null; + + public string GetGroupContents(string! path) + { + // read the file size + if (cachedRootNS == null) + cachedRootNS = new TRef( + DirectoryService.NewClientEndpoint()); + DirectoryServiceContract.Imp:Ready! ns = cachedRootNS.Acquire(); + byte[] result = ReadFromFile(path, ns); + cachedRootNS.Release(ns); + if (result == null) + return null; + string! subexpression = (!)encoder.GetString(result); + return subexpression; + } + + private byte[] ReadFromFile(string!path, DirectoryServiceContract.Imp:Ready! ns) + { + ErrorCode errCode; + byte[] result; + long size = 0; + int readSize = 4096; + NodeType nodeType; + + try { + bool temp = SdsUtils.GetAttributes(path, ns, out size, out nodeType, out errCode); + if (! temp) + // element does not exist or an error has occurred + throw new Exception("Cannot get attributes - " + SdsUtils.ErrorCodeToString(errCode)); + result = new byte[size]; + byte[] in ExHeap buf = new[ExHeap] byte[readSize]; + if (result == null || buf == null) + throw new Exception("Cannot allocate memory"); + FileContract.Imp! fileImp; + FileContract.Exp! fileExp; + FileContract.NewChannel(out fileImp, out fileExp); + bool bindOk = SdsUtils.Bind(path, ns, fileExp, out errCode); + if (!bindOk) { + delete fileImp; + throw new Exception("Can't read group - " + SdsUtils.ErrorCodeToString(errCode)); + } + fileImp.RecvSuccess(); + + long readOffset = 0; + while (true) { + fileImp.SendRead(buf, 0, readOffset, readSize); + switch receive { + case fileImp.AckRead(localbuf, bytesRead, error) : + // move the memory + Bitter.ToByteArray(localbuf, 0, (int)bytesRead, result, (int)readOffset); + if (bytesRead == readSize) { + // see if there is more + readOffset += bytesRead; + buf = localbuf; + continue; + } + delete localbuf; + break; + case fileImp.ChannelClosed() : + break; + case unsatisfiable : + break; + } + break; + } + delete fileImp; + } catch (Exception e) { + DebugStub.Print("An exception occurred while reading group definition: {0}\n", + __arglist(path)); + DebugStub.Print("Message: {0}\n", __arglist(e.Message)); + return null; + } + return result; + } + } +} diff --git a/base/Applications/NameSpace/AtomicTestDSP/DirNode.sg b/base/Applications/NameSpace/AtomicTestDSP/DirNode.sg new file mode 100644 index 0000000..9d8a066 --- /dev/null +++ b/base/Applications/NameSpace/AtomicTestDSP/DirNode.sg @@ -0,0 +1,1162 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: DirNode.sg +// +// Note: [vjm] First "Atomic" version of the Nameserver. The +// atomic blocks have deliberately been made coarse because of +// the recursive nature of all functions. The recursive +// structure of functions means that the entire function body +// becomes a part of an atomic block on a recursive call. This +// means that simply "writing" a fine grained looking atomic +// block doesn't give us an actual fine-grain atomic block, the +// code essentially forces the atomic block to span across the +// entire function in the presence of recursion. The fine +// granularity might lead to smaller atomic blocks in the +// absence of recursion consequently leading to smaller windows +// of contention among concurrent transactions. +// +// Haven't atomized kernel version functions since that "might" +// lead to undesirable interactions with other kernel +// components. +// + +//#define BREAK_ON_FAILURE +//#define CHECK_TRAVERSE_ACCESS + +using System; +using System.Text; +using System.Collections; +using System.Threading; +using Microsoft.SingSharp; +using Microsoft.Singularity; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Security; + +#if !SINGULARITY_PROCESS +namespace Microsoft.Singularity.Directory +#else +using Microsoft.Singularity; +using Microsoft.Singularity.V1.Services; +namespace Microsoft.Application.DSP +#endif +{ +#if SINGULARITY_PROCESS + public class Kernel + { + public static void Waypoint(int num) + { + } + } +#endif + + public class DirNode : Node + { + public readonly SortedList! names; + private Hashtable! notificationList; + private StringBuilder sb; + + private Mutex! dirMutex; + + public void AcquireLock() + { + dirMutex.WaitOne(); + } + public void ReleaseLock() + { + dirMutex.ReleaseMutex(); + } + + public DirNode(string! name, Node! parent) + { + names = new SortedList(); + dirMutex = new Mutex(); + notificationList = new Hashtable(); + sb = new StringBuilder(256); + base(NodeType.Directory, name, parent); + } + + public DirNode(string! name, AclCore! core, IAclPolicy! policy) + { + names = new SortedList(); + dirMutex = new Mutex(); + notificationList = new Hashtable(); + sb = new StringBuilder(256); + base(NodeType.Directory, name, core, policy); + } + + /////////////////////////////////////////////////////////////////////////////// + // begin kernel only functions + /////////////////////////////////////////////////////////////////////////////// +#if !SINGULARITY_PROCESS + public bool CreateDirectory(string! name, out ErrorCode error) + { + error = ErrorCode.NoError; + bool success = false; + AcquireLock(); + if (names.ContainsKey(name)) { + success = false; + error = ErrorCode.AlreadyExists; + DebugStub.Break(); + ReleaseLock(); + return false; + } + else { + DirNode d = new DirNode(name, this); + Tracing.Log(Tracing.Debug,"createDir: parent="+name); + names.Add(name,d); + HandleNotification(name,NotifyType.Creation); + success = true; + } + ReleaseLock(); + return success; + } + + public bool CreateLink(string! name, string! val) + { + bool success = false; + AcquireLock(); + if (names.ContainsKey(name)) { + success = false; +#if BREAK_ON_FAILURE + DebugStub.Break(); +#endif + } + else { + SymLinkNode sym = new SymLinkNode(val, name, this); + names.Add(name,sym); + success = true; + } + ReleaseLock(); + + return success; + } + + public DirNode FindDirectory(StringBuilder! p) + { + /* + sb.Append("\nFindDirectory "); + sb.Append(SbUtils.PathString(p)); + sb.Append(" at dir "); + sb.Append(this.NodeName); + DebugStub.WriteLine(sb.ToString()); + Tracing.Log(Tracing.Debug,sb.ToString()); + */ + if (p.Length == 0) { + return this; + } + + string first = SbUtils.FirstElement(p); +/* + sb.Length = 0; + sb.Append(" findDir: p="); + sb.Append(p.ToString()); + sb.Append(" First="); + sb.Append(first); + DebugStub.WriteLine(sb.ToString()); +*/ + //DebugStub.Break(); + if (null == first) { + return null; + } + + Node n = (Node)this.names[first]; + if (null == n) { + return null; + } + p = SbUtils.RemoveFirstElement(p); +/* + sb.Length = 0; + sb.Append(" afterRemove: p="); + sb.Append(p.ToString()); + sb.Append(" First="); + sb.Append(first); + DebugStub.WriteLine(sb.ToString()); +*/ + if (n is DirNode) { + return ((DirNode) n).FindDirectory(p); + } + else { + //DebugStub.Break(); + return null; + } + } + + /// + /// Special kernel interface for adding in memory images to the namespace. + /// + public bool RegisterIoMemory(string! name, IoMemory! ioMemory) + { + Tracing.Log(Tracing.Debug,"RegisterIoMemory: "+name+" in "+name+" VA:{0} Len:{1}", + ioMemory.VirtualAddress, (UIntPtr)ioMemory.Length); + + if (ioMemory.VirtualAddress == UIntPtr.Zero) { + DebugStub.Break(); + } + bool success = false; + try { + this.AcquireLock(); + this.names.Add(name, new IoMemoryNode(ioMemory, name, this)); + success = true; //success + } + finally { + this.ReleaseLock(); + } + return success; + } +#endif + /////////////////////////////////////////////////////////////////////////////// + // end kernel only functions + /////////////////////////////////////////////////////////////////////////////// + + + public override bool GetAttributes(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link, + out long length, + out NodeType nodeType + ) + { + Kernel.Waypoint(3050); + + atomic { + reparse = false; + link = null; + length = 0; + linkFound = false; + error = ErrorCode.NoError; + nodeType = NodeType.BadNode; + + if (CheckEmpty(p)) { + + //the user wants the attributes of the directory object + Kernel.Waypoint(3051); + Kernel.Waypoint(3052); + //check read access for this object + if (!CheckAccess(DirPermissions.AccessModeRead, pr)) { + error = ErrorCode.AccessDenied; + return false; + } + nodeType = NodeType.Directory; + return true; + } + + // there is more path, continue processing + string first = SbUtils.FirstElement(p); + if (null == first) { + error = ErrorCode.NotFound; + return false; + } + + // can the caller traverse the current node? + Kernel.Waypoint(3052); +#if CHECK_TRAVERSE_ACCESS + if (!CheckAccess(DirPermissions.AccessModeTraverse, pr)) { + error = ErrorCode.AccessDenied; + Kernel.Waypoint(3053); + return false; + } +#endif + Kernel.Waypoint(3054); + Node n = (Node)this.names[first]; + if (null == n) { + error = ErrorCode.NotFound; + nodeType = NodeType.BadNode; + return false; + } + + p = SbUtils.RemoveFirstElement(p); + Kernel.Waypoint(3055); + bool ok = n.GetAttributes(p, + pr, + out linkFound, + out error, + out reparse, + out link, + out length, + out nodeType + ); + + Kernel.Waypoint(3056); + return ok; + } + + } + + private bool isMatch(string! name, string! pattern) + { + bool match = false; + bool continueMatch = true; + string prefix = null; + string postfix = null; + + int starPos = pattern.IndexOf("*"); + + if (starPos != -1) { + if (starPos == 0) { + prefix = null; + postfix = pattern.Substring(1); + } + else if (starPos == pattern.Length-1) { + prefix = pattern.Substring(0, pattern.Length-1); + postfix = null; + } + else { + prefix = pattern.Substring(0, starPos); + postfix = pattern.Substring(starPos+1); + } + + if (prefix != null) { + if (!name.StartsWith(prefix)) { + continueMatch = false; + } + } + if (continueMatch && postfix != null) { + if (!name.EndsWith(postfix)) { + continueMatch = false; + } + } + match = continueMatch; + } + else if (pattern == name) { + match = true; + } + + //DebugStub.WriteLine("name={0} pre={1} post={2} match={3}", + // __arglist(name, prefix, postfix, match)); + return match; + } + + public void HandleNotification(string! name, NotifyType type) + { + if (notificationList == null) { + return; + } + + foreach (DictionaryEntry n in notificationList) { + string pattern = (string!) n.Key; + bool match = isMatch (name,pattern); + + if (match) { + NotifyContract.Imp notifyEP = + ((TRef !) n.Value).Acquire(); + assert notifyEP.InState(NotifyContract.Notify.Value); + notifyEP.SendChangeNotification(Bitter.FromString2(name),type); + // should really be a switch receive + notifyEP.RecvAckChangeNotification(); + Tracing.Log(Tracing.Debug,"notifying: pattern="+pattern+" path="+name+" type="+type); + ((TRef !) n.Value).Release(notifyEP); + } + } //foreach + } + + + /// + /// null on success, the service argument if it failed. + /// + public override ServiceContract.Exp Bind(StringBuilder! p, + Principal pr, + out bool success, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link, + [Claims] ServiceContract.Exp! service) + { + Tracing.Log(Tracing.Debug, "bind "+ SbUtils.PathString(p)); + Kernel.Waypoint(3000); + + atomic { + success = false; + linkFound = false; + reparse = false; + link = null; + error = ErrorCode.NoError; + + if (CheckEmpty(p)) { + //the user wants to bind to a directory object in the namespace + Kernel.Waypoint(3001); + DirectoryServiceContract.Exp dirEP = service as DirectoryServiceContract.Exp; + Kernel.Waypoint(3002); + if (dirEP != null) { + // check Traverse access for both caller and supplied EP +#if CHECK_TRAVERSE_ACCESS + if (!CheckAccess(DirPermissions.AccessModeTraverse, pr, service)) { + DebugStub.WriteLine("No access to DirectoryService.Bind"); + Kernel.Waypoint(3003); + error = ErrorCode.AccessDenied; + return service; + } +#endif + //Tracing.Log(Tracing.Debug," found '/' starting dir worker"); + Kernel.Waypoint(3004); + + DirectoryServiceWorker.Create(this, dirEP); + + Kernel.Waypoint(3005); + success = true; + return null; + } + else { + error = ErrorCode.ContractNotSupported; + return service; + } + } + + Kernel.Waypoint(3006); + Node n = GetNextNode(p, pr, out error); + if (null == n) { + return service; + } + + Kernel.Waypoint(3009); + ServiceContract.Exp sp = n.Bind(p, + pr, + out success, + out linkFound, + out error, + out reparse, + out link, service); + Kernel.Waypoint(3010); + return sp; + } + } + + + public override ServiceProviderContract.Imp Register(StringBuilder! p, + Principal pr, + [Claims] ServiceProviderContract.Imp! sp, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + bool firstFound; + Node n; + +#if !SINGULARITY_PROCESS + Tracing.Log(Tracing.Debug,"({1:x8}) Register: path ={0}\n", + SbUtils.PathString(p),(UIntPtr)Kernel.AddressOf(Thread.CurrentThread)); +#endif + atomic { + reparse = false; + linkFound = false; + link = null; + error = ErrorCode.NoError; + + if (CheckEmpty(p) ) { + error = ErrorCode.NotFound; + return sp; + } + + if (SbUtils.IsTail(p)) { + string! name = (!)SbUtils.FirstElement(p); + if (names.ContainsKey(name)) { + error = ErrorCode.AlreadyExists; + return sp; + } + + // check register access for both caller and EP + else if (!CheckAccess(DirPermissions.AccessModeRegister, pr, sp)) { + error = ErrorCode.AccessDenied; + return sp; + } + else { + HandleNotification(name, NotifyType.Creation); + this.names.Add(name, new ProviderNode(sp, name, this)); + error = ErrorCode.NoError; + return null; + } + } + else { + n = GetNextNode(p, pr, out error); + if (n == null) { + return sp; + } + return n.Register(p, pr, sp, out linkFound, out error, out reparse, out link); + } + } + + } + + + /// + /// The endpoint on success, null, if it fails. + /// + public override ServiceProviderContract.Imp:Start Deregister(StringBuilder! p, + Principal pr, + DirectoryServiceContract.Exp! ep, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + + { + bool firstFound; + Node n; + +#if !SINGULARITY_PROCESS + Tracing.Log(Tracing.Debug,"({1:x8}) DeRegister: path ={0}\n", + SbUtils.PathString(p),(UIntPtr)Kernel.AddressOf(Thread.CurrentThread)); +#endif + atomic { + reparse = false; + linkFound = false; + link = null; + error = ErrorCode.NoError; + + if (CheckEmpty(p) ) { + error = ErrorCode.NotFound; + return null; + } + + if (SbUtils.IsTail(p)) { + string! name = (!)SbUtils.FirstElement(p); + if (!names.ContainsKey(name)) { + error = ErrorCode.NotFound; + return null; + } + // check deregister access of caller + else if (!CheckAccess(DirPermissions.AccessModeDeregister, pr)) { + error = ErrorCode.AccessDenied; + return null; + } + else { + HandleNotification(name, NotifyType.Deletion); + n = (Node) names[name]; + if (n != null && n is ProviderNode) { + ServiceProviderContract.Imp:Start sp = ((ProviderNode) n).GetServiceEndpoint(); + names.Remove(name); + error = ErrorCode.NoError; + return sp; + } + else { + error = ErrorCode.NotProvider; + return null; + } + } + } + else { + n = GetNextNode(p, pr, out error); + if (n == null) { + return null; + } + return n.Deregister(p, pr, ep, out linkFound, out error, out reparse, out link); + + } + } + return null; + } + + // Local Enumeration Records. We need this + // because we don't want to do ExHeap allocations in an + // atomic block (due to the resulting side effects) in + // the Enumerate() method below. + struct LocalEnumerationRecords + { + public string Path; + public NodeType Type; + } + + + /// + /// The a vector of vectors if success, null, if it fails. + /// + public EnumerationRecords[] in ExHeap Enumerate(Principal pr, out ErrorCode error) + { + error = ErrorCode.Unknown; + + // check read access for directory enumerate + if (!CheckAccess(DirPermissions.AccessModeRead, pr)) { + error = ErrorCode.AccessDenied; + return null; + } + + // store the enumeration in a local vector + // from within the atomic block, and after the + // atomic block succeeds copy the local vector to + // the ExHeap buffer that is used to send out the + // enumeration + EnumerationRecords[] in ExHeap responses; + + LocalEnumerationRecords[] localResponses; + + atomic { + error = ErrorCode.Unknown; + localResponses = new LocalEnumerationRecords[names.Count]; + + for (int i = 0; i < names.Count; i++){ + localResponses[i].Path = (!) (string)names.GetKey(i); + localResponses[i].Type = ((!) (Node)names.GetByIndex(i)).Type; + } + } + responses = new [ExHeap] EnumerationRecords[localResponses.Length]; + for(int i = 0; i < localResponses.Length; i++) { + expose (responses[i]) { + delete responses[i].Path; // checker doesn't know its null. + responses[i].Path = + Bitter.FromString2((!) localResponses[i].Path); + responses[i].Type = localResponses[i].Type; + } + } + + return responses; + } + + /// + /// true on success, false, if it fails. + /// + public override NotifyContract.Imp Notify(StringBuilder! path, + Principal pr, + string! pattern, + bool sendExisting, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link, + [Claims] NotifyContract.Imp! notifyImp) + { + //DebugStub.WriteLine(" dir Notify() sb.len={0}, s={1}",__arglist(pathSpec.Length,pathSpec.ToString())); + atomic { + error = ErrorCode.NoError; + linkFound = false; + reparse = false; + link = null; + + if (path.Length == 0) { + // got it! + DebugStub.Break(); + return notifyImp; + } + + if (SbUtils.IsTail(path)) { + string! first = (!)SbUtils.FirstElement(path); + + // check access: can the caller AND dest EP received notifications for this object + if (!CheckAccess(DirPermissions.AccessModeNotify, pr, notifyImp)) { + error = ErrorCode.AccessDenied; + return notifyImp; + } + notifyImp.SendBegin(); + TRef notifyEP = + new TRef (notifyImp); + + notificationList.Add(first,notifyEP); + Tracing.Log(Tracing.Debug,"notify: pattern="+first); + return null; + } + else { + // check access: can the caller traverse the current folder +#if CHECK_TRAVERSE_ACCESS + if (!CheckAccess(DirPermissions.AccessModeTraverse, pr)) { + error = ErrorCode.AccessDenied; + return notifyImp; + } +#endif + string first = SbUtils.FirstElement(path); + sb.Length = 0; + sb.Append(" dirnode Notify: str="); + sb.Append(path.ToString()); + sb.Append(" first = "); + sb.Append(first); + //DebugStub.WriteLine(sb.ToString()); + + Node n = (Node)this.names[first]; + if (null == n) { + DebugStub.Break(); + return notifyImp; + } + + path = SbUtils.RemoveFirstElement(path); + return n.Notify(path, pr, pattern, sendExisting, + out linkFound, out error, out reparse, out link, notifyImp); + } + + } + } + + public override FileContract.Imp CreateAndBindFile(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + linkFound = false; + error = ErrorCode.NotImplemented; + reparse = false; + link = null; + + return null; + } + + public override bool CreateDirectory(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + Node n; + + atomic { + linkFound = false; + reparse = false; + link = null; + error = ErrorCode.NoError; + + if (SbUtils.IsTail(p)) { + string! name = (!)SbUtils.FirstElement(p); + if (names.ContainsKey(name)) { + error = ErrorCode.AlreadyExists; + return false; + } + // check write access to parent + if (!CheckAccess(DirPermissions.AccessModeWrite, pr)) { + error = ErrorCode.AccessDenied; + return false; + } + else { + DirNode d = new DirNode(name, this); + Tracing.Log(Tracing.Debug,"createDir: parent="+name); + names.Add(name,d); + // not sure if this is needed + // here, maybe needed only for + // Registering and Deregistering + // services; hence commenting out + // the notification part + //HandleNotification(name, NotifyType.Creation); + return true; + } + } + else { + // pass the request on to the next node if there is one. + if (CheckEmpty(p)) { + error = ErrorCode.NotFound; + DebugStub.Break(); + return false; + } + n = GetNextNode(p, pr, out error); + if (n == null) { + return false; + } + return ((!)n).CreateDirectory(p, pr, out linkFound, out error, out reparse, out link); + + } + return false; + } + } + + public override bool CreateFile(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + Node n; + linkFound = false; + reparse = false; + link = null; + error = ErrorCode.NoError; + + // since the function implementation (commented out + // below) always returns a "false" value and does + // not update the system state, we'll simply return + // a "false" value here itself + return false; + + /* + if (SbUtils.IsTail(p)) { + // true files are not supported in the namespace + error = ErrorCode.NotImplemented; + return false; + } + else { + // pass the request on to the next node if there is one. + if (CheckEmpty(p)) { + error = ErrorCode.NotImplemented; + return false; + } + n = GetNextNode(p, pr, out error); + if (n == null) { + return false; + } + return ((!)n).CreateFile(p, pr, out linkFound, out error, out reparse, out link); + + } + return false; + */ + } + + private bool CheckEmpty(StringBuilder! p) + { + if ( (p.Length == 0) || ( (p.Length == 1 ) && (p[0] == '/') ) ) { + return true; + } + return false; + } + + private Node GetNextNode(StringBuilder! p, Principal pr, out ErrorCode error) + { + //DebugStub.Break(); + string first = SbUtils.FirstElement(p); + error = ErrorCode.NoError; + if (null == first) { + return null; + } + + Kernel.Waypoint(3006); +#if CHECK_TRAVERSE_ACCESS + if (!CheckAccess(DirPermissions.AccessModeTraverse, pr)) { + Kernel.Waypoint(3007); + error = ErrorCode.AccessDenied; + return null; + } +#endif + Kernel.Waypoint(3008); + + Node n = (Node)this.names[first]; + if (null == n) { + error = ErrorCode.NotFound; + return null; + } + + SbUtils.RemoveFirstElement(p); + return n; + } + + public override bool CreateLink(StringBuilder! p, + Principal pr, + string! value, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + Node n; + atomic { + linkFound = false; + link = null; + reparse = false; + error = ErrorCode.NoError; + + if (SbUtils.IsTail(p)) { + string! name = (!)SbUtils.FirstElement(p); + if (names.ContainsKey(name)) { + error = ErrorCode.AlreadyExists; + return false; + } + // check write access to parent + else if (!CheckAccess(DirPermissions.AccessModeWrite, pr)) { + error = ErrorCode.AccessDenied; + return false; + } + else { + SymLinkNode sym = new SymLinkNode(value, name, this); + names.Add(name,sym); + return true; + } + } + else { //recurse + if (CheckEmpty(p)) { + error = ErrorCode.NotFound; + return false; + } + n = GetNextNode(p, pr, out error); + if (n == null) { + return false; + } + return ((!)n).CreateLink(p, pr, value, out linkFound, out error, out reparse, out link); + } + } + } + + public override bool DeleteDirectory(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + Node n; + + DirNode child; + + atomic { + linkFound = false; + reparse = false; + link = null; + error = ErrorCode.NotFound; + if (CheckEmpty(p)) { + return false; + } + + + if (SbUtils.IsTail(p)) { + string! name = (!)SbUtils.FirstElement(p); + if (names.ContainsKey(name)) { + // check to see if this node has entries + // if so let the caller know + n = GetNextNode(p, pr, out error); + if (n == null) { + return false; + } + if (n is DirNode) { + child = (DirNode) n; + if (child.names.Count != 0) { + DebugStub.WriteLine("Directory is not empty({0})!", __arglist(child.names.Count)); + error = ErrorCode.DirectoryNotEmpty; + return false; + } + // check write access to parent + else if (!CheckAccess(DirPermissions.AccessModeWrite, pr)) { + error = ErrorCode.AccessDenied; + return false; + } + // check write access to child + else if (!n.CheckAccess(DirPermissions.AccessModeWrite, pr)) { + error = ErrorCode.AccessDenied; + return false; + } + } + else { + error = ErrorCode.NotDirectory; + return false; + } + + error = ErrorCode.NoError; + names.Remove(name); + return true; + } + else { + return false; + } + } + + n = GetNextNode(p, pr, out error); + if (n == null) { + linkFound = false; + reparse = false; + link = null; + return false; + } + return ((!)n).DeleteDirectory(p, pr, out linkFound, out error, out reparse, out link); + + } + } + + public override bool DeleteFile(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + Node n; + linkFound = false; + reparse = false; + link = null; + error = ErrorCode.NotFound; + + // since the function implementation (commented out + // below) always returns a "false" value and does + // not update the system state, we'll simply return + // a "false" value here itself + return false; + + /* + if (CheckEmpty(p)) { + error = ErrorCode.NotFound; + return false; + } + if (SbUtils.IsTail(p)) { + string! name = (!)SbUtils.FirstElement(p); + if (names.ContainsKey(name)) { + // check write access to parent + if (!CheckAccess(DirPermissions.AccessModeWrite, pr)) { + error = ErrorCode.AccessDenied; + return false; + } + // continue on to actual node for deletion + } + else { + return false; + } + } + + n = GetNextNode(p, pr, out error); + if (n == null) { + return false; + } + return ((!)n).DeleteFile(p, pr, out linkFound, out error, out reparse, out link); + */ + } + + public override bool DeleteLink(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + + + { + Node n; + + //DebugStub.Break(); + + atomic { + linkFound = false; + reparse = false; + link = null; + error = ErrorCode.NotFound; + if (CheckEmpty(p)) { + return false; + } + + if (SbUtils.IsTail(p)) { + string! name = (!)SbUtils.FirstElement(p); + if (names.ContainsKey(name)) { + //check write access to parent + if (!CheckAccess(DirPermissions.AccessModeWrite, pr)) { + error = ErrorCode.AccessDenied; + return false; + } + error = ErrorCode.NoError; + // this should check whether the node is a link! + names.Remove(name); + return true; + } + else { + return false; + } + } + + n = GetNextNode(p, pr, out error); + if (n == null) { + linkFound = false; + reparse = false; + link = null; + return false; + } + return ((!)n).DeleteLink(p, pr, out linkFound, out error, out reparse, out link); + } + } + + public override bool GetLinkValue(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + + { + Node n; + + atomic { + error = ErrorCode.NotLink; + linkFound = false; + reparse = false; + link = null; + + //DebugStub.Break(); + if (CheckEmpty(p)) { + return false; + } + + n = GetNextNode(p, pr, out error); + if (n == null) { + return false; + } + return ((!)n).GetLinkValue(p, pr, out linkFound, out error, out reparse, out link); + } + } + + + public override bool QueryACL(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link, + out Acl acl + ) + { + Node n; + + acl = new Acl(); + + atomic { + error = ErrorCode.NoError; + linkFound = false; + reparse = false; + link = null; + if (CheckEmpty(p)) { + if (CheckAccess(DirPermissions.AccessModeRead, pr)) { + error = ErrorCode.AccessDenied; + return false; + } + acl = this.GetInstanceAcl(); + return true; + } + n = GetNextNode(p, pr, out error); + if (n == null) { + return false; + } + return ((!)n).QueryACL(p, pr, out linkFound, out error, out reparse, out link, out acl); + } + } + + public override bool StoreACL(StringBuilder! p, + Principal pr, + Acl acl, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + Node n; + + atomic { + linkFound = false; + reparse = false; + link = null; + error = ErrorCode.NoError; + + if (CheckEmpty(p)) { + if (!CheckAccess(DirPermissions.AccessModeSetAcl, pr)) { + error = ErrorCode.AccessDenied; + return false; + } + SetInstanceAcl(acl); + return true; + } + n = GetNextNode(p, pr, out error); + if (n == null) { + return false; + } + return ((!)n).StoreACL(p, pr, acl, out linkFound, out error, out reparse, out link); + } + } + } +} diff --git a/base/Applications/NameSpace/AtomicTestDSP/DirPermissions.sg b/base/Applications/NameSpace/AtomicTestDSP/DirPermissions.sg new file mode 100644 index 0000000..764a2a4 --- /dev/null +++ b/base/Applications/NameSpace/AtomicTestDSP/DirPermissions.sg @@ -0,0 +1,42 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: DirPermissions.sg +// +// Note: +// + +using Microsoft.Singularity.Security; + +#if !SINGULARITY_PROCESS +namespace Microsoft.Singularity.Directory +#else +namespace Microsoft.Application.DSP +#endif + +{ + public class DirPermissions + { + public static readonly AccessMode AccessModeTraverse; // can pass through + public static readonly AccessMode AccessModeRead; // can read/enumerate + public static readonly AccessMode AccessModeWrite; // can create/write an object + public static readonly AccessMode AccessModeSetAcl; // can modify access control + public static readonly AccessMode AccessModeRegister; // can register + public static readonly AccessMode AccessModeDeregister; // can deregister + public static readonly AccessMode AccessModeNotify; // can receive notifications + + static DirPermissions() { + AccessModeTraverse = new AccessMode("traverse"); + AccessModeRead = new AccessMode("read"); + AccessModeWrite = new AccessMode("write"); + AccessModeSetAcl = new AccessMode("setacl"); + AccessModeRegister = new AccessMode("register"); + AccessModeDeregister = new AccessMode("deregister"); + AccessModeNotify = new AccessMode("notify"); + } + } +} + + diff --git a/base/Applications/NameSpace/AtomicTestDSP/DirectoryService.sg b/base/Applications/NameSpace/AtomicTestDSP/DirectoryService.sg new file mode 100644 index 0000000..4a0c2f4 --- /dev/null +++ b/base/Applications/NameSpace/AtomicTestDSP/DirectoryService.sg @@ -0,0 +1,212 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Directory.sg +// +// Note: +// + +using System; +using System.Threading; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.SingSharp; +using Microsoft.SingSharp.Runtime; +using Microsoft.Singularity.Directory; + +using Microsoft.Singularity.Security; +[assembly: ApplicationPublisherAttribute("singularity.microsoft.com")] +[assembly: AssertPrivilegeAttribute("$register-privilege.localhost")] + +namespace Microsoft.Application.DSP +{ + public class NameServiceDSP + { + + private static DirNode rootDir; + private static string mountPoint; + + private static int Register(string! name, [Claims]ServiceProviderContract.Imp! imp) + { + // acquire namespace endpoint + DirectoryServiceContract.Imp epNS = DirectoryService.NewClientEndpoint(); + mountPoint = name; + + try { + epNS.SendRegister(Bitter.FromString2(name),imp); + switch receive { + case epNS.AckRegister(): + break; + case epNS.NakRegister(reject, error): + DebugStub.Break(); + delete reject; + return -1; + break; + case epNS.ChannelClosed(): + DebugStub.Break(); + return -1; + break; + case epNS.NakRegisterReparse(char[]! in ExHeap path, + char[]! in ExHeap rest, + bool linkFound, + ServiceProviderContract.Imp:Start! reject) : + DebugStub.Break(); + delete reject; + delete path; + delete rest; + return -1; + break; + case unsatisfiable: + Tracing.Log(Tracing.Debug,"unable to register NakConnect with Nameservice\n"); + DebugStub.Break(); + return -1; + } + } + finally { + delete epNS; + } + + return 0; + } + + private static int Deregister(string! name) + { + // acquire namespace endpoint + DirectoryServiceContract.Imp epNS = DirectoryService.NewClientEndpoint(); + mountPoint = name; + + try { + epNS.SendDeregister(Bitter.FromString2(name)); + switch receive { + case epNS.AckDeregister(service): + delete service; + break; + case epNS.NakDeregister(error): + DebugStub.Break(); + break; + case epNS.ChannelClosed(): + DebugStub.Break(); + break; + case unsatisfiable: + Tracing.Log(Tracing.Debug,"unable to register NakConnect with Nameservice\n"); + DebugStub.Break(); + return -1; + } + } + finally { + delete epNS; + } + + return 0; + } + + public static void Initialize() + { + IAclPolicy _policy = new PathPolicyEngine(); + InstallAcls(_policy); + AclCore _core = new AclCore(null, new DirAclCoreSupport()); + _core.Disable = true; + rootDir = new DirNode("/", _core, _policy); + } + + + // in the fullness of time, we should read the server configuration + // from a reified manifest including config information + // for now, we will just add a rule to allow **any** access + private static void InstallAcls(IAclPolicy! policy) + { + /* + // read the rules section from the config + XmlNode node = config.GetChild(PolicyListXmlTag); + if (node == null) { + return; + } + + foreach (XmlNode! rule in node.Children) { + if (rule.Name != "rule") { + continue; + } + + string! resource = (!)rule.GetAttribute("resource", ""); + if (resource.Equals("")) { + continue; + } + string! aclstr = (!)rule.GetAttribute("acl", ""); + if (aclstr.Equals("")) { + continue; + } + + policy.AddRule(resource, aclstr); + } + */ + policy.AddRule("/", "{/groups/anyall}"); + } + + public static void Finalize() + { + Deregister(mountPoint); + } + + public static void tell(string name) + { + Console.WriteLine("{0}: ", name); + } + + public static int Main(string[]! args) + { + int status; + Initialize(); + + if (args.Length < 2) { + tell(args[0]); + return -1; + } + + ServiceProviderContract.Imp! imp; + ServiceProviderContract.Exp! s; + ServiceProviderContract.NewChannel(out imp, out s); + status = Register((!)args[1], imp); + + if (status != 0) { + delete s; + return status; + } + + try { + for (bool run = true; run;) { + switch receive { + // Listen for new connections + case s.Connect(ServiceContract.Exp:Start! candidate): + DirectoryServiceContract.Exp:Start exp = candidate as DirectoryServiceContract.Exp:Start!; + if (exp != null) { + s.SendAckConnect(); + DirectoryServiceWorker.Create(rootDir,exp); + } + else s.SendNackConnect(candidate); + break; + case s.ChannelClosed() : + run = false; + Console.WriteLine("Channel Closed. DSP shutting down"); + break; + case unsatisfiable: + run = false; + Console.WriteLine("Unsatisfiable. DSP shutting down"); + break; + } + } + } + finally { + } + delete s; + Console.WriteLine(" last line of DSP... process should terminate"); + return 0; + } + } +} + + + + diff --git a/base/Applications/NameSpace/AtomicTestDSP/DirectoryServiceWorker.sg b/base/Applications/NameSpace/AtomicTestDSP/DirectoryServiceWorker.sg new file mode 100644 index 0000000..8e26b02 --- /dev/null +++ b/base/Applications/NameSpace/AtomicTestDSP/DirectoryServiceWorker.sg @@ -0,0 +1,193 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: DirectoryServiceWorker.sg +// +// Note: +// + +using System; +using System.Text; +using System.Collections; +using System.Runtime.Remoting; +using System.Runtime.InteropServices; +using System.Threading; +using Microsoft.SingSharp; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Security; +using Microsoft.Singularity.Directory.WorkerFunctions; + +#if !SINGULARITY_PROCESS +namespace Microsoft.Singularity.Directory +#else +using Microsoft.Singularity; +using Microsoft.Singularity.V1.Services; +namespace Microsoft.Application.DSP +#endif +{ + using SharedHeap = Microsoft.Singularity.Memory.SharedHeap; + + class DirectoryServiceWorker + { + private TRef epRef; + private DirNode dirNode; + + private DirectoryServiceWorker(DirNode dirNode, + [Claims] DirectoryServiceContract.Exp:Start! i_ep) + requires i_ep.InState(DirectoryServiceContract.Start.Value); + { + epRef = new TRef(i_ep); + this.dirNode = dirNode; + base(); + } + + private void Start() + { +#if !SINGULARITY_PROCESS + Thread thread = Thread.CreateThread(DirectoryService.processForWorkerThreads, + new ThreadStart(Run)); +#else + Thread thread = new Thread (new ThreadStart(Run)); +#endif + + if (thread != null) { + thread.Start(); + } + } + + public static void Create(DirNode dirNode, + [Claims] DirectoryServiceContract.Exp:Start! i_ep) + { + // + // We need to do some trickery to pass the ownership of i_ep to + // the thread that will run the worker. + // We are currently working on behalf of some user process, but + // the worker thread will be a kernel thread. + // The transfer has to happen after we released the i_ep into the TRef + // but before we acquire the TRef. This is because the Release and Acquire + // operations actually cause the endpoint to be dereferenced and that + // must happen by the correct owner. + + // The TRef implementation in the kernel now takes care of this. + + DirectoryServiceWorker worker; + + worker = new DirectoryServiceWorker(dirNode, i_ep); + + // Now start the worker, which will acquire the endpoint in the TRef. + worker.Start(); + } + + private void Run() + { + bool success; + int code; + char* opt(ExHeap[]) path; +#if !SINGULARITY_PROCESS + Tracing.Log(Tracing.Debug,"new thread={0:x8}",(UIntPtr)Kernel.AddressOf(Thread.CurrentThread)); +#endif + DirectoryServiceContract.Exp ep = epRef.Acquire(); + + epRef = null; + + ep.SendSuccess(); + try { + for (bool run = true; run;) { + switch receive { + case ep.Bind(i_path, i_server) : + WorkerFunctions.DoBind(dirNode, ep, i_path, i_server); + break; + + case ep.BeginEnumeration() : + WorkerFunctions.DoEnumerate(dirNode, ep); + break; + + case ep.GetAttributes( char []! in ExHeap i_path) : + WorkerFunctions.DoGetAttributes(dirNode, ep, i_path); + break; + + case ep.ReadEnumeration() : + WorkerFunctions.DoMore(dirNode, ep); + break; + + case ep.Notify(i_path, i_pattern, i_sendExisting, i_notifyImp): + WorkerFunctions.DoNotify(dirNode, ep,i_path, i_pattern, i_sendExisting, i_notifyImp); + break; + + case ep.Register(i_path, i_provider): + WorkerFunctions.DoRegister(dirNode, ep, i_path, i_provider); + break; + + case ep.EndEnumeration() : + WorkerFunctions.DoStop(dirNode, ep); + break; + + case ep.Deregister(i_path): + WorkerFunctions.DoDeregister(dirNode, ep, i_path); + break; + + case ep.CreateDirectory(i_name) : + WorkerFunctions.DoCreateDirectory(dirNode, ep,i_name); + break; + + case ep.DeleteDirectory(i_name) : + WorkerFunctions.DoDeleteDirectory(dirNode, ep,i_name); + break; + + case ep.CreateFile( char []! in ExHeap i_name) : + WorkerFunctions.DoCreateFile(dirNode, ep,i_name); + break; + + case ep.DeleteFile(i_name): + WorkerFunctions.DoDeleteFile(dirNode, ep,i_name); + break; + + case ep.QueryACL(char[]! in ExHeap i_name): + WorkerFunctions.DoQueryACL(dirNode, ep, i_name); + break; + + case ep.StoreACL(char[]! in ExHeap i_name, char[] in ExHeap acl): + WorkerFunctions.DoStoreACL(dirNode, ep, i_name, acl); + break; + + case ep.CreateAndBindFile(char []! in ExHeap i_name, FileContract.Imp:Ready! imp) : + WorkerFunctions.DoCreateAndBindFile(dirNode, ep, i_name, imp); + break; + + case ep.CreateLink(i_name,i_value) : + WorkerFunctions.DoCreateLink(dirNode, ep,i_name, i_value); + break; + + case ep.DeleteLink(i_name): + WorkerFunctions.DoDeleteLink(dirNode, ep,i_name); + break; + + case ep.GetLinkValue(i_name): + WorkerFunctions.DoGetLinkValue(dirNode, ep,i_name); + break; + + case ep.ChannelClosed(): +#if SINGULARITY_PROCESS + //DebugStub.WriteLine("SDSWorker Thread shutting down"); +#endif + run = false; + break; + + case unsatisfiable: + DebugStub.Print("NameServiceWorker shutting down\n"); + DebugStub.Break(); + run = false; + break; + }//switch + } //for + } //try + finally { + delete ep; + } + } //run + } //DirectoryServiceWorker class +} //namespace diff --git a/base/Applications/NameSpace/AtomicTestDSP/IoMemoryNode.sg b/base/Applications/NameSpace/AtomicTestDSP/IoMemoryNode.sg new file mode 100644 index 0000000..2e75acc --- /dev/null +++ b/base/Applications/NameSpace/AtomicTestDSP/IoMemoryNode.sg @@ -0,0 +1,377 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: IoMemoryNode.sg +// +// Note: internal node type used to support IoMemory images +// + +using System; +using System.Text; +using System.Collections; +using System.Threading; +using Microsoft.SingSharp; +using Microsoft.Singularity; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Security; + +#if !SINGULARITY_PROCESS +namespace Microsoft.Singularity.Directory +#else +using Microsoft.Singularity; +using Microsoft.Singularity.V1.Services; +namespace Microsoft.Application.DSP +#endif +{ + + public class IoMemoryNode : Node + { + public IoMemory ioMemory; + + public IoMemoryNode(IoMemory ioMem, string! name, Node! parent) + { + this.ioMemory = ioMem; + base(NodeType.IoMemory, name, parent); + } + + /// + /// null on success, the service argument if it failed. + /// + public override ServiceContract.Exp Bind(StringBuilder! p, + Principal pr, + out bool success, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link, + [Claims] + ServiceContract.Exp! service) + { + Kernel.Waypoint(3200); + reparse = false; + link = null; + success = false; + linkFound = false; + + if (! (p.Length == 0) ){ + error = ErrorCode.NotFound; + return service; + } + + // The FileContract needs to be subdivided into Read and Write, then + // we can determine which permissions to use here. For now, it must + // be the case that all uses (if any) of IoMemory objects in the file system + // are read-only. [EPW] + if (!CheckAccess(DirPermissions.AccessModeRead, pr, service)) { + DebugStub.WriteLine("No access to IoMemoryNode.Bind"); + error = ErrorCode.AccessDenied; + return service; + } + +#if !SINGULARITY_PROCESS + Tracing.Log(Tracing.Debug, "Starting stream IoMemory writer"); + + //send a bind message to the IoMemory FS with the endpoint and the cookie as args. + FileContract.Exp:Start fp = service as FileContract.Exp; + if (fp == null) { + success = false; + error = ErrorCode.ContractNotSupported; + return service; + } + + Kernel.Waypoint(3201); + + IoMemFSContract.Imp:Ready io = Directory.DirectoryService.AcquireIoFS(); + if (io != null) { + Kernel.Waypoint(3202); + io.SendConnect(fp, (UIntPtr)ioMemory.VirtualAddress, ioMemory.Length); + Kernel.Waypoint(3203); + io.RecvAckConnect(); + Kernel.Waypoint(3204); + Directory.DirectoryService.ReleaseIoFS(io); + success = true; + } + else { + DebugStub.Break(); + delete fp; + success = false; + } + Kernel.Waypoint(3205); + error = ErrorCode.NoError; + return null; +#endif + error = ErrorCode.NotImplemented; + return service; + } + + /// + /// null on success, the sp argument if it failed. + /// + public override ServiceProviderContract.Imp Register(StringBuilder! p, + Principal pr, + [Claims]ServiceProviderContract.Imp! sp, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + // cannot register over an existing provider + reparse = false; + linkFound = false; + link = null; + error = ErrorCode.NotSupported; + return sp; + } + + /// + /// The endpoint on success, null, if it fails. + /// + public override ServiceProviderContract.Imp:Start Deregister(StringBuilder! path, + Principal pr, + DirectoryServiceContract.Exp! ep, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + + { + link = null; + linkFound = false; + reparse = false; + error = ErrorCode.NotSupported; + if (! (path.Length == 0) ) { + return null; + } + + // we are being removed + // the remove will fail! + + // if we ever allow deregister of IoMemoryNode + // do not forget to add an access control check. + return null; + } + + + /// + /// if true returns length and node type, otherwise error + /// + public override bool GetAttributes(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link, + out long length, + out NodeType nodeType + ) + { + linkFound = false; + reparse = false; + link = null; + error = ErrorCode.NoError; + nodeType = NodeType.IoMemory; + length = ioMemory.Length; + return true; + } + + + /// + /// null on success, the imp argument if it failed. + /// + public override NotifyContract.Imp Notify(StringBuilder! pathSpec, + Principal pr, + string! pattern, + bool sendExisting, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link, + [Claims] NotifyContract.Imp! notifyImp) + { + // this method should never be called + error = ErrorCode.NotSupported; + reparse = false; + link = null; + linkFound = false; + return notifyImp; + } + + public override FileContract.Imp CreateAndBindFile(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + linkFound = false; + error = ErrorCode.NotImplemented; + reparse = false; + link = null; + + return null; + } + + public override bool CreateDirectory(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + linkFound = false; + error = ErrorCode.NotImplemented; + reparse = false; + link = null; + + return false; + } + public override bool CreateFile(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + linkFound = false; + error = ErrorCode.NotImplemented; + reparse = false; + link = null; + + return false; + } + + public override bool CreateLink(StringBuilder! p, + Principal pr, + string! value, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + linkFound = false; + error = ErrorCode.NotImplemented; + reparse = false; + link = null; + + return false; + } + public override bool DeleteDirectory(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + linkFound = false; + error = ErrorCode.NotImplemented; + reparse = false; + link = null; + + return false; + } + public override bool DeleteFile(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + linkFound = false; + error = ErrorCode.NotImplemented; + reparse = false; + link = null; + + return false; + } + public override bool DeleteLink(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + + { + linkFound = false; + error = ErrorCode.NotImplemented; + reparse = false; + link = null; + return false; + } + + public override bool GetLinkValue(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + + { + linkFound = false; + error = ErrorCode.NotLink; + reparse = false; + link = null; + return false; + } + + public override bool QueryACL(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link, + out Acl acl + ) + { + linkFound = false; + error = ErrorCode.NoError; + reparse = false; + link = null; + acl = new Acl(); + + if (CheckAccess(DirPermissions.AccessModeRead, pr)) { + error = ErrorCode.AccessDenied; + return false; + } + acl = GetInstanceAcl(); + return true; + } + + public override bool StoreACL(StringBuilder! p, + Principal pr, + Acl acl, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + linkFound = false; + error = ErrorCode.NoError; + reparse = false; + link = null; + + if (!CheckAccess(DirPermissions.AccessModeSetAcl, pr)) { + error = ErrorCode.AccessDenied; + return false; + } + + SetInstanceAcl(acl); + return true; + } + } +} diff --git a/base/Applications/NameSpace/AtomicTestDSP/Node.sg b/base/Applications/NameSpace/AtomicTestDSP/Node.sg new file mode 100644 index 0000000..cd124f5 --- /dev/null +++ b/base/Applications/NameSpace/AtomicTestDSP/Node.sg @@ -0,0 +1,314 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Node.sg +// +// Note: +// + +using System; +using System.Text; +using System.Collections; +using System.Threading; +using Microsoft.SingSharp; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Security; + +#if !SINGULARITY_PROCESS +namespace Microsoft.Singularity.Directory +#else +using Microsoft.Singularity; +using Microsoft.Singularity.V1.Services; +namespace Microsoft.Application.DSP +#endif +{ + public abstract class Node + { + // base class for all node types in name space + + private string nodeName; + + /// + /// The policy object controlling the access to this node + /// + private AclCore! core; + private IAclPolicy! policy; + /// + + /// ACLs here are not persistent. + /// + private Acl acl = Acl.nullAcl; + private IAclRule rule = null; + + private readonly NodeType nodeType; + + protected Node(NodeType nodeType, string! name, AclCore! core, IAclPolicy! policy) + { + this.nodeType = nodeType; + this.nodeName = name; + this.core = core; + this.policy = policy; + } + + protected Node(NodeType nodeType, string! name, Node! parent) + { + this.nodeType = nodeType; + this.nodeName = parent.nodeName + "/" + name; + this.core = parent.core; + this.policy = parent.policy; + } + + private Acl GetObjectAcl() + { + lock (this) { + if (acl.val != null) { + if (rule == null || rule.Valid) + return acl; + } + acl = policy.LookupAndExpand(nodeName, out rule); + return acl; + } + } + + public bool CheckAccess(AccessMode! permission, Principal pr) + { + Acl acl = GetObjectAcl(); + return core.CheckAccess(acl, permission, pr); + } + + public bool CheckAccess(AccessMode! permission, Principal pr, Endpoint*! in ExHeap ep) + { + Acl acl = GetObjectAcl(); + if (!core.CheckAccess(acl, permission, pr)) + return false; + Principal pr2 = AclCore.EndpointPeer(ep); + if (pr.Equal(pr2)) + return true; + return core.CheckAccess(acl, permission, AclCore.EndpointPeer(ep)); + } + + public Acl GetInstanceAcl() + { + lock (this) { + if (rule == null) + return acl; + } + return Acl.nullAcl; + } + + public void SetInstanceAcl(Acl acl) + { + lock (this) { + this.acl = acl; + this.rule = null; + } + } + + public string! FullName { get { return nodeName; } } + + /// + /// null on success, the service argument if it failed. + /// + public abstract ServiceContract.Exp Bind(StringBuilder! p, + Principal pr, + out bool success, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link, + [Claims] + ServiceContract.Exp! service); + + + /// CreateAndBindFile + /// + /// true if success false if it fails. + /// + public abstract FileContract.Imp CreateAndBindFile(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ); + + /// CreateDirectory + /// + /// true if success false if it fails. + /// + public abstract bool CreateDirectory(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ); + + /// CreateFile + /// + /// true if success false if it fails. + /// + public abstract bool CreateFile(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ); + + /// CreateFile + /// + /// true if success false if it fails. + /// + public abstract bool CreateLink(StringBuilder! p, + Principal pr, + string! value, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ); + /// DeleteDirectory + /// + /// true if success false if it fails. + /// + public abstract bool DeleteDirectory(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ); + /// DeleteFileusing Microsoft.SingSharp; + + /// + /// true if success false if it fails. + /// + public abstract bool DeleteFile(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ); + + /// DeleteLink + /// + /// true if success false if it fails. + /// + public abstract bool DeleteLink(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ); + + + /// GetLinkValue + /// + /// true if success false if it fails. + /// + public abstract bool GetLinkValue(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ); + + /// + /// The endpoint on success, null, if it fails. + /// + public abstract ServiceProviderContract.Imp:Start Deregister(StringBuilder! path, + Principal pr, + DirectoryServiceContract.Exp! ep, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ); + + + /// + /// true if success false if it fails. + /// + public abstract bool GetAttributes(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link, + out long length, + out NodeType nodeType + ); + + + + /// + /// null on success, the imp argument if it failed. + /// + public abstract NotifyContract.Imp Notify(StringBuilder! pathSpec, + Principal pr, + string! pattern, + bool sendExisting, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link, + [Claims] NotifyContract.Imp! notifyImp); + + /// QueryACL + /// + /// true if success false if it fails. + /// + public abstract bool QueryACL(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link, + out Acl acl + ); + + + /// Register + /// + /// true if success false if it fails. + /// + public abstract ServiceProviderContract.Imp Register(StringBuilder! p, + Principal pr, + [Claims]ServiceProviderContract.Imp! sp, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ); + + /// StoreACL + /// + /// true if success false if it fails. + /// + public abstract bool StoreACL(StringBuilder! p, + Principal pr, + Acl acl, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ); + + + public NodeType Type + { + get + { + return this.nodeType; + } + } + } +} diff --git a/base/Applications/NameSpace/AtomicTestDSP/Path.sg b/base/Applications/NameSpace/AtomicTestDSP/Path.sg new file mode 100644 index 0000000..8997e32 --- /dev/null +++ b/base/Applications/NameSpace/AtomicTestDSP/Path.sg @@ -0,0 +1,84 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Nameserver.cs +// +// Note: +// + +using System; +using System.Collections; +using System.Runtime.Remoting; +using System.Runtime.InteropServices; +using System.Threading; +using Microsoft.SingSharp; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; + +#if !SINGULARITY_PROCESS +namespace Microsoft.Singularity.Directory +#else +namespace Microsoft.Application.DSP +#endif +{ + public class Path + { + ArrayList elts; + + public Path(String! s) + { + string[] sa = s.Split("/".ToCharArray()); + ArrayList elts = this.elts = new ArrayList(sa); + elts.RemoveAt(0); // since paths start with a slash, the first one will be empty + } + + public bool Empty { get { return this.elts.Count == 0; } } + + public int Length() + { + return elts.Count; + } + + public String StripLast() + { + int pos = elts.Count - 1; + String s = (String)elts[pos]; + elts.RemoveAt(pos); + return s; + } + + public void Append(String elt) + { + elts.Add(elt); + } + + public String FirstElement() + { + return (String)elts[0]; + } + + public void RemoveFirstElement() + { + elts.RemoveAt(0); + } + + public String! PathString() + { + String result = ""; + IEnumerator e = elts.GetEnumerator(); + while (e.MoveNext()) { + result += "/" + e.Current; + } + return result; + } + + public char[]! in ExHeap PathVector() + { + String result = PathString(); + return Bitter.FromString2(result); + } + } +} diff --git a/base/Applications/NameSpace/AtomicTestDSP/Property.sg b/base/Applications/NameSpace/AtomicTestDSP/Property.sg new file mode 100644 index 0000000..e0f8ee1 --- /dev/null +++ b/base/Applications/NameSpace/AtomicTestDSP/Property.sg @@ -0,0 +1,43 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// + +#if !SINGULARITY_PROCESS +namespace Microsoft.Singularity.Directory +#else +namespace Microsoft.Application.DSP +#endif +{ + public class Property + { + private string name; + private byte[] value; + + public Property(string! name, byte[]! value) + { + this.name = name; + this.value = value; + } + + public string! Name + { + get + { + return (!)name; + } + } + + public byte[]! Value + { + get + { + return (!)value; + } + set + { + this.value = value; + } + } + } +} diff --git a/base/Applications/NameSpace/AtomicTestDSP/ProviderNode.sg b/base/Applications/NameSpace/AtomicTestDSP/ProviderNode.sg new file mode 100644 index 0000000..bca13b5 --- /dev/null +++ b/base/Applications/NameSpace/AtomicTestDSP/ProviderNode.sg @@ -0,0 +1,458 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Directory.sg +// +// Note: +// + +using System; +using System.Text; +using System.Collections; +using System.Threading; +using Microsoft.SingSharp; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Security; + +#if !SINGULARITY_PROCESS +namespace Microsoft.Singularity.Directory +#else +namespace Microsoft.Application.DSP +#endif +{ + // Although there currently are none, there might need to be access control + // checks at Bind time. Certainly, the Bind target can do an access check, + // but the Bind intermediary, here, might also make a check. See the discussion + // below. + + public class ProviderNode : Node + { + public TRef! ServiceEndpoint; + private bool isDead; + + public ProviderNode([Claims] ServiceProviderContract.Imp! imp, string! name, Node! parent) + requires imp.InState(ServiceProviderContract.Start.Value); + { + ServiceEndpoint = new TRef(imp); + isDead = false; + base(NodeType.ServiceProvider, name, parent); + } + + public ServiceProviderContract.Imp:Start! GetServiceEndpoint() { + return this.ServiceEndpoint.Acquire(); + } + + /// + /// null on success, the service argument if it failed. + /// + public override ServiceContract.Exp Bind(StringBuilder! p, + Principal pr, + out bool success, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link, + [Claims] + ServiceContract.Exp! service) + { + Kernel.Waypoint(3100); + + reparse = false; + link = null; + success = false; + linkFound = false; + + if (p.Length != 0) { + if ( (p.Length == 1) && (p[0] == '/') ) { + // pass thru if it is just the delimiter character. + } + else { + // we have hit a non-leaf service provider + // send back a reparse message + error = ErrorCode.NotFound; + reparse = true; + link = p.ToString(); + return service; + } + } + + // There continues to be an inconsistency here with access control. + // We might do the access control here on Bind, in which case we know + // the caller. However, if we require the access control operation + // to be done on the other side of the Connect operation, then that + // code doesn't see the original invoker and moreover there is no + // appropriate AccessDenied failure on Connect. + + // It seems a little weird to put access controls on the provider + // node, since such node are transient, but that is perhaps what we + // should do. + + // If we decide to do ACL checks here, figure out how to get the + // permissions from the service endpoint!! No access check here until we do. + + /* + if (!CheckNodeAccess(???, pr, service)) { + DebugStub.WriteLine("No access to bind"); + error = ErrorCode.AccessDenied; + return service; + } + */ + + lock (this) { + Kernel.Waypoint(3101); + if (isDead) { + success = false; + error = ErrorCode.NotFound; + return service; + } + + ServiceProviderContract.Imp ep = this.ServiceEndpoint.Acquire(); + assert ep.InState(ServiceProviderContract.Start.Value); + Tracing.Log(Tracing.Debug, "Connecting to Service Provider"); + try { + ep.SendConnect(service); + switch receive { + case ep.AckConnect(): + success = true; + error = ErrorCode.NoError; + return null; + case ep.NackConnect(rejectedEP): + Tracing.Log(Tracing.Debug,"nak connect "); + // REVIEW what should be returned here? + error = ErrorCode.ContractNotSupported; + return rejectedEP; + case ep.ChannelClosed(): + Tracing.Log(Tracing.Debug,"channel closed"); + // make this a zombie node + isDead = true; + error = ErrorCode.ChannelClosed; + success = false; + return null; + case unsatisfiable: + Tracing.Log(Tracing.Debug,"Unsatisfiable!!"); + error = ErrorCode.Unsatisfiable; + success = false; + return null; + } + } + finally { + this.ServiceEndpoint.Release(ep); + } + Kernel.Waypoint(3102); + } // lock on node + } + + /// + /// null on success, the sp argument if it failed. + /// + public override ServiceProviderContract.Imp Register(StringBuilder! p, + Principal pr, + [Claims]ServiceProviderContract.Imp! sp, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + if (p.Length != 0) { + if ( (p.Length == 1) && (p[0] == '/') ) { + // pass thru if it is just the delimiter character. + } + else { + // we have hit a non-leaf service provider + // send back a reparse message + error = ErrorCode.Unknown; + reparse = true; + linkFound = false; + link = p.ToString(); + return sp; + } + } + + // cannot register over an existing provider + reparse = false; + linkFound = false; + link = null; + error = ErrorCode.NotSupported; + return sp; + } + + /// + /// The endpoint on success, null, if it fails. + /// + public override ServiceProviderContract.Imp:Start Deregister(StringBuilder! p, + Principal pr, + DirectoryServiceContract.Exp! ep, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + + { + link = null; + linkFound = false; + reparse = false; + + if (p.Length != 0) { + if ( (p.Length == 1) && (p[0] == '/') ) { + // pass thru if it is just the delimiter character. + } + else { + // we have hit a non-leaf service provider + // send back a reparse message + error = ErrorCode.Unknown; + reparse = true; + linkFound = false; + link = p.ToString(); + return null; + } + } + + // Add the following access check on Deregister pursuant on the + // discussion about access controls on providers above. + /* + if (!CheckNodeAccess(DirPermissions.AccessModeDeregister, pr, ep)){ + error = ErrorCode.AccessDenied; + return null; + } + */ + + // we are being removed + error = ErrorCode.NoError; + return this.ServiceEndpoint.Acquire(); + } + + + /// + /// if true returns length and node type, otherwise error + /// + public override bool GetAttributes(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link, + out long length, + out NodeType nodeType + ) + { + + if (p.Length != 0) { + if ( (p.Length == 1) && (p[0] == '/') ) { + // pass thru if it is just the delimiter character. + } + else { + // we have hit a non-leaf service provider + // send back a reparse message + error = ErrorCode.Unknown; + reparse = true; + linkFound = false; + length = 0; + link = p.ToString(); + nodeType = NodeType.ServiceProvider; + return false; + } + } + + linkFound = false; + reparse = false; + link = p.ToString(); + nodeType = NodeType.ServiceProvider; + length = 0; + error = ErrorCode.Unknown; + return true; + } + + + /// + /// null on success, the imp argument if it failed. + /// + public override NotifyContract.Imp Notify(StringBuilder! p, + Principal pr, + string! pattern, + bool sendExisting, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link, + [Claims] NotifyContract.Imp! notifyImp) + { + linkFound = false; + error = ErrorCode.NotImplemented; + reparse = false; + link = null; + + if (p.Length != 0) { + if ( (p.Length == 1) && (p[0] == '/') ) { + // pass thru if it is just the delimiter character. + } + else { + // we have hit a non-leaf service provider + // send back a reparse message + error = ErrorCode.Unknown; + reparse = true; + linkFound = false; + link = p.ToString(); + return notifyImp; + } + } + return notifyImp; + } + + public override FileContract.Imp CreateAndBindFile(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + linkFound = false; + error = ErrorCode.NotImplemented; + reparse = false; + link = null; + + return null; + } + + private bool CheckForTraverse (StringBuilder! p, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + linkFound = false; + error = ErrorCode.Unknown; + reparse = false; + link = null; + + if (p.Length != 0) { + if ( (p.Length == 1) && (p[0] == '/') ){ + // pass thru if it is just the delimiter character. + } + else { + // we have hit a non-leaf service provider + // send back a reparse message + error = ErrorCode.NoError; + reparse = true; + linkFound = false; + link = p.ToString(); + if (p[0] == '/') link = link.Substring(1); + return false; + } + } + return false; + + } + + public override bool CreateDirectory(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + return CheckForTraverse(p, out linkFound, out error, out reparse, out link); + } + + public override bool CreateFile(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + return CheckForTraverse(p, out linkFound, out error, out reparse, out link); + } + + public override bool CreateLink(StringBuilder! p, + Principal pr, + string! value, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + return CheckForTraverse(p, out linkFound, out error, out reparse, out link); + } + public override bool DeleteDirectory(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + return CheckForTraverse(p, out linkFound, out error, out reparse, out link); + } + public override bool DeleteFile(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + return CheckForTraverse(p, out linkFound, out error, out reparse, out link); + } + public override bool DeleteLink(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + + { + return CheckForTraverse(p, out linkFound, out error, out reparse, out link); + } + + public override bool GetLinkValue(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + + { + return CheckForTraverse(p, out linkFound, out error, out reparse, out link); + } + + + public override bool QueryACL(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link, + out Acl acl + ) + { + acl = new Acl(); + return CheckForTraverse(p, out linkFound, out error, out reparse, out link); + } + + public override bool StoreACL(StringBuilder! p, + Principal pr, + Acl acl, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + return CheckForTraverse(p, out linkFound, out error, out reparse, out link); + } + } +} diff --git a/base/Applications/NameSpace/AtomicTestDSP/ResolutionState.sg b/base/Applications/NameSpace/AtomicTestDSP/ResolutionState.sg new file mode 100644 index 0000000..0cd0860 --- /dev/null +++ b/base/Applications/NameSpace/AtomicTestDSP/ResolutionState.sg @@ -0,0 +1,50 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// + +#if !SINGULARITY_PROCESS +namespace Microsoft.Singularity.Directory +#else +namespace Microsoft.Application.DSP +#endif +{ + using System; + + /// + /// This class contains state accumulated during the resolution + /// of a namespace path. + /// + public class ResolutionState + { + /// + /// what we have resolved so far (modulo the current namespace provider) + /// + private string resolved; + + public ResolutionState() + { + resolved = "/"; + } + + public void UpdateResolved(string! current) + { + if (current.StartsWith("/") || resolved.EndsWith("/")) + { + resolved = resolved + current; + } + else + { + resolved = resolved + "/" + current; + } + } + + public string! Resolved + { + get + { + return (!)resolved; + } + } + } +} diff --git a/base/Applications/NameSpace/AtomicTestDSP/SbUtils.sg b/base/Applications/NameSpace/AtomicTestDSP/SbUtils.sg new file mode 100644 index 0000000..f1629ba --- /dev/null +++ b/base/Applications/NameSpace/AtomicTestDSP/SbUtils.sg @@ -0,0 +1,156 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: SbUtils.cs +// StringBuilder Utility Class +// Note: +// + +using System; +using System.Text; +using Microsoft.Singularity.Channels; + +#if !SINGULARITY_PROCESS +namespace Microsoft.Singularity.Directory +#else +using Microsoft.Singularity; +using Microsoft.Singularity.V1.Services; +namespace Microsoft.Application.DSP +#endif +{ + public class SbUtils + { + private const char delimiter = '/'; + + public static bool IsTail(StringBuilder! sb) + { + if (sb.Length <= 1) return false; + int pos = IndexOf(sb,delimiter,1); + if (pos == -1) return true; + return false; + } + public static int IndexOf (StringBuilder! sb, char theChar, int startPos) + { + if (sb.Length == 0) return 0; + for (int i = startPos ; i < sb.Length; i++) { + if (sb[i] == theChar) return i; + } + return -1; + } + + public static int LastIndexOf (StringBuilder! sb, char theChar, int startPos) + { + if (sb.Length == 0) return 0; + for (int i = sb.Length ; i > startPos+1 ; i--) { + if (sb[i-1] == theChar) return i; + } + return -1; + } + + public static bool Empty (StringBuilder! sb) + { + if ( sb.Length > 0) { + return true; + } + else { + return false; + } + } + + public int Length(StringBuilder! sb) + { + return sb.Length; + } + + public static StringBuilder! StripLast(StringBuilder! sb) + { + int pos = LastIndexOf(sb,delimiter,0); + if ( (pos+1) < sb.Length ) { + sb.Length = pos-1; + } + else { + sb.Length = 0; + } + return sb; + } + + + public static StringBuilder! RemoveFirstElement(StringBuilder! sb) + { + return StripFirst(sb); + } + + public static StringBuilder! StripFirst(StringBuilder! sb) + { + if ( sb[0] == delimiter){ + int pos = IndexOf(sb, delimiter,1); // just in case it starts with '/' + if ( (pos >= 0) && (pos < sb.Length ) ) { + sb.Remove(0,pos); + return sb; + } + sb.Length = 0; + return sb; + } + else { + int pos = IndexOf(sb,delimiter,0); // just in case it starts with '/' + if ( (pos >= 0) && (pos < sb.Length ) ){ + sb.Remove(0,pos); + return sb; + } + sb.Length = 0; + return sb; + } + } + + public static void Append(StringBuilder! sb, String! elt) + { + sb.Append(elt); + } + + // Return a st + // + public static String FirstElement(StringBuilder! sb) + { + if (sb.Length == 0) return null; + + if ( sb[0] == delimiter){ + int pos = IndexOf(sb,delimiter,1); + + // DebugStub.WriteLine(" FindFirst:pos={0},len={1},s={2}",__arglist(pos,sb.Length,sb.ToString())); + //DebugStub.Break(); + if (pos == -1) { + if (sb.Length == 1) return null; // just the delimiter + return sb.ToString(1,sb.Length-1); + } + if ( (pos > 1) && (pos < sb.Length ) ) { + return sb.ToString(1,pos-1); + } + return null; + } + else { + int pos = IndexOf(sb,delimiter,0); + if (pos == -1) { + return sb.ToString(); + } + if ( (pos < sb.Length) && (pos > 0) ){ + return sb.ToString(0,pos); + } + return null; + } + } + + public static String PathString(StringBuilder! sb) + { + if (sb.Length == 0 ) return null; + return sb.ToString(); + } + + public static char[]! in ExHeap PathVector(StringBuilder! sb) + { + return Bitter.FromString2(sb.ToString()); + } + } +} diff --git a/base/Applications/NameSpace/AtomicTestDSP/SymLinkNode.sg b/base/Applications/NameSpace/AtomicTestDSP/SymLinkNode.sg new file mode 100644 index 0000000..48b6aea --- /dev/null +++ b/base/Applications/NameSpace/AtomicTestDSP/SymLinkNode.sg @@ -0,0 +1,373 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: SymLinkNode.sg +// +// Note: +// + +using System; +using System.Text; +using System.Collections; +using System.Threading; +using Microsoft.SingSharp; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Security; + +#if !SINGULARITY_PROCESS +namespace Microsoft.Singularity.Directory +#else +using Microsoft.Singularity; +using Microsoft.Singularity.V1.Services; +namespace Microsoft.Application.DSP +#endif +{ + // There are no access checks on symbolic links. + // In order to read a link, traverse access to the parent is sufficient. + // Although one might think that read access to the parent would be more + // appropriate here, the nature of the DirectoryService protocol allows anyone + // traversing a link to find the link value, hence there is no benefit to + // making "reading" of a link more strict. + + public class SymLinkNode : Node + { + private string symbolicLink; + + public SymLinkNode(string value, string! name, Node! parent) + { + symbolicLink = value; + base(NodeType.SymLink, name, parent); + } + + /// + /// null on success, the service argument if it failed. + /// + public override ServiceContract.Exp Bind(StringBuilder! p, + Principal pr, + out bool success, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link, + [Claims] + ServiceContract.Exp! service) + { + Kernel.Waypoint(3500); + reparse = true; + success = true; + linkFound = true; + error = ErrorCode.NoError; + + if (! (p.Length == 0)) + link = symbolicLink + SbUtils.PathString(p); + else + link = symbolicLink; + Kernel.Waypoint(3501); + return service; + } + + /// + /// null on success, the sp argument if it failed. + /// + public override ServiceProviderContract.Imp Register(StringBuilder! p, + Principal pr, + [Claims]ServiceProviderContract.Imp! sp, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + // cannot register over an existing name + reparse = false; + linkFound = false; + link = null; + error = ErrorCode.AlreadyExists; + return sp; + } + + /// + /// The endpoint on success, null, if it fails. + /// + public override ServiceProviderContract.Imp:Start Deregister(StringBuilder! path, + Principal pr, + DirectoryServiceContract.Exp! ep, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + + { + error = ErrorCode.NotSupported; + link = null; + linkFound = false; + reparse = false; + if (!(path.Length == 0) ) { + return null; + } + + // cannot be removed + return null; + } + + /// + /// if true returns length and node type, otherwise error + /// + public override bool GetAttributes(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link, + out long length, + out NodeType nodeType + ) + { + Kernel.Waypoint(3700); + reparse = true; + linkFound = true; + length = 0; + nodeType = NodeType.SymLink; + error = ErrorCode.NoError; + + // this is a traverse operation. There is more left on the path + if (! (p.Length == 0)) { + link = symbolicLink + SbUtils.PathString(p); + return false; + } + + // stop here + reparse = false; + link = symbolicLink; + Kernel.Waypoint(3701); + return true; + } + + /// + /// true on success, false, if it fails. + /// + public override NotifyContract.Imp Notify(StringBuilder! pathSpec, + Principal pr, + string! pattern, + bool sendExisting, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link, + [Claims] NotifyContract.Imp! notifyImp) + { + // this method should never be called + error = ErrorCode.NotSupported; + reparse = false; + link = symbolicLink; + linkFound = true; + return notifyImp; + } + + public override FileContract.Imp CreateAndBindFile(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + linkFound = false; + error = ErrorCode.NotImplemented; + reparse = false; + link = null; + + return null; + } + + public override bool CreateDirectory(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + //DebugStub.Break(); + reparse = true; + linkFound = true; + link = null; + error = ErrorCode.NoError; + + if (! (p.Length == 0) ) + link = symbolicLink + SbUtils.PathString(p); + else + link = symbolicLink ; + + return false; + } + public override bool CreateFile(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + linkFound = false; + error = ErrorCode.NotImplemented; + reparse = false; + link = null; + + return false; + } + + public override bool CreateLink(StringBuilder! p, + Principal pr, + string! value, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + reparse = true; + linkFound = true; + error = ErrorCode.NoError; + + if (! (p.Length == 0) ) + link = symbolicLink + SbUtils.PathString(p); + else + link = symbolicLink ; + return false; + } + + public override bool DeleteDirectory(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + reparse = true; + linkFound = true; + error = ErrorCode.NoError; + + if (! (p.Length == 0) ) { + link = symbolicLink + SbUtils.PathString(p); + return false; + } + + link = symbolicLink ; + error = ErrorCode.NotDirectory; + reparse = false; + return false; + } + + public override bool DeleteFile(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + reparse = true; + linkFound = true; + error = ErrorCode.NoError; + + if (! (p.Length == 0) ) + link = symbolicLink + SbUtils.PathString(p); + else + link = symbolicLink ; + return false; + } + + public override bool DeleteLink(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + + { + reparse = true; + linkFound = true; + error = ErrorCode.NoError; + + if (! (p.Length == 0) ) + link = symbolicLink + SbUtils.PathString(p); + else + link = symbolicLink ; + return false; + } + + public override bool GetLinkValue(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + + { + reparse = true; + linkFound = true; + error = ErrorCode.NoError; + + // this is a traverse operation + if (! (p.Length == 0) ) { + link = symbolicLink + SbUtils.PathString(p); + return false; + } + link = symbolicLink; + return true; + } + + public override bool QueryACL(StringBuilder! p, + Principal pr, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link, + out Acl acl + ) + { + reparse = true; + linkFound = true; + error = ErrorCode.NoError; + reparse = true; + acl = new Acl(); + + if (! (p.Length == 0)) + link = symbolicLink + SbUtils.PathString(p); + else + link = symbolicLink; + return false; + } + + public override bool StoreACL(StringBuilder! p, + Principal pr, + Acl acl, + out bool linkFound, + out ErrorCode error, + out bool reparse, + out string link + ) + { + reparse = true; + linkFound = true; + error = ErrorCode.NoError; + + if (! (p.Length == 0)) + link = symbolicLink + SbUtils.PathString(p); + else + link = symbolicLink; + return false; + } + + } +} diff --git a/base/Applications/NameSpace/AtomicTestDSP/WorkerFunctions.sg b/base/Applications/NameSpace/AtomicTestDSP/WorkerFunctions.sg new file mode 100644 index 0000000..0a105a6 --- /dev/null +++ b/base/Applications/NameSpace/AtomicTestDSP/WorkerFunctions.sg @@ -0,0 +1,1203 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: WorkerFunctions.sg +// +// Note: +// + +using System; +using System.Text; +using System.Collections; +using System.Runtime.Remoting; +using System.Runtime.InteropServices; +using System.Threading; +using Microsoft.SingSharp; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Security; + +#if !SINGULARITY_PROCESS +namespace Microsoft.Singularity.Directory +#else +using Microsoft.Singularity; +using Microsoft.Singularity.V1.Services; +namespace Microsoft.Application.DSP +#endif +{ + using SharedHeap = Microsoft.Singularity.Memory.SharedHeap; + + class WorkerFunctions + { + + //------------------------------------------------------------------------------------ + // Worker functions for DirectoryServiceWorker loop + //------------------------------------------------------------------------------------ + + public static void DoDeregister(Node! dir, + DirectoryServiceContract.Exp! ep , + [Claims] char[]! in ExHeap i_path) + { + ErrorCode error; + bool reparse; + bool linkFound; + string link; + string prefix; + Char[] in ExHeap exPrefix; + Char[] in ExHeap exSuffix; + string pathCopy = Bitter.ToString2(i_path); + Principal pr = AclCore.EndpointPeer(ep); + + try { + ServiceProviderContract.Imp:Start service = + dir.Deregister(new StringBuilder (Bitter.ToString2(i_path)), + pr, + ep, + out linkFound, out error, out reparse, out link); + + if (service != null) { + ep.SendAckDeregister(service); + Tracing.Log(Tracing.Debug,"Register success"); + delete i_path; + return; + } + + if (reparse) { + if (null == link) { + ep.SendNakDeregister(ErrorCode.Unknown); + } + else { + if (linkFound) { + Tracing.Log(Tracing.Debug,"reparsing {0} as link",link); + exPrefix = Bitter.FromString2(link); + exSuffix = Bitter.FromString2(""); + ep.SendNakDeregisterReparse(exPrefix, exSuffix, linkFound); + } + else { + // need to construct prefix from original path + int prefixIndex = pathCopy.IndexOf(link); + if (-1 == prefixIndex) { + exSuffix = null; + exPrefix = null; + DebugStub.Break(); + ep.SendNakDeregister(ErrorCode.Unknown); + } + else { + if (prefixIndex == 0) prefix = pathCopy; + else prefix = pathCopy.Substring(0,prefixIndex); + + exPrefix = Bitter.FromString2(prefix); + exSuffix = Bitter.FromString2(link); + ep.SendNakDeregisterReparse(exPrefix, + exSuffix, + linkFound + ); + } + } + } + } //reparse + else { + //DebugStub.Break(); + ep.SendNakDeregister(error); + } + + } + catch (Exception e) { + DebugStub.Print(" Exception {0}\n", __arglist(e.ToString())); + } + delete i_path; + } + + //------------------------------------------------------------------------------------ + // Directory Enumeration + //------------------------------------------------------------------------------------ + public static void DoEnumerate(DirNode! dir, + DirectoryServiceContract.Exp! ep + ) + { + ErrorCode error; + Principal pr = AclCore.EndpointPeer(ep); + EnumerationRecords[] in ExHeap results = + dir.Enumerate(pr, out error); + if (results == null) ep.SendEnumerationTerminated(ErrorCode.InsufficientResources); + else ep.SendEnumerationEntries(results, false); + } + + public static void DoMore(DirNode! dir, + DirectoryServiceContract.Exp! ep + ) + { + + ep.SendEnumerationTerminated(ErrorCode.NotImplemented); + } + + public static void DoStop(DirNode! dir, + DirectoryServiceContract.Exp! ep + ) + { + + } + + //------------------------------------------------------------------------------------ + //------------------------------------------------------------------------------------ + public static void DoRegister(DirNode! dir, + DirectoryServiceContract.Exp! ep , + [Claims] char[]! in ExHeap i_path, + [Claims] ServiceProviderContract.Imp:Start! i_provider + ) + { + ErrorCode error; + bool reparse; + bool linkFound; + string link; + string prefix; + Char[] in ExHeap exPrefix; + Char[] in ExHeap exSuffix; + string pathCopy = Bitter.ToString2(i_path); + Principal pr = AclCore.EndpointPeer(ep); + + ServiceProviderContract.Imp reject = null; + try { + Tracing.Log(Tracing.Debug," Register started"); + reject = dir.Register(new StringBuilder(Bitter.ToString2(i_path)), + pr, + i_provider, + out linkFound, out error, out reparse, out link); + + Tracing.Log(Tracing.Debug,"Register: linkFound={0}, reparse={1}", + linkFound ? (UIntPtr) 1 : (UIntPtr) 0, + reparse ? (UIntPtr) 1 : (UIntPtr) 0 + ); + if (reject == null) { + ep.SendAckRegister(); + Tracing.Log(Tracing.Debug,"Register success"); + } + else { + if (reparse) { + Tracing.Log(Tracing.Debug,"reparsing "+link); + if (link == null ) { + DebugStub.Break(); + ep.SendNakRegister(reject,ErrorCode.Unknown); + } + else { + if (linkFound) { + Tracing.Log(Tracing.Debug,"reparsing {0} as link",link); + exPrefix = Bitter.FromString2(link); + exSuffix = Bitter.FromString2(link); + ep.SendNakRegisterReparse(exPrefix, + exSuffix, + linkFound, + reject); + } + else { + Tracing.Log(Tracing.Debug,"Register(reparse)"+link); + // need to construct prefix from original path + int prefixIndex = pathCopy.IndexOf(link); + if (-1 == prefixIndex) { + exSuffix = null; + exPrefix = null; + DebugStub.Break(); + ep.SendNakRegister(reject, ErrorCode.Unknown); + } + else { + prefix = pathCopy.Substring(0,prefixIndex); + exPrefix = Bitter.FromString2(prefix); + exSuffix = Bitter.FromString2(link); + ep.SendNakRegisterReparse(exPrefix, + exSuffix, + linkFound, + reject); + } + } + //DebugStub.Break(); + } + } // reparse + else { + Tracing.Log(Tracing.Debug," Bind failure!"); + ep.SendNakRegister(reject, error); + } + } + } + catch (Exception e) { + DebugStub.Print(" Exception {0}\n", __arglist(e.ToString())); + } + delete i_path; + Tracing.Log(Tracing.Debug," register {0}", (reject == null) ? "failed" : "success"); + } + + //------------------------------------------------------------------------------------ + //------------------------------------------------------------------------------------ + public static void DoNotify(DirNode! dir, + DirectoryServiceContract.Exp! ep , + [Claims] char[]! in ExHeap i_path, + [Claims] char[]! in ExHeap i_pattern, + bool sendExisting, + [Claims] NotifyContract.Imp:Start! i_notifyImp + ) + { + bool reparse; + string link; + ErrorCode error; + bool linkFound; + string prefix; + Char[] in ExHeap exPrefix; + Char[] in ExHeap exSuffix; + Principal pr = AclCore.EndpointPeer(ep); + + + string path1 = Bitter.ToString2(i_path); + string pattern = Bitter.ToString2(i_pattern); + string pathCopy = Bitter.ToString2(i_path); + + delete i_path; + delete i_pattern; + + Tracing.Log(Tracing.Debug,"Notify {0} {1} "+path1,pattern); + NotifyContract.Imp reject = + dir.Notify(new StringBuilder(path1), + pr, + pattern, + sendExisting, + out linkFound, + out error, out reparse, out link, i_notifyImp); + if (reject == null) { // success + delete reject; + ep.SendAckNotify(); + Tracing.Log(Tracing.Debug,"Notify success"); + } + else { + if (reparse) { + if (null == link ) { + ep.SendNakNotify(reject,error); + } + else { + if (linkFound) { + Tracing.Log(Tracing.Debug,"reparsing {0} as link",link); + exPrefix = Bitter.FromString2(link); + exSuffix = Bitter.FromString2(""); + ep.SendNakNotifyReparse(exPrefix, exSuffix, linkFound, reject); + } + else { + Tracing.Log(Tracing.Debug,"Notify(reparse)"+link); + // need to construct prefix from original path + int prefixIndex = pathCopy.IndexOf(link); + if (-1 == prefixIndex) { + exSuffix = null; + exPrefix = null; + DebugStub.Break(); + ep.SendNakNotify(reject, ErrorCode.Unknown); + } + else { + prefix = pathCopy.Substring(0,prefixIndex); + exPrefix = Bitter.FromString2(prefix); + exSuffix = Bitter.FromString2(link); + ep.SendNakNotifyReparse(exPrefix, + exSuffix, + linkFound, + reject); + } + } + } + } //reparse + else { + Tracing.Log(Tracing.Debug," Bind failure!"); + ep.SendNakNotify(reject, error); + } + } + } + + //------------------------------------------------------------------------------------ + //------------------------------------------------------------------------------------ + + public static void DoBind(DirNode! dir, + DirectoryServiceContract.Exp! ep , + [Claims] char[]! in ExHeap i_path, + [Claims] ServiceContract.Exp:Start! i_server + ) + { + try { + bool success; + bool reparse; + string link; + ErrorCode error; + bool linkFound; + string prefix; + Char[] in ExHeap exPrefix; + Char[] in ExHeap exSuffix; + Principal pr = AclCore.EndpointPeer(ep); + + string pathCopy = Bitter.ToString2(i_path); + Tracing.Log(Tracing.Debug," lookup started: {0}",pathCopy); +#if !SINGULARITY_PROCESS + Monitoring.Log(Monitoring.Provider.Directory, + (ushort)DirectoryEvent.DoBind, + pathCopy); +#endif + ServiceContract.Exp reject = + dir.Bind(new StringBuilder (pathCopy), + pr, + out success, out linkFound, out error, out reparse, out link, i_server); + Tracing.Log(Tracing.Debug," success={0}, linkFound={1}, reparse={2}", + success ? (UIntPtr) 1 : (UIntPtr) 0, + linkFound ? (UIntPtr) 1 : (UIntPtr) 0, + reparse ? (UIntPtr) 1 : (UIntPtr) 0 + ); + if (reject == null && success) { // success + ep.SendAckBind(); + Tracing.Log(Tracing.Debug," Bind success"); + } + else { + if (reparse) { + Tracing.Log(Tracing.Debug,"reparsing "+link); + if (link == null || reject == null) { + DebugStub.Break(); + ep.SendNakBind(reject,ErrorCode.Unknown); + } + else { + if (linkFound) { + Tracing.Log(Tracing.Debug,"reparsing {0} as link",link); + exPrefix = Bitter.FromString2(link); + ep.SendNakBindReparse(exPrefix, + null, + linkFound, + reject); + } + else { + Tracing.Log(Tracing.Debug,"Bind(reparse)"+link); + // need to construct prefix from original path + int prefixIndex = pathCopy.IndexOf(link); + if (-1 == prefixIndex) { + exSuffix = null; + exPrefix = null; + DebugStub.Break(); + ep.SendNakBind(reject, ErrorCode.Unknown); + } + else { + prefix = pathCopy.Substring(0,prefixIndex); + exPrefix = Bitter.FromString2(prefix); + exSuffix = Bitter.FromString2(link); + ep.SendNakBindReparse(exPrefix, + exSuffix, + linkFound, + reject); + } + } + //DebugStub.Break(); + } + } // reparse + else { + Tracing.Log(Tracing.Debug," Bind failure!"); + ep.SendNakBind(reject, error); + } + } + } + catch (Exception e) { + DebugStub.Print(" Exception {0}\n", __arglist(e.ToString())); + } + delete i_path; + } + + //------------------------------------------------------------------------------------ + //------------------------------------------------------------------------------------ + public static void DoGetAttributes(DirNode! dir, DirectoryServiceContract.Exp! ep ,[Claims] char[]! in ExHeap i_path) + { + bool reparse; + string link; + ErrorCode error; + bool linkFound; + string prefix; + Char[] in ExHeap exPrefix; + Char[] in ExHeap exSuffix; + long length; + NodeType nodeType; + Principal pr = AclCore.EndpointPeer(ep); + + string pathCopy = Bitter.ToString2(i_path); + string! path1 = Bitter.ToString2(i_path); + delete i_path; + +#if !SINGULARITY_PROCESS + Monitoring.Log(Monitoring.Provider.Directory, + (ushort)DirectoryEvent.DoGetAttributes, + pathCopy); +#endif + bool aSuccess = dir.GetAttributes(new StringBuilder(path1), + pr, + out linkFound, + out error, + out reparse, + out link, + out length, + out nodeType + ); + + Tracing.Log(Tracing.Debug,"linkFound={1}, reparse={2}", + linkFound ? (UIntPtr) 1 : (UIntPtr) 0, + reparse ? (UIntPtr) 1 : (UIntPtr) 0 + ); + if (aSuccess) { + //if (error != ErrorCode.NoError) DebugStub.Break(); + ep.SendAckGetAttributes(nodeType,length); + } + else { + if (reparse) { + if (null == link) { + ep.SendNakGetAttributes(ErrorCode.Unknown); + } + else { + if (linkFound) { + Tracing.Log(Tracing.Debug,"reparsing {0} as link",link); + exPrefix = Bitter.FromString2(link); + exSuffix = Bitter.FromString2(""); + ep.SendNakGetAttributesReparse(exPrefix, exSuffix, linkFound); + } + else { + Tracing.Log(Tracing.Debug,"GetAttr(reparse)"+link); + // need to construct prefix from original path + int prefixIndex = pathCopy.IndexOf(link); + if (-1 == prefixIndex) { + exSuffix = null; + exPrefix = null; + DebugStub.Break(); + ep.SendNakGetAttributes(ErrorCode.Unknown); + } + else { + if (prefixIndex == 0) { + prefix = pathCopy; + } + else { + prefix = pathCopy.Substring(0,prefixIndex); + } + exPrefix = Bitter.FromString2(prefix); + exSuffix = Bitter.FromString2(link); + ep.SendNakGetAttributesReparse(exPrefix, + exSuffix, + linkFound + ); + } + } + } + } + else { + ep.SendNakGetAttributes(error); + } + } + Kernel.Waypoint(3401); + } + + //------------------------------------------------------------------------------------ + //------------------------------------------------------------------------------------ + public static void DoCreateDirectory(DirNode! dir, DirectoryServiceContract.Exp! ep ,[Claims] char[]! in ExHeap exPath) + { + try { + bool ok; + bool reparse; + string link; + ErrorCode error; + bool linkFound; + string prefix; + Char[] in ExHeap exPrefix; + Char[] in ExHeap exSuffix; + Principal pr = AclCore.EndpointPeer(ep); + + string pathCopy = Bitter.ToString2(exPath); + delete exPath; + +#if SINGULARITY_PROCESS + //DebugStub.Break(); +#else + Monitoring.Log(Monitoring.Provider.Directory, + (ushort)DirectoryEvent.DoCreateDirectory, + pathCopy); + +#endif + ok = dir.CreateDirectory(new StringBuilder (pathCopy), + pr, + out linkFound, + out error, + out reparse, + out link); + if(ok) { + ep.SendAckCreateDirectory(); + return; + } + if (reparse) { + if (null == link) { + ep.SendNakCreateDirectory(ErrorCode.Unknown); + } + else { + if (linkFound) { + Tracing.Log(Tracing.Debug,"reparsing {0} as link",link); + exPrefix = Bitter.FromString2(link); + exSuffix = Bitter.FromString2(""); + ep.SendNakCreateDirectoryReparse(exPrefix, exSuffix, linkFound); + } + else { + // need to construct prefix from original path + int prefixIndex = pathCopy.IndexOf(link); + if (-1 == prefixIndex) { + exSuffix = null; + exPrefix = null; + DebugStub.Break(); + ep.SendNakCreateDirectory(ErrorCode.Unknown); + } + else { + if (prefixIndex == 0) prefix = pathCopy; + else prefix = pathCopy.Substring(0,prefixIndex); + + exPrefix = Bitter.FromString2(prefix); + exSuffix = Bitter.FromString2(link); + ep.SendNakCreateDirectoryReparse(exPrefix, + exSuffix, + linkFound + ); + } + } + } + } //reparse + else { + //DebugStub.Break(); + ep.SendNakCreateDirectory(error); + } + } + finally { + } + } + //------------------------------------------------------------------------------------ + //------------------------------------------------------------------------------------ + public static void DoCreateFile(DirNode! dir, + DirectoryServiceContract.Exp! ep, + [Claims] char[]! in ExHeap exPath) + { + try { + bool ok; + bool reparse; + string link; + ErrorCode error; + bool linkFound; + string prefix; + Char[] in ExHeap exPrefix; + Char[] in ExHeap exSuffix; + Principal pr = AclCore.EndpointPeer(ep); + + string pathCopy = Bitter.ToString2(exPath); + delete exPath; +#if !SINGULARITY_PROCESS + Monitoring.Log(Monitoring.Provider.Directory, + (ushort)DirectoryEvent.DoCreateFile, + pathCopy); +#endif + + ok = dir.CreateFile(new StringBuilder (pathCopy), + pr, + out linkFound, + out error, + out reparse, + out link); + if(ok) { + ep.SendAckCreateFile(); + return; + } + if (reparse) { + if (null == link) { + ep.SendNakCreateFile(ErrorCode.Unknown); + } + else { + if (linkFound) { + Tracing.Log(Tracing.Debug,"reparsing {0} as link",link); + exPrefix = Bitter.FromString2(link); + exSuffix = Bitter.FromString2(""); + ep.SendNakCreateFileReparse(exPrefix, exSuffix, linkFound); + } + else { + // need to construct prefix from original path + int prefixIndex = pathCopy.IndexOf(link); + if (-1 == prefixIndex) { + exSuffix = null; + exPrefix = null; + DebugStub.Break(); + ep.SendNakCreateFile(ErrorCode.Unknown); + } + else { + if (prefixIndex == 0) prefix = pathCopy; + else prefix = pathCopy.Substring(0,prefixIndex); + + exPrefix = Bitter.FromString2(prefix); + exSuffix = Bitter.FromString2(link); + ep.SendNakCreateFileReparse(exPrefix, + exSuffix, + linkFound + ); + } + } + } + } //reparse + else { + ep.SendNakCreateFile(error); + } + } + finally { + } + } + + //------------------------------------------------------------------------------------ + //------------------------------------------------------------------------------------ + public static void DoDeleteDirectory( DirNode! dir, DirectoryServiceContract.Exp! ep ,[Claims] char[]! in ExHeap exPath) + { + try { + bool ok; + bool reparse; + string link; + ErrorCode error; + bool linkFound; + string prefix; + Char[] in ExHeap exPrefix; + Char[] in ExHeap exSuffix; + Principal pr = AclCore.EndpointPeer(ep); + + string pathCopy = Bitter.ToString2(exPath); + delete exPath; + +#if !SINGULARITY_PROCESS + Monitoring.Log(Monitoring.Provider.Directory, + (ushort)DirectoryEvent.DoDeleteDirectory, + pathCopy); +#endif + ok = dir.DeleteDirectory(new StringBuilder (pathCopy), + pr, + out linkFound, + out error, + out reparse, + out link); + if(ok) { + ep.SendAckDeleteDirectory(); + return; + } + if (reparse) { + if (null == link) { + ep.SendNakDeleteDirectory(ErrorCode.Unknown); + } + else { + if (linkFound) { + Tracing.Log(Tracing.Debug,"reparsing {0} as link",link); + exPrefix = Bitter.FromString2(link); + exSuffix = Bitter.FromString2(""); + ep.SendNakDeleteDirectoryReparse(exPrefix, exSuffix, linkFound); + } + else { + // need to construct prefix from original path + int prefixIndex = pathCopy.IndexOf(link); + if (-1 == prefixIndex) { + exSuffix = null; + exPrefix = null; + DebugStub.Break(); + ep.SendNakDeleteDirectory(ErrorCode.Unknown); + } + else { + if (prefixIndex == 0) prefix = pathCopy; + else prefix = pathCopy.Substring(0,prefixIndex); + + exPrefix = Bitter.FromString2(prefix); + exSuffix = Bitter.FromString2(link); + ep.SendNakDeleteDirectoryReparse(exPrefix, + exSuffix, + linkFound + ); + } + } + } + } //reparse + else { + ep.SendNakDeleteDirectory(error); + } + } + finally { + } + } + + //------------------------------------------------------------------------------------ + //------------------------------------------------------------------------------------ + public static void DoDeleteFile( DirNode! dir, DirectoryServiceContract.Exp! ep, + [Claims] char[]! in ExHeap exPath) + { + try { + bool ok; + bool reparse; + string link; + ErrorCode error; + bool linkFound; + string prefix; + Char[] in ExHeap exPrefix; + Char[] in ExHeap exSuffix; + Principal pr = AclCore.EndpointPeer(ep); + + string pathCopy = Bitter.ToString2(exPath); + delete exPath; +#if !SINGULARITY_PROCESS + Monitoring.Log(Monitoring.Provider.Directory, + (ushort)DirectoryEvent.DoCreateFile, + pathCopy); +#endif + + ok = dir.DeleteFile(new StringBuilder (pathCopy), + pr, + out linkFound, + out error, + out reparse, + out link); + if(ok) { + ep.SendAckDeleteFile(); + return; + } + if (reparse) { + if (null == link) { + ep.SendNakDeleteFile(ErrorCode.Unknown); + } + else { + if (linkFound) { + Tracing.Log(Tracing.Debug,"reparsing {0} as link",link); + exPrefix = Bitter.FromString2(link); + exSuffix = Bitter.FromString2(""); + ep.SendNakDeleteFileReparse(exPrefix, exSuffix, linkFound); + } + else { + // need to construct prefix from original path + int prefixIndex = pathCopy.IndexOf(link); + if (-1 == prefixIndex) { + exSuffix = null; + exPrefix = null; + DebugStub.Break(); + ep.SendNakDeleteFile(ErrorCode.Unknown); + } + else { + if (prefixIndex == 0) prefix = pathCopy; + else prefix = pathCopy.Substring(0,prefixIndex); + + exPrefix = Bitter.FromString2(prefix); + exSuffix = Bitter.FromString2(link); + ep.SendNakDeleteFileReparse(exPrefix, + exSuffix, + linkFound + ); + } + } + } + } //reparse + else { + ep.SendNakDeleteFile(error); + } + } + finally { + } + } + + + public static void DoQueryACL( DirNode! dir, + DirectoryServiceContract.Exp! ep , + [Claims] char[]! in ExHeap exPath + ) + { + try { + bool ok; + bool reparse; + string link; + ErrorCode error; + bool linkFound; + string prefix; + Acl acl; + Char[] in ExHeap exPrefix; + Char[] in ExHeap exSuffix; + string! pathCopy = Bitter.ToString2(exPath); + + delete exPath; + + Principal pr = AclCore.EndpointPeer(ep); + + ok = dir.QueryACL(new StringBuilder (pathCopy), + pr, + out linkFound, + out error, + out reparse, + out link, + out acl); + if (ok) { + ep.SendAckQueryACL(Bitter.FromString(acl.val)); + } + if (reparse) { + if (null == link) { + ep.SendNakQueryACL(ErrorCode.Unknown); + } + else { + if (linkFound) { + Tracing.Log(Tracing.Debug,"reparsing {0} as link", link); + exPrefix = Bitter.FromString2(link); + exSuffix = Bitter.FromString2(""); + ep.SendNakQueryACLReparse(exPrefix, exSuffix, linkFound); + return; + } + else { + // need to construct prefix from original path + int prefixIndex = pathCopy.IndexOf(link); + if (-1 == prefixIndex) { + exSuffix = null; + exPrefix = null; + DebugStub.Break(); + ep.SendNakQueryACL(ErrorCode.Unknown); + } + else { + if (prefixIndex == 0) prefix = pathCopy; + else prefix = pathCopy.Substring(0,prefixIndex); + + exPrefix = Bitter.FromString2(prefix); + exSuffix = Bitter.FromString2(link); + ep.SendNakQueryACLReparse(exPrefix, + exSuffix, + linkFound); + return; + } + } + } + } //reparse + else { + ep.SendNakQueryACL(error); + } + } + finally { + } + } + + public static void DoStoreACL( DirNode! dir, + DirectoryServiceContract.Exp! ep , + [Claims] char[]! in ExHeap exPath, + [Claims] char[] in ExHeap acl + ) + { + try { + bool ok; + bool reparse; + string link; + ErrorCode error; + bool linkFound; + string prefix; + Char[] in ExHeap exPrefix; + Char[] in ExHeap exSuffix; + string! pathCopy = Bitter.ToString2(exPath); + Acl myacl = new Acl(Bitter.ToString(acl)); + Principal pr = AclCore.EndpointPeer(ep); + + delete exPath; + + ok = dir.StoreACL(new StringBuilder (pathCopy), + pr, + myacl, + out linkFound, + out error, + out reparse, + out link); + if (ok) { + ep.SendAckStoreACL(); + } + + if (reparse) { + if (null == link) { + ep.SendNakStoreACL(ErrorCode.Unknown); + } + else { + if (linkFound) { + Tracing.Log(Tracing.Debug,"reparsing {0} as link", link); + exPrefix = Bitter.FromString2(link); + exSuffix = Bitter.FromString2(""); + ep.SendNakStoreACLReparse(exPrefix, exSuffix, linkFound, acl); + return; + } + else { + // need to construct prefix from original path + int prefixIndex = pathCopy.IndexOf(link); + if (-1 == prefixIndex) { + exSuffix = null; + exPrefix = null; + DebugStub.Break(); + ep.SendNakStoreACL(ErrorCode.Unknown); + } + else { + if (prefixIndex == 0) prefix = pathCopy; + else prefix = pathCopy.Substring(0,prefixIndex); + + exPrefix = Bitter.FromString2(prefix); + exSuffix = Bitter.FromString2(link); + ep.SendNakStoreACLReparse(exPrefix, + exSuffix, + linkFound, + acl); + return; + } + } + } + } //reparse + else { + ep.SendNakStoreACL(error); + } + delete acl; + } + finally { + } + } + + public static void DoCreateAndBindFile(DirNode! dir, + DirectoryServiceContract.Exp! ep , + [Claims] char[]! in ExHeap exPath, + [Claims] FileContract.Imp:Ready! imp + ) + { + ep.SendNakCreateAndBindFile(imp, ErrorCode.NotImplemented); + delete exPath; + return; + } + + //------------------------------------------------------------------------------------ + // DeleteLink + //------------------------------------------------------------------------------------ + public static void DoDeleteLink( DirNode! dir, + DirectoryServiceContract.Exp! ep , + [Claims] char[]! in ExHeap exPath) + { + try { + bool ok; + bool reparse; + string link; + ErrorCode error; + bool linkFound; + string prefix; + Char[] in ExHeap exPrefix; + Char[] in ExHeap exSuffix; + Principal pr = AclCore.EndpointPeer(ep); + + string pathCopy = Bitter.ToString2(exPath); + delete exPath; +#if !SINGULARITY_PROCESS + Monitoring.Log(Monitoring.Provider.Directory, + (ushort)DirectoryEvent.DoDeleteLink, + pathCopy); +#endif + ok = dir.DeleteLink(new StringBuilder (pathCopy), + pr, + out linkFound, + out error, + out reparse, + out link); + if(ok) { + ep.SendAckDeleteLink(); + return; + } + if (reparse) { + if (null == link) { + ep.SendNakDeleteLink(ErrorCode.Unknown); + } + else { + if (linkFound) { + Tracing.Log(Tracing.Debug,"reparsing {0} as link",link); + exPrefix = Bitter.FromString2(link); + exSuffix = Bitter.FromString2(""); + ep.SendNakDeleteLinkReparse(exPrefix, exSuffix, linkFound); + } + else { + // need to construct prefix from original path + int prefixIndex = pathCopy.IndexOf(link); + if (-1 == prefixIndex) { + exSuffix = null; + exPrefix = null; + DebugStub.Break(); + ep.SendNakDeleteLink(ErrorCode.Unknown); + } + else { + if (prefixIndex == 0) prefix = pathCopy; + else prefix = pathCopy.Substring(0,prefixIndex); + + exPrefix = Bitter.FromString2(prefix); + exSuffix = Bitter.FromString2(link); + ep.SendNakDeleteLinkReparse(exPrefix, + exSuffix, + linkFound + ); + } + } + } + } //reparse + else { + ep.SendNakDeleteLink(error); + } + } + finally { + } + } + + //------------------------------------------------------------------------------------ + // GetLinkValue + //------------------------------------------------------------------------------------ + public static void DoGetLinkValue( DirNode! dir, + DirectoryServiceContract.Exp! ep , + [Claims] char[]! in ExHeap exPath) + { + try { + bool ok; + bool reparse; + string link; + ErrorCode error; + bool linkFound; + string prefix; + Char[] in ExHeap exPrefix; + Char[] in ExHeap exSuffix; + Principal pr = AclCore.EndpointPeer(ep); + + string pathCopy = Bitter.ToString2(exPath); + delete exPath; + +#if !SINGULARITY_PROCESS + Monitoring.Log(Monitoring.Provider.Directory, + (ushort)DirectoryEvent.DoGetLinkValue, + pathCopy); +#endif + ok = dir.GetLinkValue(new StringBuilder (pathCopy), + pr, + out linkFound, + out error, + out reparse, + out link); + if(ok) { + if ( link == null ) { + DebugStub.Break(); + ep.SendNakGetLinkValue(ErrorCode.Unknown); + return; + } + ep.SendAckGetLinkValue(Bitter.FromString2(link)); + return; + } + if (reparse) { + if (null == link) { + ep.SendNakGetLinkValue(ErrorCode.Unknown); + } + else { + if (linkFound) { + Tracing.Log(Tracing.Debug,"reparsing {0} as link",link); + exPrefix = Bitter.FromString2(link); + exSuffix = Bitter.FromString2(""); + ep.SendNakGetLinkValueReparse(exPrefix, exSuffix, linkFound); + } + else { + // need to construct prefix from original path + int prefixIndex = pathCopy.IndexOf(link); + if (-1 == prefixIndex) { + exSuffix = null; + exPrefix = null; + DebugStub.Break(); + ep.SendNakGetLinkValue(ErrorCode.Unknown); + } + else { + if (prefixIndex == 0) prefix = pathCopy; + else prefix = pathCopy.Substring(0,prefixIndex); + + exPrefix = Bitter.FromString2(prefix); + exSuffix = Bitter.FromString2(link); + ep.SendNakGetLinkValueReparse(exPrefix, + exSuffix, + linkFound); + } + } + } + } //reparse + else { + ep.SendNakGetLinkValue(error); + } + } + finally { + } + } + + public static void DoCreateLink( DirNode! dir, + DirectoryServiceContract.Exp! ep , + [Claims] char[]! in ExHeap exPath, + [Claims] char[]! in ExHeap exValue + ) + { + try { + bool ok; + bool reparse; + string link; + ErrorCode error; + bool linkFound; + string prefix; + Char[] in ExHeap exPrefix; + Char[] in ExHeap exSuffix; + Principal pr = AclCore.EndpointPeer(ep); + + string pathCopy = Bitter.ToString2(exPath); + delete exPath; + string value = Bitter.ToString2(exValue); + delete exValue; + +#if !SINGULARITY_PROCESS + Monitoring.Log(Monitoring.Provider.Directory, + (ushort)DirectoryEvent.DoCreateLink, + pathCopy); +#endif + + ok = dir.CreateLink(new StringBuilder (pathCopy), + pr, + value, + out linkFound, + out error, + out reparse, + out link); + if(ok) { + ep.SendAckCreateLink(); + return; + } + if (reparse) { + if (null == link) { + ep.SendNakCreateLink(ErrorCode.Unknown); + } + else { + if (linkFound) { + Tracing.Log(Tracing.Debug,"reparsing {0} as link",link); + exPrefix = Bitter.FromString2(link); + exSuffix = Bitter.FromString2(""); + ep.SendNakCreateLinkReparse(exPrefix, exSuffix, linkFound); + } + else { + // need to construct prefix from original path + int prefixIndex = pathCopy.IndexOf(link); + if (-1 == prefixIndex) { + exSuffix = null; + exPrefix = null; + DebugStub.Break(); + ep.SendNakCreateLink(ErrorCode.Unknown); + } + else { + + if (prefixIndex == 0) prefix = pathCopy; + else prefix = pathCopy.Substring(0,prefixIndex); + + exPrefix = Bitter.FromString2(prefix); + exSuffix = Bitter.FromString2(link); + ep.SendNakCreateLinkReparse(exPrefix, + exSuffix, + linkFound + ); + } + } + } + } //reparse + else { + //DebugStub.Break(); + ep.SendNakCreateLink(error); + } + } + finally { + } + } + + } //WorkerFunctions class +} //namespace diff --git a/base/Applications/NameSpace/NakService/NakService.csproj b/base/Applications/NameSpace/NakService/NakService.csproj new file mode 100644 index 0000000..0ec98ce --- /dev/null +++ b/base/Applications/NameSpace/NakService/NakService.csproj @@ -0,0 +1,27 @@ + + + + + + + Exe + NakService + true + + + + + + + + + + diff --git a/base/Applications/NameSpace/NakService/NakService.sg b/base/Applications/NameSpace/NakService/NakService.sg new file mode 100644 index 0000000..20ba1f8 --- /dev/null +++ b/base/Applications/NameSpace/NakService/NakService.sg @@ -0,0 +1,196 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: NakConnect.sg +// Used for testing the namespace service. +// register /dev/NakConnect in the namespace. +// will always Nak any Connect requests. +// Note: +// +using System; +using System.Runtime.CompilerServices; +//using System.Threading; +using Microsoft.Singularity; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.V1.Services; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Security; + +using Microsoft.SingSharp; +using Microsoft.SingSharp.Runtime; +[assembly: ApplicationPublisherAttribute("singularity.microsoft.com")] +[assembly: AssertPrivilegeAttribute("$register-privilege.localhost")] + +namespace Microsoft.Singularity.Applications +{ + public static class NakConnect + { + static string hang = "/dev/ChannelHang"; + static string nakConn = "/dev/NakConnect"; + static string nakRunning = "/dev/NakRunning"; + static string closed = "/dev/ChannelClosed"; + + private static bool Register(DirectoryServiceContract.Imp! ds, + string! name, + [Claims]ServiceProviderContract.Imp! imp) + { + // acquire namespace endpoint + + ErrorCode errorOut; + ServiceProviderContract.Imp:Start service; + bool ok = SdsUtils.Register(name, ds, imp, out errorOut); + if (!ok){ + Console.WriteLine(" Registration of {0} failed. Reason: {1}", + name, + SdsUtils.ErrorCodeToString(errorOut) + ); + + } + return ok; + + } + + private static bool DoDeregister(DirectoryServiceContract.Imp! ds, string! path) + { + ErrorCode errorOut; + ServiceProviderContract.Imp:Start service; + bool ok = SdsUtils.Deregister(path, ds, out service, out errorOut); + if (!ok) DebugStub.Break(); + delete service; + return ok; + } + + static void Finalize() + { + Console.WriteLine("NakService Finalizer called."); + DebugStub.Break(); + DirectoryServiceContract.Imp ds = DirectoryService.NewClientEndpoint(); + try { + DoDeregister(ds, hang); + DoDeregister(ds, nakConn); + DoDeregister(ds, closed); + } + finally { + delete ds; + } + } + + static void CleanUp() + { + Console.WriteLine("NakService Finalizer called."); + DirectoryServiceContract.Imp ds = DirectoryService.NewClientEndpoint(); + try { + DoDeregister(ds, hang); + DoDeregister(ds, nakConn); + DoDeregister(ds, closed); + } + finally { + delete ds; + } + } + + public static int Main(String[]! args) + { + + DirectoryServiceContract.Imp ds = DirectoryService.NewClientEndpoint(); + + // register "/dev/NakConnect" in NS + ServiceProviderContract.Imp! imp; + ServiceProviderContract.Exp! s; + ServiceProviderContract.NewChannel(out imp, out s); + bool ok = NakConnect.Register(ds, nakConn, imp); + + if (!ok) { + delete s; + delete ds; + return -1; + } + + // register "/dev/ChannelHang" in NS + // we keep the exp alive but we never listen + ServiceProviderContract.Imp! imp3; + ServiceProviderContract.Exp! s3; + ServiceProviderContract.NewChannel(out imp3, out s3); + ok = NakConnect.Register(ds, hang, imp3); + if (!ok) { + delete s; + delete s3; + delete ds; + return -1; + } + + // register "/dev/NakRunning" in NS + // we keep the exp alive but we never listen + ServiceProviderContract.Imp! imp4; + ServiceProviderContract.Exp! s4; + ServiceProviderContract.NewChannel(out imp4, out s4); + ok = NakConnect.Register(ds, nakRunning, imp4); + if (!ok) { + delete s; + delete s3; + delete ds; + delete s4; + return -1; + } + + // register "/dev/ChannelClosed" in NS + // we pass the imp on to the NS but close down the exp end + ServiceProviderContract.Imp! imp2; + ServiceProviderContract.Exp! s2; + ServiceProviderContract.NewChannel(out imp2, out s2); + ok = NakConnect.Register(ds, closed, imp2); + + delete s2; // ensure channel closed on other end + + if (!ok) { + delete s; + delete s3; + delete s4; + delete ds; + return -1; + } + + // enter loop to receive Connect messages and always return NACK + + try { + for (bool run = true; run;) { + switch receive { + // Listen for new connections + case s.Connect(candidate): + Console.WriteLine("Nak Service NACKing...."); + s.SendNackConnect(candidate); + break; + case s4.Connect(candidate): + Console.WriteLine("Nak Service NACKing...."); + s.SendAckConnect(); + delete candidate; + break; + case s.ChannelClosed() : + Console.WriteLine("NakConnect channel closed"); + run = false; + break; + case s4.ChannelClosed() : //IsRunning has closed + Console.WriteLine("NakRunning channel closed"); + run = false; + break; + } + } + } + finally { + CleanUp(); + } + Console.WriteLine("terminating NakService cleanly"); + delete s; + delete s3; + delete s4; + delete ds; + SdsUtils.FlushCache(); + + return 0; + } + + } // class NakConnect +}//namespace diff --git a/base/Applications/NameSpace/NamespaceTests.proj b/base/Applications/NameSpace/NamespaceTests.proj new file mode 100644 index 0000000..931cf81 --- /dev/null +++ b/base/Applications/NameSpace/NamespaceTests.proj @@ -0,0 +1,15 @@ + + + + + + + + + + + + + diff --git a/base/Applications/NameSpace/TestDSP/DirectoryService.sg b/base/Applications/NameSpace/TestDSP/DirectoryService.sg new file mode 100644 index 0000000..197c858 --- /dev/null +++ b/base/Applications/NameSpace/TestDSP/DirectoryService.sg @@ -0,0 +1,232 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Directory.sg +// +// Note: +// + +using System; +using System.Threading; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.SingSharp; +using Microsoft.SingSharp.Runtime; +using Microsoft.Singularity.Directory; + +using Microsoft.Singularity.Security; +using Microsoft.Singularity.Security.SDS; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] +[assembly: ApplicationPublisherAttribute("singularity.microsoft.com")] +[assembly: AssertPrivilegeAttribute("$register-privilege.localhost")] + +namespace Microsoft.Application.DSP { + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [StringParameter( "mountPoint", Mandatory=true, Position=0, HelpMessage="Location to mount DSP")] + internal string mountPoint; + + reflective internal Parameters(); + + internal int AppMain() { + return NameServiceDSP.AppMain(this); + } + } + + public class NameServiceDSP + { + + private static DirNode! rootDir; + private static string! mountPoint; + + private static int Register(string! name, [Claims]ServiceProviderContract.Imp! imp) + { + // acquire namespace endpoint + DirectoryServiceContract.Imp epNS = DirectoryService.NewClientEndpoint(); + mountPoint = name; + + try { + epNS.SendRegister(Bitter.FromString2(name),imp); + switch receive { + case epNS.AckRegister(): + break; + case epNS.NakRegister(reject, error): + DebugStub.Break(); + delete reject; + return -1; + break; + case epNS.ChannelClosed(): + DebugStub.Break(); + return -1; + break; + case epNS.NakRegisterReparse(char[]! in ExHeap path, + char[]! in ExHeap rest, + bool linkFound, + ServiceProviderContract.Imp:Start! reject) : + DebugStub.Break(); + delete reject; + delete path; + delete rest; + return -1; + break; + case unsatisfiable: + Tracing.Log(Tracing.Debug,"unable to register NakConnect with Nameservice\n"); + DebugStub.Break(); + return -1; + } + } + finally { + delete epNS; + } + + return 0; + } + + private static int Deregister(string! name) + { + // acquire namespace endpoint + DirectoryServiceContract.Imp epNS = DirectoryService.NewClientEndpoint(); + mountPoint = name; + + try { + epNS.SendDeregister(Bitter.FromString2(name)); + switch receive { + case epNS.AckDeregister(service): + delete service; + break; + case epNS.NakDeregister(error): + DebugStub.Break(); + break; + case epNS.ChannelClosed(): + DebugStub.Break(); + break; + case unsatisfiable: + Tracing.Log(Tracing.Debug,"unable to register NakConnect with Nameservice\n"); + DebugStub.Break(); + return -1; + } + } + finally { + delete epNS; + } + + return 0; + } + + public static void Initialize() + { + NotificationManager.Initialize(); + NotificationManager.StartNotificationThread(); + + ISdsAcl! aclT = new SdsAclImpl(); + InstallAcls(aclT); + AclCore _core = new AclCore(null, new DirAclCoreSupport()); + rootDir = new DirNode("/", _core, aclT); + } + + + // in the fullness of time, we should read the server configuration + // from a reified manifest including config information + // for now, we will just add a rule to allow **any** access + private static void InstallAcls(ISdsAcl! aclT) + { + /* + // read the rules section from the config + XmlNode node = config.GetChild(PolicyListXmlTag); + if (node == null) { + return; + } + + foreach (XmlNode! rule in node.Children) { + if (rule.Name != "rule") { + continue; + } + + string! resource = (!)rule.GetAttribute("resource", ""); + if (resource.Equals("")) { + continue; + } + string! aclstr = (!)rule.GetAttribute("acl", ""); + if (aclstr.Equals("")) { + continue; + } + + policy.AddRule(resource, aclstr); + } + */ + //policy.AddRule("/", "{/groups/anyall}"); + aclT.Set("/", new Acl("{$dsanyrw}|{$dsregister}")); + } + + public static void Finalize() + { + Deregister(mountPoint); + } + + + internal static int AppMain(Parameters! config) + { + int status; + Initialize(); + + + ServiceProviderContract.Imp! imp; + ServiceProviderContract.Exp! s; + ServiceProviderContract.NewChannel(out imp, out s); + status = Register(config.mountPoint, imp); + + if (status != 0) { + delete s; + return status; + } + + try { + for (bool run = true; run;) { + switch receive { + // Listen for new connections + case s.Connect(ServiceContract.Exp:Start! candidate): + DirectoryServiceContract.Exp:Start exp = candidate as DirectoryServiceContract.Exp:Start!; + if (exp != null) { + s.SendAckConnect(); + DirectoryServiceWorker.Create(rootDir,exp); + } + else s.SendNackConnect(candidate); + break; + case s.ChannelClosed() : + run = false; + Console.WriteLine("Channel Closed. DSP shutting down"); + break; + case unsatisfiable: + run = false; + Console.WriteLine("Unsatisfiable. DSP shutting down"); + break; + } + } + } + finally { + } + delete s; + Console.WriteLine(" last line of DSP... process should terminate"); + return 0; + } + } +} + + + + diff --git a/base/Applications/NameSpace/TestDSP/TestDSP.csproj b/base/Applications/NameSpace/TestDSP/TestDSP.csproj new file mode 100644 index 0000000..12d5d6e --- /dev/null +++ b/base/Applications/NameSpace/TestDSP/TestDSP.csproj @@ -0,0 +1,46 @@ + + + + + + + Exe + TestDSP + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/base/Applications/Network/BlastServer/BlastServer.cs b/base/Applications/Network/BlastServer/BlastServer.cs new file mode 100644 index 0000000..d2d81ab --- /dev/null +++ b/base/Applications/Network/BlastServer/BlastServer.cs @@ -0,0 +1,276 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: TcpBlast.cs +// +// Note: Simple Singularity test program. +// + +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using System.Collections; + +#if SINGULARITY +using Microsoft.Contracts; +using System.IO; +using System.Runtime.InteropServices; + +using Microsoft.SingSharp; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using NetStack.Contracts; +using NetStack.Channels.Public; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] +#endif + + +namespace Microsoft.Singularity.Applications.Network +{ +#if SINGULARITY + [ConsoleCategory(HelpMessage="BlastServer TCP data to a ipAddress, port", DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef tcpRef; + + + [LongParameter( "port", Mandatory=true, Position=0, HelpMessage="port to gulp from ")] + internal long port; + + + [LongParameter( "numBytes", Mandatory=true, Position=1, HelpMessage="Total bytes to send")] + internal long numBytes; + + + [LongParameter( "chunkSize", Mandatory=true, Position=2, HelpMessage="Chunks size to send")] + internal long chunkSize; + + reflective internal Parameters(); + + internal int AppMain() { + return BlastServer.AppMain(this); + } + } +#endif + + public class BlastServer + { + /////////////////////////////////////////////////////////////////////// + // Constants + private const int WorkerThreads = 32; + private const int MaxWorkItems = 32 * WorkerThreads; + private const string RepeatPattern = "Here is a repeating string of text that serves as content. "; + + /////////////////////////////////////////////////////////////////////// + // class variables + ushort port; + uint numBytes; + uint chunkSize; + byte[] chunkBuffer; + ThreadPool threadPool; + + private void DispatchRequest(object dispatchObject) + { + Console.WriteLine(dispatchObject as string); + Console.WriteLine("We should Never get here"); +#if SINGULARITY + DebugStub.Break(); +#endif + } + + private void test (object dispatchObject) + { + Console.Write(dispatchObject as string); + } + + private void Blaster (object sock) + { + Socket socket = sock as Socket; +#if SINGULARITY + assert socket != null; +#endif + int bytesSent = 0; + int iterations =0; + + + uint bytesLeft = numBytes, patternLength = (uint)RepeatPattern.Length; + try { + while (bytesLeft > 0) { + uint thisPass = chunkSize < bytesLeft ? chunkSize : bytesLeft; + if (thisPass == chunkSize) { + socket.Send(chunkBuffer); + } + else { + byte[] thisPassBuffer = new byte[thisPass]; + for (uint i = 0; i < thisPass; i++) { + thisPassBuffer [(int)i] = (byte)RepeatPattern[(int)i % (int)patternLength]; + } + socket.Send(thisPassBuffer); + } + bytesLeft -= thisPass; + bytesSent += (int) thisPass; + iterations++; + } + } catch(ArgumentNullException ae) { + Console.WriteLine("ArgumentNullException : {0}", ae.ToString()); + } catch(SocketException se) { + Console.WriteLine("SocketException : {0}", se.ToString()); + } catch(Exception e) { + Console.WriteLine("Unexpected exception : {0}", e.ToString()); + } + //Console.WriteLine("Sent {0} bytes in {1} iterations",bytesSent,iterations); + + socket.Shutdown(SocketShutdown.Both); + socket.Close(); + Thread.Sleep(2); + } + + private void Listen() { + Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + socket.Bind(new IPEndPoint(IPAddress.Any, (int)this.port)); + socket.Listen((int)SocketOptionName.MaxConnections); + while (true) { + Socket s = socket.Accept(); + threadPool.QueueUserWorkItem(new ThreadPool.WorkCallback(Blaster), s); + } + } + +#if SINGULARITY + [NotDelayed] +#endif + public BlastServer (ushort port, uint numBytes, uint chunkSize) + { + this.port = port; + this.numBytes = numBytes; + this.chunkSize = chunkSize; + + chunkBuffer = new byte[chunkSize]; + for (uint i = 0; i < chunkSize; i++) { + chunkBuffer [(int)i] = (byte)RepeatPattern[(int)i % (int)RepeatPattern.Length]; + } + + Console.WriteLine("BlastServer listening on port {0} for {1} bytes in {2}-byte chunks", + port, numBytes, chunkSize); + + threadPool = new ThreadPool( + WorkerThreads, MaxWorkItems, + new ThreadPool.WorkCallback(DispatchRequest) + ); +#if blee + for (int i=0; i < 50 ; i++) { + for (int j = 0; j < 40; j++) { + bool isFull = threadPool.QueueUserWorkItem(new ThreadPool.WorkCallback(test), "."); + while (isFull) { + Thread.Sleep(2); + isFull = threadPool.QueueUserWorkItem(new ThreadPool.WorkCallback(test), "yes\n"); + } + } + Thread.Sleep(300); + } +#endif + } + + public static void Usage() + { + Console.WriteLine("blastserver "); + } + + public void Shutdown() + { + threadPool.Shutdown(); + } +#if SINGULARITY + internal static int AppMain(Parameters! config) + { + + if (config.port > 65536 || config.port < 0) { + Console.WriteLine("Port number out of range: {0}", config.port); + return -1; + } + + ushort port = (ushort) config.port; + uint numBytes = (uint) config.numBytes; + uint chunkSize = (uint) config.chunkSize; + BlastServer bs = new BlastServer( port, numBytes, chunkSize); + + bs.Listen(); + bs.Shutdown(); + return 0; + } +#else + public static int Main(string[] /*!*/ args) + { + int start = -1; + if (args.Length < 4 + start) + { + Usage(); + return 1; + } + + ushort port; + + try { + port = UInt16.Parse(args[1+start]); + } + catch (FormatException) { + Console.WriteLine("Malformed port number: {0}", args[1+start]); + return -1; + } + catch (OverflowException) { + Console.WriteLine("Port number out of range: {0}", args[1+start]); + return -1; + } + + uint numBytes; + + try { + numBytes = UInt32.Parse(args[2+start]); + } + + catch (FormatException) { + Console.WriteLine("Malformed number of bytes: {0}", args[2+start]); + return -1; + } + catch (OverflowException) { + Console.WriteLine("Byte count out of range: {0}", args[2+start]); + return -1; + } + + uint chunkSize; + + try { + chunkSize = UInt32.Parse(args[3+start]); + } + catch (FormatException) { + Console.WriteLine("Malformed chunk size: {0}", args[3+start]); + return -1; + } + catch (OverflowException) { + Console.WriteLine("Chunk size out of range: {0}", args[3+start]); + return -1; + } + BlastServer bs = new BlastServer( port, numBytes, chunkSize); + + bs.Listen(); + bs.Shutdown(); + return 0; + } +#endif + } // end class TcpBlast +} diff --git a/base/Applications/Network/BlastServer/BlastServer.csproj b/base/Applications/Network/BlastServer/BlastServer.csproj new file mode 100644 index 0000000..9bb3d73 --- /dev/null +++ b/base/Applications/Network/BlastServer/BlastServer.csproj @@ -0,0 +1,27 @@ + + + + + + + Exe + BlastServer + 1 + + + + + + + + + + diff --git a/base/Applications/Network/BlastServer/ThreadPool.cs b/base/Applications/Network/BlastServer/ThreadPool.cs new file mode 100644 index 0000000..7c1f948 --- /dev/null +++ b/base/Applications/Network/BlastServer/ThreadPool.cs @@ -0,0 +1,173 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: ThreadPool.sg +// +// Note: +// +using System; +using System.Collections; +using System.Threading; +#if SINGULARITY +using Microsoft.Contracts; +#endif + +namespace Microsoft.Singularity.Applications +{ + /// This class implements a non-Singleton + /// threadpool and has a configurable work queue + /// size. + public sealed class ThreadPool + { + internal class WorkItem { + public WorkCallback callback; + public object userObject; + + public WorkItem(WorkCallback callback, object userObject) + { + this.callback = callback; + this.userObject = userObject; + } + } + + public delegate void WorkCallback(object userObject); + + Queue /* ! */ workItems; + WorkCallback /* ! */ workCallback; + int maxQueuedItems; + volatile int threadCount; + volatile bool shutdown; + ManualResetEvent shutdownEvent; + +#if SINGULARITY + [NotDelayed] +#endif + public ThreadPool(int maxThreads, + int maxQueuedItems, + WorkCallback/* ! */ workCallback) +#if SINGULARITY + requires maxThreads > 0; + requires maxQueuedItems > 0; + requires maxThreads <= maxQueuedItems; +#endif + { + this.workCallback = workCallback; + this.workItems = new Queue(maxQueuedItems); + this.maxQueuedItems = maxQueuedItems; + this.threadCount = maxThreads; + this.shutdown = false; + this.shutdownEvent = new ManualResetEvent(false); +#if SINGULARITY + base(); +#endif + for (int i = 0; i < maxThreads; i++) { + Thread t = new Thread(new ThreadStart(WorkerMain)); + t.Start(); + } + } + + /// + /// Queues call to constructor supplied delegate with + /// user supplied object. If queuing request causes queue to + /// become full, false is returned and no further items should + /// be enqueued until delegate has been called. + /// + public bool QueueUserWorkItem(object userObject) + { + bool queueIsFull = false; + lock (this) { + if (workItems.Count == maxQueuedItems) { + queueIsFull = true; + } + else { +#if SINGULARITY + assert workItems.Count < maxQueuedItems; + assert shutdown == false; +#endif + WorkItem work = new WorkItem(this.workCallback, userObject); + workItems.Enqueue(work); + queueIsFull = (workItems.Count == maxQueuedItems); + if (workItems.Count == 1){ + } + Monitor.Pulse(this); + } + } + return queueIsFull; + } + + /// + /// Queues call to supplied delegate with + /// user supplied object. If queuing request causes queue to + /// become full, false is returned and no further items should + /// be enqueued until delegate has been called. + /// + public bool QueueUserWorkItem(WorkCallback callback, object userObject) + { + bool queueIsFull = false; + lock (this) { + if (workItems.Count == maxQueuedItems) { + queueIsFull = true; + } + else { +#if SINGULARITY + assert workItems.Count < maxQueuedItems; + assert shutdown == false; +#endif + WorkItem work = new WorkItem(callback, userObject); + workItems.Enqueue(work); + queueIsFull = (workItems.Count == maxQueuedItems); + if (workItems.Count == 1){ + } + Monitor.Pulse(this); + } + } + return queueIsFull; + } + + /// + /// Shutdown thread pool instance. Caller blocks until + /// the threads in the pool have finished outstanding + /// work items. + /// + public void Shutdown() + { + lock (this) { + shutdown = true; + Monitor.PulseAll(this); + } + shutdownEvent.WaitOne(); + } + + private void WorkerMain() + { + while (true) { + object workItem = null; + lock (this) { + while (workItems.Count == 0 && !shutdown) { + Monitor.Wait(this); + } + if (workItems.Count == 0 && shutdown) { + break; + } + workItem = workItems.Dequeue(); + } + if (workItem != null) { + WorkItem w = workItem as WorkItem; +#if SINGULARITY + assert w != null; + assert w.callback != null; +#endif + w.callback(w.userObject); + } + + if (--threadCount == 0) { + shutdownEvent.Set(); + } + } + } + } +} + diff --git a/base/Applications/Network/CommandLib/CommandLib.csproj b/base/Applications/Network/CommandLib/CommandLib.csproj new file mode 100644 index 0000000..b3a41e6 --- /dev/null +++ b/base/Applications/Network/CommandLib/CommandLib.csproj @@ -0,0 +1,31 @@ + + + + + + + Library + NetworkCommands + + + + + + + + + + + + + + + diff --git a/base/Applications/Network/CommandLib/NetworkCommands.cs b/base/Applications/Network/CommandLib/NetworkCommands.cs new file mode 100644 index 0000000..2585f06 --- /dev/null +++ b/base/Applications/Network/CommandLib/NetworkCommands.cs @@ -0,0 +1,142 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: IpCommands.cs +// +// Note: Minimal Network Adapter Configuration Tool +// + +using System; +using System.Diagnostics; +using System.Net.IP; + +using Microsoft.SingSharp; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using NetStack.Contracts; +using NetStack.Channels.Public; + +namespace Microsoft.Singularity.Applications.Network +{ + public class Utils + { + public static bool ConnectEndPoint(string! lookupName, [Claims] ServiceContract.Exp! ep) + { + DirectoryServiceContract.Imp epNS = DirectoryService.NewClientEndpoint(); + + try + { + ErrorCode errorOut; + bool ok = SdsUtils.Bind(lookupName, epNS, ep, out errorOut); + if (!ok) { + return false; + } + else { + return true; + } +/* + epNS.SendBind(Microsoft.Singularity.Bitter.FromString2(lookupName), ep); + + switch receive + { + case epNS.NakBind(ServiceContract.Exp:Start rejectedEP, error) : + // failure + delete rejectedEP; + return false; + break; + + case epNS.AckBind() : + // success + return true; + break; + + case epNS.ChannelClosed() : + // failure + return false; + } +*/ + } + finally + { + delete epNS; + } + } + + public static TcpConnectionContract.Imp:ReadyState GetNewTcpEndPoint() + { + TcpContract.Imp! tcpImp; + TcpContract.Exp! tcpExp; + TcpContract.NewChannel(out tcpImp, out tcpExp); + + if (ConnectEndPoint(TcpContract.ModuleName, tcpExp)) + { + tcpImp.RecvReady(); + + TcpConnectionContract.Imp! connImp; + TcpConnectionContract.Exp! connExp; + TcpConnectionContract.NewChannel(out connImp, out connExp); + + tcpImp.SendCreateTcpSession(connExp); + connImp.RecvReady(); + delete tcpImp; + return connImp; + } + else + { + delete tcpImp; + return null; + } + } + + public static UdpConnectionContract.Imp:ReadyState GetNewUdpEndPoint() + { + UdpContract.Imp! udpImp; + UdpContract.Exp! udpExp; + UdpContract.NewChannel(out udpImp, out udpExp); + + if (ConnectEndPoint(UdpContract.ModuleName, udpExp)) + { + udpImp.RecvReady(); + + UdpConnectionContract.Imp! connImp; + UdpConnectionContract.Exp! connExp; + UdpConnectionContract.NewChannel(out connImp, out connExp); + + udpImp.SendCreateUdpSession(connExp); + connImp.RecvReady(); + delete udpImp; + return connImp; + } + else + { + delete udpImp; + return null; + } + } + + public static void DNSShow(DNSContract.Imp:ReadyState! dnsConn) + { + string[] prefix = { "Primary", "Secondary" }; + int key = 0; + IPv4[] servers = DNSImpConnection.GetNameServers(dnsConn); + + foreach (IPv4 nameserver in servers) + { + Console.WriteLine(" {0} name server {1}", + prefix[key], nameserver); + key = 1; + } + + if (key == 0) + { + Console.WriteLine("No DNS servers configured."); + } + } + + } + +} diff --git a/base/Applications/Network/DNS/DNS.cs b/base/Applications/Network/DNS/DNS.cs new file mode 100644 index 0000000..4b33d30 --- /dev/null +++ b/base/Applications/Network/DNS/DNS.cs @@ -0,0 +1,369 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: DNS.cs +// +// Note: Simple Singularity test program. +// +using System; +using System.Diagnostics; +using System.Net.IP; + +using Microsoft.SingSharp; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using NetStack.Contracts; +using NetStack.Channels.Public; + + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications.Network +{ + [ConsoleCategory(HelpMessage="Add network routing information", DefaultAction=true)] + internal class AddConfig { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef dnsRef; + + [StringArrayParameter( "Servers", HelpMessage="Servers to to add")] + internal string[] servers; + + reflective internal AddConfig(); + + internal int AppMain() { + DebugStub.Break(); + DNS.Add(this); + return 0; + } + } + + [ConsoleCategory(Action="show", HelpMessage="Show DNS information")] + internal class ShowConfig { + [Endpoint] + public readonly TRef Stdin; + + [Endpoint] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef dnsRef; + + reflective internal ShowConfig(); + + internal int AppMain() { + return DNS.Show(this); + } + } + + + [ConsoleCategory(Action="delete", HelpMessage="Delete DNS information")] + internal class DeleteConfig { + [Endpoint] + public readonly TRef Stdin; + + [Endpoint] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef dnsRef; + + [StringArrayParameter( "Servers", Mandatory=true, Position=0, HelpMessage="Servers to to add")] + internal string[] servers; + + reflective internal DeleteConfig(); + + internal int AppMain() { + DNS.Delete(this); + return 0; + } + } + + + [ConsoleCategory(Action="rotate", HelpMessage="Rotate name servers")] + internal class RotateConfig { + [Endpoint] + public readonly TRef Stdin; + + [Endpoint] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef dnsRef; + + reflective internal RotateConfig(); + + internal int AppMain() { + DNS.Rotate(this); + return 0; + } + } + + + [ConsoleCategory(Action="query", HelpMessage="Query DNS information")] + internal class QueryConfig { + [Endpoint] + public readonly TRef Stdin; + + [Endpoint] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef dnsRef; + + [Endpoint] + public readonly TRef ipRef; + + [StringParameter( "host", Mandatory=true, Position=0, HelpMessage="host to be queried")] + internal string name; + + reflective internal QueryConfig(); + + internal int AppMain() { + DNS.Query(this); + return 0; + } + } + + public class DNS + { + internal static int Add(AddConfig! config) + { + + DebugStub.Break(); + + if (config.servers == null) { + Console.WriteLine("no servers given"); + return -1; + } + + DNSContract.Imp dnsConn = config.dnsRef.Acquire(); + if (dnsConn == null) { + Console.WriteLine("Could not initialize DNS endpoint."); + delete dnsConn; + return 1; + } + dnsConn.RecvReady(); + + + + for (int i = 0; i < config.servers.Length; i++) + { + IPv4 resolver; + Console.WriteLine("Resolving {0}", config.servers[i]); + + if (IPv4.Parse(config.servers[i], out resolver) == false) + { + Console.WriteLine("Invalid IP address: {0}", config.servers[i]); + } + + dnsConn.SendAddNameServer((uint)resolver); + dnsConn.RecvAck(); + } + delete dnsConn; + return 0; + } + + internal static int Delete(DeleteConfig! config) + { + if (config.servers == null) { + Console.WriteLine("no servers given"); + return -1; + } + + DNSContract.Imp dnsConn = config.dnsRef.Acquire(); + if (dnsConn == null) { + Console.WriteLine("Could not initialize DNS endpoint."); + return 1; + } + dnsConn.RecvReady(); + + for (int i = 0; i < config.servers.Length; i++) + { + IPv4 resolver; + if (IPv4.Parse(config.servers[i], out resolver) == false) + { + Console.WriteLine("Invalid IP address: {0}", config.servers[i]); + } + + dnsConn.SendRemoveNameServer((uint)resolver); + dnsConn.RecvAck(); + } + delete dnsConn; + return 0; + } + + private static bool QueryInternal(string! name) + { + // NOTE use the System.NET APIs here, just to exercise our + // port of them. We could also accomplish this by using a + // DNS channel. + try + { + System.Net.IPHostEntry hostInfo = System.Net.Dns.GetHostByName(name); + if (hostInfo == null) return false; + + IPAddress[] addresses = hostInfo.AddressList; + if (addresses == null) return false; + String[] aliases = hostInfo.Aliases; + if (aliases == null) return false; + + Console.Write("Host names: "); + + int end = aliases.Length - 1; + for (int i = 0; i <= end; i++) + { + Console.Write("{0}{1}", aliases[i], (i == end) ? "" : ", "); + } + Console.Write("\n"); + + end = addresses.Length - 1; + + Console.Write("IP addresses: "); + for (int i = 0; i <= end; i++) + { + Console.Write("{0}{1}", addresses[i], (i == end) ? "" : ", "); + } + Console.Write("\n"); + + return true; + } + catch(System.Net.Sockets.SocketException) + { + return false; + } + } + + internal static int Query(QueryConfig! config) + { + bool isValid; + string name = config.name; + + DNSContract.Imp dnsConn = config.dnsRef.Acquire(); + if (dnsConn == null) + { + Console.WriteLine("Could not initialize DNS endpoint."); + return 1; + } + dnsConn.RecvReady(); + + dnsConn.SendIsValidName(Bitter.FromString(name)); + dnsConn.RecvIsValid(out isValid); + + if (!isValid) + { + Console.Write("Invalid name: {0}", name); + delete dnsConn; + return -1; + } + + if (QueryInternal(name)){ + delete dnsConn; + return -1; + } + + IPContract.Imp ipConn = config.ipRef.Acquire(); + if (ipConn == null) + { + Console.WriteLine("Could not initialize IP endpoint."); + delete dnsConn; + return -1; + } + + try + { + // Ad-hoc search list + char[]! in ExHeap repDomain; + ipConn.SendGetDomainName(); + ipConn.RecvDomainName(out repDomain); + string domain = Bitter.ToString(repDomain); + delete repDomain; + + if (domain == null) + { + Console.WriteLine("Couldn't resolve \"" + name + "\""); + delete dnsConn; + delete ipConn; + return -1; + } + + name = String.Concat(name, "."); + + int index = 0; + + do { + string guess = String.Concat(name, domain.Substring(index)); + + dnsConn.SendIsValidName(Bitter.FromString(guess)); + dnsConn.RecvIsValid(out isValid); + + if (isValid && QueryInternal(guess)) + { + delete dnsConn; + delete ipConn; + return -1; + } + + index = domain.IndexOf('.', index) + 1; + } while (index > 0 && index < domain.Length); + + Console.WriteLine("No IP address found"); + } + finally + { + } + delete ipConn; + delete dnsConn; + return 0; + } + + internal static int Rotate(RotateConfig! config) + { + DNSContract.Imp dnsConn = config.dnsRef.Acquire(); + if (dnsConn == null) + { + Console.WriteLine("Could not initialize DNS endpoint."); + return 1; + } + dnsConn.RecvReady(); + + dnsConn.SendRotateNameServers(); + dnsConn.RecvAck(); + delete dnsConn; + return 0; + } + + + internal static int Show(ShowConfig! config) + { + DNSContract.Imp dnsConn = config.dnsRef.Acquire(); + if (dnsConn == null) + { + Console.WriteLine("Could not initialize DNS endpoint."); + return 1; + } + dnsConn.RecvReady(); + + Utils.DNSShow(dnsConn); + delete dnsConn; + return 0; + } + + + } // end class DNS + +} diff --git a/base/Applications/Network/DNS/DNS.csproj b/base/Applications/Network/DNS/DNS.csproj new file mode 100644 index 0000000..21b4141 --- /dev/null +++ b/base/Applications/Network/DNS/DNS.csproj @@ -0,0 +1,27 @@ + + + + + + + + Exe + dns + true + + + + + + + + + diff --git a/base/Applications/Network/DomainName/DomainName.cs b/base/Applications/Network/DomainName/DomainName.cs new file mode 100644 index 0000000..b3d73b5 --- /dev/null +++ b/base/Applications/Network/DomainName/DomainName.cs @@ -0,0 +1,106 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: DomainName.cs +// +// Note: Simple Singularity test program. +// +using System; +using System.Diagnostics; +using System.Net.IP; + +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using NetStack.Contracts; +using NetStack.Channels.Public; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications.Network +{ + [ConsoleCategory(HelpMessage="Delete network routing information", DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef ipRef; + + [StringParameter( "n", Default=null, HelpMessage="domain name to query")] + internal string name; + + reflective internal Parameters(); + + internal int AppMain() { + DomainName.AppMain(this); + return 0; + } + } + + /// + /// Class for configuring Domain Name. + /// + public class DomainName + { + internal static int AppMain(Parameters! config) + { + + IPContract.Imp ipConn = config.ipRef.Acquire(); + if (ipConn == null) + { + Console.WriteLine("Could not initialize IP endpoint."); + return 1; + } + ipConn.RecvReady(); + + try + { + if (config.name == null) + { + char[]! in ExHeap repDomain; + ipConn.SendGetDomainName(); + ipConn.RecvDomainName(out repDomain); + Console.WriteLine(Bitter.ToString2(repDomain)); + delete repDomain; + } + else + { + ipConn.SendSetDomainName(Bitter.FromString2(config.name)); + + switch receive + { + case ipConn.Err(): + Console.WriteLine("Error setting domain name"); + return 1; // failure + + case ipConn.OK(): + Console.WriteLine("Set domain name successfully"); + break; + + case ipConn.ChannelClosed(): + Console.WriteLine("Error setting domain name (channel closed)"); + return 1; // failure + } + } + } + finally + { + delete ipConn; + } + + return 0; // success + } + } // end class DomainName +} diff --git a/base/Applications/Network/DomainName/DomainName.csproj b/base/Applications/Network/DomainName/DomainName.csproj new file mode 100644 index 0000000..30524b5 --- /dev/null +++ b/base/Applications/Network/DomainName/DomainName.csproj @@ -0,0 +1,26 @@ + + + + + + + Exe + DomainName + true + + + + + + + + + diff --git a/base/Applications/Network/HostName/HostName.cs b/base/Applications/Network/HostName/HostName.cs new file mode 100644 index 0000000..1046f11 --- /dev/null +++ b/base/Applications/Network/HostName/HostName.cs @@ -0,0 +1,111 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: HostName.cs +// +// Note: Simple Singularity test program. +// +using System; +using System.Diagnostics; +using System.Net.IP; + +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using NetStack.Contracts; +using NetStack.Channels.Public; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications.Network +{ + [ConsoleCategory(HelpMessage="Delete network routing information", DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef ipRef; + + [StringParameter( "n", Default=null, HelpMessage="domain name to query")] + internal string name; + + reflective internal Parameters(); + + internal int AppMain() { + HostName.AppMain(this); + return 0; + } + } + /// + /// Class for configuring Host Name. + /// + public class HostName + { + internal static int AppMain(Parameters! config) + { + + IPContract.Imp ipConn = (config.ipRef).Acquire(); + if (ipConn == null) + { + Console.WriteLine("Could not initialize IP endpoint."); + return 1; + } + ipConn.RecvReady(); + + try + { + if (config.name == null) + { + char[]! in ExHeap repHost, repDomain; + ipConn.SendGetHostName(); + ipConn.RecvHostName(out repHost); + + ipConn.SendGetDomainName(); + ipConn.RecvDomainName(out repDomain); + + Console.WriteLine("{0}.{1}", Bitter.ToString(repHost), Bitter.ToString(repDomain)); + delete repHost; + delete repDomain; + return 0; // success + } + else + { + ipConn.SendSetHostName(Bitter.FromString2(config.name)); + + switch receive + { + case ipConn.Err() : + Console.WriteLine("Failure setting host name \"{0}\"", config.name); + return 1; // failure; + + case ipConn.OK() : + Console.WriteLine("Success setting host name"); + break; + + case ipConn.ChannelClosed() : + Console.WriteLine("Failure setting host name \"{0}\" (channel closed)", config.name); + return 1; // failure; + } + } + } + finally + { + delete ipConn; + } + + return 0; // success + } + } // end class HostName +} diff --git a/base/Applications/Network/HostName/HostName.csproj b/base/Applications/Network/HostName/HostName.csproj new file mode 100644 index 0000000..13f9976 --- /dev/null +++ b/base/Applications/Network/HostName/HostName.csproj @@ -0,0 +1,26 @@ + + + + + + + Exe + hostname + true + + + + + + + + + diff --git a/base/Applications/Network/IPConfig/IPConfig.cs b/base/Applications/Network/IPConfig/IPConfig.cs new file mode 100644 index 0000000..2ca6053 --- /dev/null +++ b/base/Applications/Network/IPConfig/IPConfig.cs @@ -0,0 +1,393 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: IPConfig.cs +// +// Note: Simple Singularity test program. +// +using System; +using System.Diagnostics; +using System.Net.IP; + +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using Microsoft.SingSharp; +using NetStack.Contracts; +using NetStack.Channels.Public; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications.Network +{ + [ConsoleCategory(HelpMessage="Configure nic with IP addresses", DefaultAction=true)] + internal class DefaultConfig { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef ipRef; + + [StringParameter( "device", Mandatory=true, Position=0, HelpMessage="Nic to configure")] + internal string device; + + [StringParameter( "address", Mandatory=true, Position=1, HelpMessage="address to give it")] + internal string address; + + [StringParameter( "mask", Mandatory=true, Position=2, HelpMessage="mask to use")] + internal string mask; + + [StringParameter( "gateway", Mandatory=true, Position=3, HelpMessage="gateway")] + internal string gateway; + + reflective internal DefaultConfig(); + + internal int AppMain() { + return IPConfig.DefaultMain(this); + } + } + + [ConsoleCategory(Action="show", HelpMessage="SHOW nic' IP configuration" )] + internal class ShowConfig { + [Endpoint] + public readonly TRef Stdin; + + [Endpoint] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef ipRef; + + [Endpoint] + public readonly TRef dnsRef; + + reflective internal ShowConfig(); + + internal int AppMain() { + return IPConfig.Show(this); + } + } + + [ConsoleCategory(Action="dhcp", HelpMessage="Configure nic via DHCP" )] + internal class DhcpConfig { + [Endpoint] + public readonly TRef Stdin; + + [Endpoint] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef ipRef; + + [StringParameter( "device", Mandatory=true, Position=0, HelpMessage="Nic to configure")] + internal string device; + + [StringParameter( "verb", Mandatory=true, Position=1, HelpMessage="verb (start or stop).")] + internal string action; + + reflective internal DhcpConfig(); + + internal int AppMain() { + return IPConfig.Dhcp(this); + } + } + + [ConsoleCategory(Action="verify", HelpMessage="check device interface" )] + internal class VerifyConfig { + [Endpoint] + public readonly TRef Stdin; + + [Endpoint] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef ipRef; + + [StringParameter( "device", Mandatory=true, Position=0, HelpMessage="Nic to configure")] + internal string device; + + reflective internal VerifyConfig(); + + internal int AppMain() { + return IPConfig.Verify(this); + } + } + + /// + /// Class for interface configuration related commands. + /// + public class IPConfig + { + + // Marked unsafe for now since checker + // has problems with custom vector access. + public static void ShowConfig(IPContract.Imp:ReadyState! ipConn, DNSContract.Imp:ReadyState! dnsConn) + { + int done = 0; + char[]! in ExHeap hostName, domainName; + + ipConn.SendGetHostName(); + ipConn.RecvHostName(out hostName); + ipConn.SendGetDomainName(); + ipConn.RecvDomainName(out domainName); + + Console.WriteLine("Hostname: {0}.{1}", Bitter.ToString2(hostName), Bitter.ToString2(domainName)); + delete hostName; + delete domainName; + + Console.WriteLine("DNS Servers:"); + + try + { Utils.DNSShow(dnsConn); } + finally + {} + + char[][]! in ExHeap ifNames; + ipConn.SendGetInterfaces(); + ipConn.RecvInterfaceList(out ifNames); + + for (int i = 0; i < ifNames.Length; ++i) + { + CustomVector.Expose(ifNames, i); + char[] in ExHeap ifName = ifNames[i]; + if (ifName == null) + throw new Exception("ifName is null"); + string! deviceName = Bitter.ToString2(ifName); + CustomVector.UnExpose(ifNames, i); + ipConn.SendGetInterfaceState(Bitter.FromString2(deviceName)); + switch receive + { + case ipConn.InterfaceNotFound() : + Console.WriteLine("Unexpected error"); + break; + + case ipConn.InterfaceState(InterfaceInfo ifInfo) : + ShowInterface(ifInfo, deviceName); + break; + + case ipConn.ChannelClosed() : + throw new Exception("ipConn channel closed"); + } + + done++; + } + + delete ifNames; + + if (done == 0) + Console.WriteLine("No adapters present."); + } + + public static void ConfigureInterface(IPContract.Imp! ipConn, + string! adapterName, + string! addressString, + string! netmaskString, + string! gatewayString) + { + IPv4 ifAddress, netmask, gateway; + + if (IPv4.Parse(addressString, out ifAddress) == false || + IPv4.Parse(netmaskString, out netmask) == false || + IPv4.Parse(gatewayString, out gateway) == false) + { + return; + } + + ipConn.SendSetInterfaceState(Bitter.FromString2(adapterName), + (uint)ifAddress, (uint)netmask, (uint)gateway); + + switch receive + { + case ipConn.InterfaceNotFound() : + Console.WriteLine("No such interface found"); + break; + + case ipConn.Err() : + Console.WriteLine("Error occurred setting interface state"); + break; + + case ipConn.OK() : + Console.WriteLine("Successfully set interface state"); + break; + } + } + + public static void ShowInterface([Claims] InterfaceInfo ifInfo, string! ifName) + { + Console.WriteLine("Interface: {0}", ifName); + Console.WriteLine("Adapter: {0}", + Bitter.ToString(ifInfo.driverName)); + Console.WriteLine("Version: {0}", + Bitter.ToString(ifInfo.driverVersion)); + Console.WriteLine("MAC address: {0}", + ChannelUtils.HardwareAddressToString(ifInfo.hardwareAddress)); + + bool found = false; + + delete ifInfo.driverName; + delete ifInfo.driverVersion; + + InterfaceIPInfo[] in ExHeap ipConfigs = ifInfo.ipConfigs; + + if (ipConfigs != null) { + for (int i = 0; i < ipConfigs.Length; i++) + { + InterfaceIPInfo ipc = ipConfigs[i]; + Console.WriteLine(" Address: {0,-14} NetMask: {1, -14} Gateway: {2, -14}", new IPv4(ipc.address), new IPv4(ipc.netmask), new IPv4(ipc.gateway)); + found |= true; + } + delete ipConfigs; + } + + if (found == false) + Console.WriteLine(" Not configured."); + } + + public static void StartDhcp(IPContract.Imp! ipConn, + string! adapterName) + { + ipConn.SendStartDhcp(Bitter.FromString2(adapterName)); + + switch receive + { + case ipConn.InterfaceNotFound() : + Console.WriteLine("No such interface found"); + break; + + case ipConn.OK() : + Console.WriteLine("Successfully started DHCP"); + break; + } + } + + public static void StopDhcp(IPContract.Imp! ipConn, + string! adapterName) + { + ipConn.SendStopDhcp(Bitter.FromString2(adapterName)); + + switch receive + { + case ipConn.InterfaceNotFound() : + Console.WriteLine("No such interface found"); + break; + + case ipConn.OK() : + Console.WriteLine("Successfully stopped DHCP"); + break; + } + } + + internal static int Show(ShowConfig! config) + { + IPContract.Imp ipConn = (config.ipRef).Acquire(); + if (ipConn == null) { + throw new Exception("Unable to acquire handle to the IP network"); + } + ipConn.RecvReady(); + + DNSContract.Imp dnsConn = (config.dnsRef).Acquire(); + if (dnsConn == null) + { + Console.WriteLine("Could not initialize DNS endpoint."); + delete ipConn; + return -1; + } + dnsConn.RecvReady(); + + ShowConfig(ipConn, dnsConn); + delete ipConn; + delete dnsConn; + return 0; + } + + + internal static int Dhcp(DhcpConfig! config) + { + IPContract.Imp ipConn = (config.ipRef).Acquire(); + if (ipConn == null) { + throw new Exception("Unable to acquire handle to the IP network"); + } + ipConn.RecvReady(); + + if (config.action == "start") { + StartDhcp(ipConn, config.device); + } + else if (config.action == "stop") { + StopDhcp(ipConn, config.device); + } + else { + Console.WriteLine("Unknown dhcp action:{0}", config.action); + } + delete ipConn; + return 0; + } + + internal static int Verify(VerifyConfig! config) + { + string! arg1 = config.device; + + IPContract.Imp ipConn = (config.ipRef).Acquire(); + if (ipConn == null) { + throw new Exception("Unable to acquire handle to the IP network"); + } + ipConn.RecvReady(); + ipConn.SendGetInterfaceState(Bitter.FromString2(arg1)); + + switch receive + { + case ipConn.InterfaceNotFound() : + Console.WriteLine("Interface not found: \"" + arg1 + "\""); + break; + + case ipConn.InterfaceState(InterfaceInfo ifInfo) : + ShowInterface(ifInfo, arg1); + break; + + case ipConn.ChannelClosed() : + throw new Exception("ipConn channel closed"); + } + delete ipConn; + return 0; + } + + internal static int DefaultMain(DefaultConfig! config) + { + + IPContract.Imp ipConn = (config.ipRef).Acquire(); + if (ipConn == null) { + throw new Exception("Unable to acquire handle to the IP network"); + } + ipConn.RecvReady(); + + try { + ConfigureInterface(ipConn, + config.device, + config.address, + config.mask, + config.gateway); + delete ipConn; + return 0; + } + catch(Exception e) + { + Console.WriteLine("Caught exception: " + e); + } + finally + { + } + delete ipConn; + return 1; + } + } // end class IPConfig +} diff --git a/base/Applications/Network/IPConfig/IPConfig.csproj b/base/Applications/Network/IPConfig/IPConfig.csproj new file mode 100644 index 0000000..3ed375d --- /dev/null +++ b/base/Applications/Network/IPConfig/IPConfig.csproj @@ -0,0 +1,26 @@ + + + + + + + Exe + ipconfig + true + + + + + + + + + diff --git a/base/Applications/Network/MonNet/MonNet.csproj b/base/Applications/Network/MonNet/MonNet.csproj new file mode 100644 index 0000000..c12cf3f --- /dev/null +++ b/base/Applications/Network/MonNet/MonNet.csproj @@ -0,0 +1,34 @@ + + + + + + + Exe + MonNet + true + true + + + + + + + + + + + + + + + + diff --git a/base/Applications/Network/MonNet/MonNet.sg b/base/Applications/Network/MonNet/MonNet.sg new file mode 100644 index 0000000..bca1e97 --- /dev/null +++ b/base/Applications/Network/MonNet/MonNet.sg @@ -0,0 +1,837 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: MonNet.cs +// +// Note: Tool to transfer monitoring log entries over network +// +using System; + +using System.IO; + +using Microsoft.Singularity; + +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Naming; + +using System.Net.IP; +using NetStack.Contracts; +using NetStack.Channels.Public; + +using Microsoft.Singularity.Applications.Network; +using Microsoft.Singularity.Diagnostics.Contracts; + +using Microsoft.Singularity.V1.Types; + +/* For contract type handle dumping: */ +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Io.Net; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.FileSystem; + +using Thread = System.Threading.Thread; + + +using Microsoft.Singularity.Channels; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications { + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [BoolParameter( "help", Default=false, HelpMessage="Display Extended help message.")] + internal bool doHelp; + + [StringArrayParameter( "args", HelpMessage="arg bucket")] + internal string[] args; + + reflective internal Parameters(); + + internal int AppMain() { + return Monnet.AppMain(this); + } + } + + public class Monnet + { + public class Proc + { + public static ProcessContract.Imp:ReadyState BindToProcessDiagnostics() + { + ProcessContract.Exp! exp; + ProcessContract.Imp! imp; + ProcessContract.NewChannel(out imp, out exp); + + // get NS endpoint + DirectoryServiceContract.Imp ns = DirectoryService.NewClientEndpoint(); + try + { + ErrorCode errorOut; + bool ok = SdsUtils.Bind(ProcessContract.ModuleName, ns, exp, out errorOut); + if (!ok) { + delete imp; + Console.WriteLine("Bind of {0} failed. reason: {1}\n", MemoryContract.ModuleName,SdsUtils.ErrorCodeToString(errorOut) ); + if (errorOut == ErrorCode.ChannelClosed) + { + throw new Exception("Encountered a ChannelClosed to NameServer"); + } + return null; + } + else { + imp.RecvReady(); + } + } + finally + { + delete ns; + } + return imp; + } + + public static int []! GetProcessIDs(ProcessContract.Imp:ReadyState! imp) + { + int [] ids = null; + int[]! in ExHeap xids; + imp.SendGetProcessIDs(); + imp.RecvProcessIDs(out xids); + // REVIEW: The kernel process is being returned twice so we're + // skipping one of the entries if the process ID matches. + int startIndex = 0; + if (xids[0] == xids[1]) + startIndex++; + ids = new int[xids.Length - startIndex]; + for (int i = startIndex; i < xids.Length; i++) + { + ids[i - startIndex] = xids[i]; + } + delete xids; + return ids; + } + + public static int [] GetProcessThreadIDs(ProcessContract.Imp:ReadyState! imp, int procID) + { + imp.SendGetProcessThreadIDs(procID); + int [] retVal = null; + + switch receive + { + case imp.NotFound() : + break; + + case imp.ProcessThreadIDs(int[]! in ExHeap tids) : + retVal = new int[tids.Length]; + for (int i=0; i> 32); + postSysInfoEvent(ref ev, null); + + dumpContractTypeHandles(); + dumpPidEntries(); + + // TODO: disk ID -> name rundowns + } + + private static void dumpPidEntries() + { + Monitoring.LogEntry ev = newSysInfoEvent(SysInfoEvent.PidInfo); + Monitoring.LogEntry ev2 = newSysInfoEvent(SysInfoEvent.ThreadInfo); + + ProcessContract.Imp:ReadyState pDiag = Proc.BindToProcessDiagnostics(); + + if (pDiag == null) { + } + else { + int [] procIds = Proc.GetProcessIDs(pDiag); + string [] names = Proc.GetProcessNames(pDiag,procIds); + + for (int i=0; i= 0) + smallname = fullname.Substring(idx+1); + else + smallname = fullname; + + postSysInfoEvent(ref ev, smallname); + } + } + + + public static byte[]! buf; // event buffer + public static int bufoffset; // current position in event buffer + public static byte[] text; // buffer for event string + public static int textlen; // length of event string + + public static TcpConnectionContract.Imp:Connected! + OpenConnection(IPv4 address, ushort port) + { + TcpConnectionContract.Imp tcpConn = Utils.GetNewTcpEndPoint(); + if (tcpConn == null) { + Console.WriteLine("Could not initialize TCP endpoint."); + throw new ArgumentException("Could not initialize TCP endpoint."); + } + + Console.Write("Connecting..."); + + // Try to connect to the remote host + tcpConn.SendConnect((uint)address, port); + + switch receive + { + case tcpConn.CouldNotConnect(TcpError error) : + Console.WriteLine("Failed to connect: TcpError = " + System.Net.Sockets.TcpException.GetMessageForTcpError(error)); + delete tcpConn; + throw new ArgumentException("Failed to connect."); + break; + + case tcpConn.OK() : + // success; + break; + + case tcpConn.ChannelClosed() : + // how rude + Console.WriteLine("Netstack channel closed unexpectedly"); + delete tcpConn; + throw new ArgumentException("Netstack channel closed unexpectedly"); + break; + } + + Console.WriteLine("Connected"); + return tcpConn; + } + + public static TcpConnectionContract.Imp:Connected + SetupNetwork(string sIp, string sPort) + { + IPv4 host; + try + { + host = IPv4.Parse(sIp); + } + catch (FormatException e) + { + Console.WriteLine("{0}: {1}", e, sIp); + return null; + } + + ushort port; + try + { + port = UInt16.Parse(sPort); + } + catch (FormatException) + { + Console.WriteLine("Malformed port number: {0}", sPort); + return null; + } + catch (OverflowException) + { + Console.WriteLine("Port number out of range: {0}", sPort); + return null; + } + + TcpConnectionContract.Imp! conn = OpenConnection(host, port); + + return conn; + } + + + // we segment our large buffer into COMMSZ chunks for punting through + // to the network stack + private static int COMMSZ = 64*1024; // 64KB + + public static int SendLogBuffer(TcpConnectionContract.Imp! conn) + { + int sendidx = 0; + int sendlen; + byte[]! in ExHeap data; + + // copy data to exheap in chunks and send + Console.Write("Sending"); + while (sendidx < bufoffset) + { + sendlen = Math.Min(COMMSZ, bufoffset - sendidx); + data = Bitter.FromByteArray(buf, sendidx, sendlen); + + conn.SendWrite(data); + switch receive + { + case conn.OK() : + Console.Write("."); + break; + + case conn.CantSend() : + Console.WriteLine(": Connection closed unexpectedly (CantSend)"); + return -1; + break; + + case conn.ConnectionClosed(): + Console.WriteLine(": Connection closed unexpectedly (ConnectionClosed)"); + return -1; + break; + } + + sendidx += sendlen; + } + + Console.WriteLine("OK"); + return 0; + } + + public static int marshalled; // count of events marshalled + + public static int Marshall(ref Monitoring.LogEntry e) + { + int tl = (textlen > 0)? textlen : 0; + if (sizeof(Monitoring.LogEntry) + bufoffset + tl > buf.Length) { + Console.WriteLine("Marshall: buffer full"); + return -1; + } + + unsafe { + fixed (byte *bp = &buf[bufoffset]) { + /* Use a simple cast */ + Monitoring.LogEntry *lep = (Monitoring.LogEntry *)bp; + *lep = e; + } + } + bufoffset += sizeof(Monitoring.LogEntry); + + if (textlen > 0) { + Array.Copy(text, 0, buf, bufoffset, textlen); + bufoffset += textlen; + } + textlen = 0; + + marshalled++; + return 0; + } + + // Fill event buffer until either duration has passed or + // we have maxevents + public static int FillEventBuffer(ulong duration, ulong maxevents, + ulong evstart) + { + int ret = -1; + ulong counter = evstart; + ulong old_counter = 0; + ulong count_lost = 0; + ulong sum_lost = 0; + + ulong hz = (ulong)Processor.CyclesPerSecond; + ulong now = Processor.CycleCount; + ulong end = now + duration * hz; + + ulong evcount = 0; + + Monitoring.LogEntry e = new Monitoring.LogEntry(); + + Console.WriteLine("MonNet: collecting with duration={0}secs, maxevents={1}", + duration, maxevents); + + bool done = false; + while (!done) + { + // Get an event + while (true) + { + ret = -1; + now = Processor.CycleCount; + if (now > end || evcount >= maxevents) + { + done = true; + + if (now > end) + Console.WriteLine("Timed out ({0}ms late)", (now-end)*1000/hz); + if (evcount >= maxevents) + Console.WriteLine("Got enough events"); + break; + } + + unsafe { + ret = Monitoring.GetEntry(ref counter, out e); + } + if (old_counter != counter) + { + count_lost++; + sum_lost += counter - old_counter; + //Console.Write("X{0}", counter - old_counter); + } + old_counter = counter; + + if (ret == 0) {// Got an event + evcount++; + break; + } else { // No event to get, sleep and try again + // are we just using defaults? + if (duration == ((ulong)DEF_DUR) && + maxevents == ((ulong)DEF_MAXEV)) + { + done = true; + Console.WriteLine("No more events"); + break; + } + else + { + Thread.Sleep(100); + } + } + } + counter++; + + if (ret == 0) + { + if (e.cycleCount == 0) + { +// Console.Write('^'); + evcount--; + continue; // got illegal entry, so try next + } + + // Try to get text buffer for event + if (e.text != null) + { + int size; + unsafe { + assume text != null; + fixed (byte * b = text) { + size = Monitoring.FillTextEntry(e.text, e.cycleCount, + b, text.Length); + } + } + + if (size != 0) // fixup size in event structure + { + if (size < 0) // error: dropped text string + Console.WriteLine("size={0}", size); + + unsafe { + e.text = (byte *)size; + } + textlen = size; + } + } + + // put event in buffer + ret = Marshall(ref e); + if (ret != 0) { + Console.WriteLine("BUFFER FULL: exiting EARLY!"); + done = true; + break; + } + } + } + Console.WriteLine("Got {0} events", evcount); + return ret; + } + + + /* We can't actually "clear" the kernel log; what this does + * is find the counter number for the log's current end, + * so we can pass it into FillEventBuffer() later. */ + private static ulong clearLog() + { + int ret; + ulong counter = 0; + Monitoring.LogEntry e = new Monitoring.LogEntry(); + int i = 0; + + while (true) + { + unsafe { + ret = Monitoring.GetEntry(ref counter, out e); + } + if (ret == 0) { + counter++; // got an event; try next one + } else { + break; // failed to get an event, we're done + } + + /* sanity check */ + if (i++ > 5000000) + { + Console.WriteLine("error: clearLog() looped 5000000 times; bailing"); + break; + } + } + + return counter; + } + + + + /************************************************/ + /* Command line gubbins */ + + + private static int doTransfer(string sIp, string sPort) + { + int ret; + + // Setup the networking stuff. + // austind: due to a race in the netstack, must open the connection + // and start sending data on it promptly, otherwise you'll get + // a RST and an exception. + TcpConnectionContract.Imp conn = SetupNetwork(sIp, sPort); + if (conn == null) + return -1; + + // Transmit the buffer + ret = SendLogBuffer(conn); + + // Tidy up + conn.SendClose(); + delete conn; + + return ret; + } + + + private static int doSlurp(long runTime, long maxevents, + ulong evstart) + { + // Allocate the buffers + buf = new Byte[16<<20]; // should be big enough + bufoffset = 0; + text = new byte[256]; + textlen = 0; + + marshalled = 0; // num events copied to buf + + // Put preamble into buffer + dumpSysInfo(); + + return FillEventBuffer((ulong)runTime, (ulong)maxevents, evstart); + } + + + public static bool ParseNumber(string/*!*/ arg, + string/*!*/ name, + out long value) + { + // arg should look like "[-][A-z]:[0-9]*" + if (arg.Length >= 4) + { + try + { + value = Int64.Parse(arg.Substring(3)); + return true; + } + catch (FormatException) + {Console.WriteLine("format ex"); } + catch (OverflowException) + {Console.WriteLine("overflow ex");} + } + Console.WriteLine("Could not parse {0}, {1}", name,arg.Substring(3)); + value = 0; + return false; + } + + internal static int usage() + { + Console.WriteLine("Usage: monnet /d /c /w:WARMUP /e /r:RUNTIME /n:MAXEVENTS /s /t:IP:PORT"); + Console.WriteLine(" /d disable logging"); + Console.WriteLine(" /c \"clear\" log: ie note current end"); + Console.WriteLine(" /w:WARMUP pause for WARMUP seconds"); + Console.WriteLine(" /e enable logging"); + Console.WriteLine(" /r:RUNTIME set event slurp limit to RUNTIME seconds"); + Console.WriteLine(" /n:MAXEVENTS set event slurp limit to MAXEVENTS"); + Console.WriteLine(" (without /r or /n options: slurp until log empty or marshal buffer full)"); + Console.WriteLine(" /s slurp events according to limits"); + Console.WriteLine(" /t:IP:PORT transfer via TCP to IPADDR:PORT"); + Console.WriteLine("All options can occur in any order, zero or more times"); + Console.WriteLine("They are executed in order. Example:"); + Console.WriteLine("monnet /d /c /w:300 /e /r:300 /s /d /t:10.99.99.1:5000"); + return -1; + } + + private static long DEF_DUR = 999999999; // seconds ie forever + private static long DEF_MAXEV = 999999999; + + internal static int AppMain(Parameters! config) + { + int ret = 0; + long runTime = DEF_DUR, maxevents = DEF_MAXEV; + ulong evstart = 0; + string[] args = config.args; + + if (config.doHelp) return usage(); + + if (args == null) + { + return usage(); + } + + bool needHelp = (args.Length == 0); + + int i; + for (i = 0; !needHelp && i < args.Length; i++) + { + string arg = args[i]; + + if (arg == null || arg.Length < 2 || (arg[0] != '-' && arg[0] != '/') ) + { + Console.WriteLine("Invalid argument: {0}", arg); + return usage(); + } + + long temp; + switch (arg[1]) + { + case 'd': + case 'e': + bool active = (arg[1] == 'e'); + Console.WriteLine(active?"Enabling logging":"Disabling logging"); + Monitoring.setActive(active); + break; + + case '?': + case 'h': + needHelp = true; + break; + + case 'c': + Console.WriteLine("Clearing log"); + evstart = clearLog(); + break; + + case 'w': + ParseNumber(arg, "Warmup time", out temp); + Console.WriteLine("Pausing {0}secs for warmup", temp); + Thread.Sleep(((int)temp) * 1000); + break; + + case 'r': + ParseNumber(arg, "Run time", out runTime); + break; + + case 'n': + ParseNumber(arg, "Maxevents", out maxevents); + break; + + case 's': + doSlurp(runTime, maxevents, evstart); + break; + + case 't': + int colon = arg.IndexOf(':', 3); + if (colon < 0) + { + Console.WriteLine("argument error: missing colon in '{0}': expecting IPADDR:PORT", arg); + return usage(); + } + string ipaddr = arg.Substring(3, colon-3); + string port = arg.Substring(colon+1); + ret = doTransfer(ipaddr, port); + if (ret != 0) + return ret; + break; + + default: + Console.WriteLine("Unknown option {0}", arg); + needHelp = true; + break; + } + } // for args + + if (needHelp) + { + return usage(); + } + + return 0; + } + + } +} diff --git a/base/Applications/Network/NetworkApps.proj b/base/Applications/Network/NetworkApps.proj new file mode 100644 index 0000000..6989630 --- /dev/null +++ b/base/Applications/Network/NetworkApps.proj @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/base/Applications/Network/NetworkCommand.targets b/base/Applications/Network/NetworkCommand.targets new file mode 100644 index 0000000..8e2f29e --- /dev/null +++ b/base/Applications/Network/NetworkCommand.targets @@ -0,0 +1,20 @@ + + + + + + Exe + + + + + + + + + + + + + + diff --git a/base/Applications/Network/Route/Route.cs b/base/Applications/Network/Route/Route.cs new file mode 100644 index 0000000..6785575 --- /dev/null +++ b/base/Applications/Network/Route/Route.cs @@ -0,0 +1,311 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Route.cs +// +// Note: Simple Singularity test program. +// +using System; +using System.Diagnostics; +using System.Net.IP; + +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using Microsoft.SingSharp; +using NetStack.Contracts; +using NetStack.Channels.Public; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications.Network { + + [ConsoleCategory(Action="show", HelpMessage="Show network routing information")] + internal class ShowConfig { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef routingRef; + + reflective internal ShowConfig(); + + internal int AppMain() { + return Route.Show(this); + } + } + + [ConsoleCategory(HelpMessage="Add network routing information",DefaultAction=true)] + internal class AddConfig { + [Endpoint] + public readonly TRef Stdin; + + [Endpoint] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef routingRef; + + [Endpoint] + public readonly TRef ipRef; + + [StringParameter( "destination", Mandatory=true, Position=0, HelpMessage="destination to be added")] + internal string destination; + + [StringParameter( "g", Mandatory=true, Position=1, HelpMessage="Gateway")] + internal string gateway; + + [StringParameter( "i", Default=null, HelpMessage="ifAddress")] + internal string ifAddress; + + reflective internal AddConfig(); + + internal int AppMain() { + Route.Add(this); + return 0; + } + } + + [ConsoleCategory(Action="delete", HelpMessage="Show network routing information")] + internal class DeleteConfig { + [Endpoint] + public readonly TRef Stdin; + + [Endpoint] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef routingRef; + + [StringParameter( "address", Mandatory=true, Position=0, HelpMessage="Address to be deleted")] + internal string address; + + [StringParameter( "destination", Mandatory=true, Position=0, HelpMessage="Address to be added")] + internal string destination; + + reflective internal DeleteConfig(); + + internal int AppMain() { + return Route.Delete(this); + } + } + + /// + /// Class for routing related configuration. + /// + public class Route + { + internal static int Show(ShowConfig! config) + { + RouteEntry[] in ExHeap routes; + + RoutingContract.Imp routeConn = (config.routingRef).Acquire(); + if (routeConn == null) { + Console.WriteLine("Could not initialize routing endpoint."); + return 1; + } + routeConn.RecvReady(); + + routeConn.SendGetRoutingTable(); + routeConn.RecvRoutingTable(out routes); + + if (routes == null) + throw new Exception("routes is null"); + + for (int i = 0; i < routes.Length; i++) + { + Console.WriteLine("Network : " + ChannelUtils.NetworkToString(routes[i].network)); + Console.WriteLine("Gateway : " + ChannelUtils.AddressToString(routes[i].gateway)); + Console.WriteLine("Interface address : " + ChannelUtils.AddressToString(routes[i].ifaddr)); + Console.WriteLine("Metric : " + routes[i].metric); + Console.WriteLine(String.Format("Tag : {0:x8}\n", routes[i].tag)); + } + + delete routes; + delete routeConn; + return 0; + } + + internal static int Add(AddConfig! config) + { + IPv4 gateway; + + RoutingContract.Imp routeConn = (config.routingRef).Acquire(); + if (routeConn == null) { + Console.WriteLine("Could not initialize routing endpoint."); + return 1; + } + routeConn.RecvReady(); + + if (IPv4.Parse(config.gateway, out gateway) == false) + { + Console.WriteLine("Could not parse gateway address."); + delete routeConn; + return -1; + } + + try + { + // note for some reason the compiler doesn't + // realize that ifaddr will definitely be assigned if + // we survive the if/switch-receive sequence. Work + // around that by initializing. + IPv4 ifaddr = new IPv4(0); + + if (config.ifAddress == null) + { + routeConn.SendFindHostRoute((uint)gateway); + + switch receive + { + case routeConn.Route(RouteEntry r) : + ifaddr = new IPv4(r.ifaddr); + break; + + case routeConn.NoRouteFound() : + Console.WriteLine("No route to gateway."); + delete routeConn; + return -1; + break; + + case routeConn.ChannelClosed() : + Console.WriteLine("routeConn channel closed."); + throw new Exception("routeConn channel closed."); + } + } + else if (IPv4.Parse(config.ifAddress, out ifaddr) == false) + { + Console.WriteLine("Could not parse interface address."); + delete routeConn; + return -1; + } + + IPContract.Imp ipConn = (config.ipRef).Acquire(); + if (ipConn == null) + { + Console.WriteLine("Could not initialize IP endpoint."); + delete routeConn; + return -1; + } + + try + { + bool isLocal; + ipConn.SendIsLocalAddress((uint)ifaddr); + ipConn.RecvIsLocal(out isLocal); + + if (!isLocal) + { + Console.WriteLine("Proposed interface address is not bound to an interface."); + delete routeConn; + return -1; + } + } + finally + { + delete ipConn; + ipConn = null; + } + + IPv4Network destination; + if (IPv4Network.Parse(config.destination, out destination) == false) + { + Console.WriteLine("Could not parse destination address."); + delete routeConn; + return -1; + } + + NetStack.Contracts.Network nwrk = new NetStack.Contracts.Network(); + nwrk.network = (uint)destination.Network; + nwrk.netmask = (uint)destination.NetMask; + routeConn.SendAddRoute(nwrk, (uint)gateway, (uint)ifaddr); + + switch receive + { + case routeConn.Err() : + Console.WriteLine("Route could not be added -- it may already exist."); + break; + + case routeConn.OK() : + Console.WriteLine("Route added successfully"); + break; + + case routeConn.ChannelClosed() : + throw new Exception("routeConn channel closed"); + } + } + catch (Exception e) + { + Console.WriteLine("Exception: {0}", e); + } + delete routeConn; + return 0; + } + + internal static int Delete(DeleteConfig! config) + { + RoutingContract.Imp routeConn = (config.routingRef).Acquire(); + if (routeConn == null) + { + Console.WriteLine("Could not initialize routing endpoint."); + return 1; + } + routeConn.RecvReady(); + + IPv4Network destination; + if (IPv4Network.Parse(config.destination, out destination) == false) + { + Console.WriteLine("Could not parse destination address."); + } + + Network destNet = ChannelUtils.NetworkToChannelNetwork(destination); + routeConn.SendFindSpecificNetRoute(destNet); + + switch receive + { + case routeConn.NoRouteFound() : + Console.WriteLine("No route for destination."); + delete routeConn; + return -1; + + case routeConn.Route(RouteEntry r) : + // Do nothing; success. + break; + + case routeConn.ChannelClosed() : + Console.WriteLine("routeConn channel closed."); + throw new Exception("routeConn channel closed."); + } + + routeConn.SendDeleteRoute(destNet); + + switch receive + { + case routeConn.NoRouteFound() : + Console.WriteLine("Unexpected error attempting to delete the route"); + break; + + case routeConn.OK() : + Console.WriteLine("Route successfully deleted"); + break; + + case routeConn.ChannelClosed() : + Console.WriteLine("routeConn channel closed"); + throw new Exception("routeConn channel closed"); + } + delete routeConn; + return 0; + } + } // end class Route +} diff --git a/base/Applications/Network/Route/Route.csproj b/base/Applications/Network/Route/Route.csproj new file mode 100644 index 0000000..acf4023 --- /dev/null +++ b/base/Applications/Network/Route/Route.csproj @@ -0,0 +1,26 @@ + + + + + + + Exe + route + true + + + + + + + + + diff --git a/base/Applications/Network/TcpBlast/TcpBlast.csproj b/base/Applications/Network/TcpBlast/TcpBlast.csproj new file mode 100644 index 0000000..80cd67d --- /dev/null +++ b/base/Applications/Network/TcpBlast/TcpBlast.csproj @@ -0,0 +1,26 @@ + + + + + + + Exe + TcpBlast + true + + + + + + + + + diff --git a/base/Applications/Network/TcpBlast/TcpBlast.sg b/base/Applications/Network/TcpBlast/TcpBlast.sg new file mode 100644 index 0000000..8925d1d --- /dev/null +++ b/base/Applications/Network/TcpBlast/TcpBlast.sg @@ -0,0 +1,186 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: TcpBlast.cs +// +// Note: Simple Singularity test program. +// +using System; +using System.Diagnostics; +using System.Net.IP; + +using Microsoft.SingSharp; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using NetStack.Contracts; +using NetStack.Channels.Public; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications.Network +{ + [ConsoleCategory(HelpMessage="Blast TCP data to a ipAddress, port", DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef tcpRef; + + [StringParameter( "address", Mandatory=true, Position=0, HelpMessage="IP Address to receive from")] + internal string address; + + + [LongParameter( "port", Mandatory=true, Position=1, HelpMessage="port to gulp from ")] + internal long port; + + + [LongParameter( "numBytes", Mandatory=true, Position=2, HelpMessage="Total bytes to send")] + internal long numBytes; + + + [LongParameter( "chunkSize", Mandatory=true, Position=3, HelpMessage="Chunks size to send")] + internal long chunkSize; + + reflective internal Parameters(); + + internal int AppMain() { + return TcpBlast.AppMain(this); + } + } + + public class TcpBlast + { + private const string RepeatPattern = "Here is a repeating string of text that serves as content. "; + + public static int Blast([Claims] TcpConnectionContract.Imp:ReadyState! tcpConn, + IPv4 address, ushort port, uint numBytes, uint chunkSize) + { + Console.WriteLine("TcpBlast to {0} at port {1} for {2} bytes in {3}-byte chunks", + address, port, numBytes, chunkSize); + + Console.Write("Connecting..."); + + try + { + // Try to connect to the remote host + tcpConn.SendConnect((uint)address, port); + + switch receive + { + case tcpConn.CouldNotConnect(TcpError error) : + Console.WriteLine("Failed to connect: TcpError = " + System.Net.Sockets.TcpException.GetMessageForTcpError(error)); + delete tcpConn; + return -1; + break; + + case tcpConn.OK() : + // success; + break; + + case tcpConn.ChannelClosed() : + // how rude + Console.WriteLine("Netstack channel closed unexpectedly"); + delete tcpConn; + return -1; + break; + } + + Console.WriteLine("Connected"); + byte[] in ExHeap buf; + uint bytesLeft = numBytes, patternLength = (uint)RepeatPattern.Length; + + while (bytesLeft > 0) { + uint thisPass = chunkSize < bytesLeft ? chunkSize : bytesLeft; + buf = new[ExHeap] byte[thisPass]; + + for (uint i = 0; i < thisPass; i++) { + buf[(int)i] = (byte)RepeatPattern[(int)i % (int)patternLength]; + } + + tcpConn.SendWrite(buf); + + switch receive + { + case tcpConn.OK() : + break; + + case tcpConn.CantSend() : + Console.WriteLine("Connection closed unexpectedly"); + delete tcpConn; + return -1; + break; + } + + bytesLeft -= thisPass; + } + + tcpConn.SendClose(); + delete tcpConn; + Console.WriteLine("Done"); + } + catch (Exception e) { + Console.WriteLine("Unexpected exception: {0}", e); + } + + return 0; + } + + public static void Usage() + { + Console.WriteLine("tcpgulp "); + } + + internal static int AppMain(Parameters! config) + { + IPv4 host; + try { + host = IPv4.Parse(config.address); + } + catch (FormatException e) { + Console.WriteLine("{0}: {1}", e, config.address); + return -1; + } + + + if (config.port > 65536 || config.port < 0) { + Console.WriteLine("Port number out of range: {0}", config.port); + return -1; + } + + ushort port = (ushort) config.port; + uint numBytes = (uint) config.numBytes; + uint chunkSize = (uint) config.chunkSize; + + TcpContract.Imp tcpConn = (config.tcpRef).Acquire(); + if (tcpConn == null) + { + Console.WriteLine("Could not initialize TCP endpoint."); + return 1; + } + tcpConn.RecvReady(); + + TcpConnectionContract.Imp! connImp; + TcpConnectionContract.Exp! connExp; + TcpConnectionContract.NewChannel(out connImp, out connExp); + + tcpConn.SendCreateTcpSession(connExp); + connImp.RecvReady(); + delete tcpConn; + + return Blast(connImp, host, port, numBytes, chunkSize); + } + } // end class TcpBlast +} diff --git a/base/Applications/Network/TcpGulp/TcpGulp.cs b/base/Applications/Network/TcpGulp/TcpGulp.cs new file mode 100644 index 0000000..5dda84d --- /dev/null +++ b/base/Applications/Network/TcpGulp/TcpGulp.cs @@ -0,0 +1,206 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: TcpGulp.cs +// +// Note: Simple Singularity test program. +// +using System; +using System.Diagnostics; +using System.Net.IP; + +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using NetStack.Contracts; +using NetStack.Channels.Public; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications.Network +{ + [ConsoleCategory(HelpMessage="Blast TCP data to a ipAddress, port", DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef tcpRef; + + [StringParameter( "ipAddress", Mandatory=true, Position=0, HelpMessage="IP Address to send to")] + internal string ipAddress; + + + [StringParameter( "port", Mandatory=true, Position=1, HelpMessage="port to blats")] + internal string port; + + reflective internal Parameters(); + + internal int AppMain() { + return TcpGulp.AppMain(this); + } + } + + public class TcpGulp + { + public static int Gulp(TcpConnectionContract.Imp:ReadyState! tcpConn, IPv4 address, ushort port) + { + Console.WriteLine("TcpGulp({0}, {1})", address, port); + + try + { + // Try to connect to the remote host + tcpConn.SendConnect((uint)address, port); + + switch receive + { + case tcpConn.CouldNotConnect(TcpError error): + { + Console.WriteLine("Failed to connect: TcpError = " + System.Net.Sockets.TcpException.GetMessageForTcpError(error)); + return -1; + } + break; + + case tcpConn.OK() : + // success; + break; + + case tcpConn.ChannelClosed() : + // how rude + Console.WriteLine("Netstack channel closed unexpectedly"); + return -1; + break; + } + + Console.WriteLine("Connected"); + bool connected = true; + int messages = 0; + int bytesRead = 0; + + while(connected) + { + tcpConn.SendRead(); + + switch receive + { + case tcpConn.Data(byte[]! in ExHeap data) : + //Console.Write('.'); + messages++; + bytesRead += data.Length; +#if false + Console.WriteLine("Read {0} bytes :", data.Length); + + for(int i = 0; i < data.Length; ++i) + { + if (data[i] < 32) + { Console.Write("<" + (int)data[i] + ">"); } + else + { Console.Write((char)data[i]); } + } +#endif + delete data; + break; + + case tcpConn.ConnectionClosed() : + tcpConn.SendClose(); // Zombie -> Closed + connected = false; + break; + + case tcpConn.NoMoreData() : + // We're never going to send anything + tcpConn.SendClose(); // SendOnly -> Closed + connected = false; + break; + + case tcpConn.ChannelClosed() : + // How rude + connected = false; + break; + } + } + + Console.WriteLine("\nConnection closed"); + Console.WriteLine("got {0} messages {1} bytes ", + messages, bytesRead); + } + catch (Exception e) + { + Console.WriteLine("Unexpected exception: {0}", e); + } + finally + { + } + + return 0; + } + + public static void Usage() + { + Console.WriteLine("tcpgulp "); + } + + internal static int AppMain(Parameters! config) + { + IPv4 host; + + + + try + { + host = IPv4.Parse(config.ipAddress); + } + catch (FormatException e) + { + Console.WriteLine("{0}: {1}", e, config.ipAddress); + return -1; + } + + ushort port; + try + { + port = UInt16.Parse(config.port); + } + catch (FormatException) + { + Console.WriteLine("Malformed port number: {0}", config.port); + return -1; + } + catch (OverflowException) + { + Console.WriteLine("Port number out of range: {0}", config.port); + return -1; + } + + TcpContract.Imp tcpConn = (config.tcpRef).Acquire(); + if (tcpConn == null) + { + Console.WriteLine("Could not initialize TCP endpoint."); + return 1; + } + tcpConn.RecvReady(); + + TcpConnectionContract.Imp! connImp; + TcpConnectionContract.Exp! connExp; + TcpConnectionContract.NewChannel(out connImp, out connExp); + + tcpConn.SendCreateTcpSession(connExp); + connImp.RecvReady(); + delete tcpConn; + + int result = Gulp(connImp, host, port); + delete connImp; + return result; + } + } // end class TcpGulp +} diff --git a/base/Applications/Network/TcpGulp/TcpGulp.csproj b/base/Applications/Network/TcpGulp/TcpGulp.csproj new file mode 100644 index 0000000..d3c5c88 --- /dev/null +++ b/base/Applications/Network/TcpGulp/TcpGulp.csproj @@ -0,0 +1,26 @@ + + + + + + + Exe + TcpGulp + true + + + + + + + + + diff --git a/base/Applications/Network/UdpBlast/UdpBlast.cs b/base/Applications/Network/UdpBlast/UdpBlast.cs new file mode 100644 index 0000000..817a30e --- /dev/null +++ b/base/Applications/Network/UdpBlast/UdpBlast.cs @@ -0,0 +1,248 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: UdpBlast.cs +// +// Note: Simple Singularity test program. +// +using System; +using System.Diagnostics; +using System.Net.IP; +using System.Threading; + +using Microsoft.Singularity; +using Microsoft.SingSharp; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using NetStack.Contracts; +using NetStack.Channels.Public; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications.Network { + [ConsoleCategory(HelpMessage="Send UDP data to and ipAddress and port", + DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef udpRef; + + [LongParameter("p", Mandatory=false, HelpMessage="Packet size (bytes)", Default = 1500)] + internal long packetBytes; + + [LongParameter("r", Mandatory=false, HelpMessage="Transmission rate in bits per second", Default = 64000)] + internal long bitsPerSecond; + + [LongParameter("t", Mandatory=false, HelpMessage="Seconds to send packets for", Default = 30)] + internal long seconds; + + [BoolParameter("v", Mandatory=false, HelpMessage="Verbose output", Default = true)] + internal bool verbose; + + [StringParameter("Address", Mandatory=true, Position=0, HelpMessage="Destination IP Address")] + internal string address; + + [LongParameter("port", Mandatory=true, Position=1, HelpMessage="Destination UDP port")] + internal long port; + + reflective internal Parameters(); + + internal int AppMain() { + return UdpBlast.AppMain(this); + } + } + + public class UdpBlast + { + private const uint FixedHeaderBytes = 42; // Ether + IP + UDP + + private static bool verbose; + + public static void VerboseWriteLine(string format, + params Object [] args) + { + string msg = String.Format(format, args); + DebugStub.WriteLine(msg); + if (verbose) { + Console.WriteLine(format, args); + } + } + + private static void + SendPackets( + UdpConnectionContract.Imp:ReadyState! udpConn, + long bitsPerSecond, + uint bytesPerPacket, + long durationSeconds + ) + { + DateTime startTime = DateTime.Now; + DateTime endTime = (startTime + + TimeSpan.FromSeconds(durationSeconds)); + + DateTime secondStart = startTime; + DateTime secondEnd = startTime + TimeSpan.FromSeconds(1); + + DateTime now = startTime; + + uint second = 0; + long bitsThisSecond = 0; + long totalBits = 0; + + while (now < endTime) { + int pps = 0; + + while (now < secondEnd && bitsThisSecond < bitsPerSecond) { + // XXX: Just bursting packets out for + // now rather than pacing them, + // interested mainly in saturation case. + byte[] in ExHeap pkt; + uint pktSize; + if ((long)bytesPerPacket * 8 < bitsPerSecond - bitsThisSecond) { + pktSize = bytesPerPacket; + } + else { + pktSize = (uint)((bitsPerSecond - bitsThisSecond) / 8); + if (pktSize <= FixedHeaderBytes) { + pktSize = FixedHeaderBytes + 1; + } + } + pkt = new [ExHeap] byte [pktSize - FixedHeaderBytes]; + udpConn.SendWrite(pkt); + udpConn.RecvOK(); + bitsThisSecond += pktSize * 8; + now = DateTime.Now; + pps++; + } + + while (now < secondEnd) { + Thread.Sleep(0); + now = DateTime.Now; + } + + TimeSpan tau = secondEnd - secondStart; + VerboseWriteLine( + "Round {0} duration(secs) {1:f2} rate (pps) {2} rate (bps) {3:e3}", + second, tau.TotalSeconds, + pps, + bitsThisSecond / tau.TotalSeconds); + second++; + totalBits += bitsThisSecond; + bitsThisSecond = 0; + secondStart = now; + secondEnd = now + TimeSpan.FromSeconds(1); + } + + Console.WriteLine( + "Average rate: {0:e3} bps", + totalBits / (now - startTime).TotalSeconds + ); + } + + public static int + Blast( + [Claims] UdpConnectionContract.Imp:ReadyState! udpConn, + IPv4 address, + ushort port, + long bitsPerSecond, + long bytesPerPacket, + long durationSeconds + ) + { + Console.WriteLine("UdpBlast({0}, {1})", address, port); + + try { + udpConn.SendConnectWithAnyLocalEndPoint((uint)address, port); + + switch receive { + case udpConn.OK() : + // success; + Console.WriteLine("Connected"); + break; + + case udpConn.InvalidEndPoint(ip, rejectedPort) : + throw new Exception("udpConn address and port rejected"); + + case udpConn.ChannelClosed() : + throw new Exception("udpConn channel closed"); + } + + SendPackets(udpConn, + bitsPerSecond, + (uint)bytesPerPacket, + durationSeconds); + Console.WriteLine("Closing connection"); + + udpConn.SendClose(); + } + catch (Exception e) { + Console.WriteLine("Unexpected exception: {0}", e); + } + finally { + delete udpConn; + } + + return 0; + } + + internal static int AppMain(Parameters! config) + { + IPv4 host; + try { + host = IPv4.Parse(config.address); + } + catch (FormatException e) { + Console.WriteLine("{0}: {1}", e, config.address); + return -1; + } + + if (config.port > 65536 || config.port < 0) { + Console.WriteLine("Port number out of range: {0}", config.port); + return -1; + } + ushort port = (ushort) config.port; + + if ((uint)config.packetBytes < FixedHeaderBytes) { + Console.WriteLine("Packet size needs to be larger than fixed header size ({0} bytes)", FixedHeaderBytes); + return -1; + } + + UdpBlast.verbose = config.verbose; + + UdpContract.Imp udpConn = ((!)config.udpRef).Acquire(); + if (udpConn == null) { + Console.WriteLine("Could not initialize TCP endpoint."); + return 1; + } + udpConn.RecvReady(); + + UdpConnectionContract.Imp! connImp; + UdpConnectionContract.Exp! connExp; + UdpConnectionContract.NewChannel(out connImp, out connExp); + + udpConn.SendCreateUdpSession(connExp); + connImp.RecvReady(); + delete udpConn; + + return Blast(connImp, + host, port, + config.bitsPerSecond, + config.packetBytes, + config.seconds + ); + } + } // end class UdpBlast +} diff --git a/base/Applications/Network/UdpBlast/UdpBlast.csproj b/base/Applications/Network/UdpBlast/UdpBlast.csproj new file mode 100644 index 0000000..368ad66 --- /dev/null +++ b/base/Applications/Network/UdpBlast/UdpBlast.csproj @@ -0,0 +1,27 @@ + + + + + + + Exe + UdpBlast + + + + + + + + + diff --git a/base/Applications/Network/UdpGulp/UdpGulp.cs b/base/Applications/Network/UdpGulp/UdpGulp.cs new file mode 100644 index 0000000..e533446 --- /dev/null +++ b/base/Applications/Network/UdpGulp/UdpGulp.cs @@ -0,0 +1,189 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: UdpGulp.cs +// +// Note: Simple Singularity test program. +// +using System; +using System.Diagnostics; +using System.Net.IP; +using System.Threading; + +using Microsoft.Singularity; +using Microsoft.SingSharp; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using NetStack.Contracts; +using NetStack.Channels.Public; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications.Network +{ + [ConsoleCategory(HelpMessage="Receive UDP data from a ipAddress, port", + DefaultAction = true)] + internal class Parameters + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef udpRef; + + [LongParameter("t", Mandatory = false, HelpMessage = "Seconds to send packets for", Default = 30)] + internal long seconds; + + [StringParameter("a", Mandatory = false, HelpMessage = "Local address to bind to.", Default = "0.0.0.0")] + internal string address; + + [LongParameter("port", Mandatory = true, Position = 0, HelpMessage = "port to gulp from")] + internal long port; + + reflective internal Parameters(); + + internal int AppMain() + { + return UdpGulp.AppMain(this); + } + } + + public class UdpGulp + { + private const int FixedHeaderBytes = 42; // Ether + IP + UDP + + private static void + ReceivePackets( + UdpConnectionContract.Imp:ReadyState! udpConn, + long totalSeconds + ) + { + int bytesThisRound = 0; + + DateTime now = DateTime.Now; + DateTime epochEnd = now + TimeSpan.FromSeconds(1); + DateTime epochStart = now; + + while (--totalSeconds >= 0) { + while (now < epochEnd) { + udpConn.SendPollRead((epochEnd - now).Milliseconds); + switch receive { + case udpConn.NoData() : + // No data to read. This doesn't + // necessarily mean the connection + // is closed. + Thread.Yield(); + break; + case udpConn.Data(uint addr, ushort port2, + byte[]! in ExHeap data): + bytesThisRound += data.Length + FixedHeaderBytes; + delete data; + break; + case udpConn.ChannelClosed(): + throw new Exception("udpConn channel closed"); + } + now = DateTime.Now; + } + + TimeSpan delta = now - epochStart; + Console.WriteLine( + "Duration(s) {0:f2} rate(bps) {1:e3} bps", + delta.TotalSeconds, + 8.0 * bytesThisRound / delta.TotalSeconds); + bytesThisRound = 0; + epochStart = DateTime.Now; + epochEnd = epochStart + TimeSpan.FromSeconds(1); + } + } + + public static int + Gulp([Claims] UdpConnectionContract.Imp:ReadyState! udpConn, + IPv4 address, + ushort port, + long totalSeconds) + { + Console.WriteLine("UdpGulp({0}, {1})", address, port); + + try { + // Bind local endpoint + udpConn.SendBindLocalEndPoint((uint)address, port); + + switch receive { + case udpConn.OK() : + // success; + Console.WriteLine("Connected"); + break; + + case udpConn.InvalidEndPoint(ip, rejectedPort) : + throw new Exception("udpConn address and port rejected"); + + case udpConn.ChannelClosed() : + throw new Exception("udpConn channel closed"); + } + + ReceivePackets(udpConn, totalSeconds); + + Console.WriteLine("Closing connection"); + udpConn.SendClose(); + } + catch (Exception e) + { + Console.WriteLine("Unexpected exception: {0}", e); + } + finally { + delete udpConn; + } + return 0; + } + + internal static int AppMain(Parameters! config) + { + IPv4 host; + try { + host = IPv4.Parse(config.address); + } + catch (FormatException e) { + Console.WriteLine("{0}: {1}", e, config.address); + return -1; + } + + if (config.port > 0xffff || config.port < 0) { + Console.WriteLine("Port number out of range: {0}", + config.port); + return -1; + } + ushort port = (ushort) config.port; + + UdpContract.Imp udpConn = (config.udpRef).Acquire(); + if (udpConn == null) { + Console.WriteLine("Could not initialize TCP endpoint."); + return 1; + } + + Console.WriteLine("Waiting for ready"); + udpConn.RecvReady(); + + UdpConnectionContract.Imp! connImp; + UdpConnectionContract.Exp! connExp; + UdpConnectionContract.NewChannel(out connImp, out connExp); + + Console.WriteLine("Creating session"); + udpConn.SendCreateUdpSession(connExp); + connImp.RecvReady(); + delete udpConn; + Console.WriteLine("Ready"); + return Gulp(connImp, host, port, config.seconds); + } + } // end class UdpGulp +} diff --git a/base/Applications/Network/UdpGulp/UdpGulp.csproj b/base/Applications/Network/UdpGulp/UdpGulp.csproj new file mode 100644 index 0000000..1613eb9 --- /dev/null +++ b/base/Applications/Network/UdpGulp/UdpGulp.csproj @@ -0,0 +1,26 @@ + + + + + + + Exe + UdpGulp + true + + + + + + + + + diff --git a/base/Applications/Paths.targets b/base/Applications/Paths.targets new file mode 100644 index 0000000..57e0203 --- /dev/null +++ b/base/Applications/Paths.targets @@ -0,0 +1,16 @@ + + + + diff --git a/base/Applications/PingPongIntTest/PingPongIntTest.csproj b/base/Applications/PingPongIntTest/PingPongIntTest.csproj new file mode 100644 index 0000000..34ee103 --- /dev/null +++ b/base/Applications/PingPongIntTest/PingPongIntTest.csproj @@ -0,0 +1,25 @@ + + + + + + + Exe + PingPongIntTest + + + + + + + + + diff --git a/base/Applications/PingPongIntTest/PingPongIntTest.sg b/base/Applications/PingPongIntTest/PingPongIntTest.sg new file mode 100644 index 0000000..f937d2d --- /dev/null +++ b/base/Applications/PingPongIntTest/PingPongIntTest.sg @@ -0,0 +1,38 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: PingPongIntTest.cs +// +// Note: Simple Singularity test program. +// +using System; +using Microsoft.Singularity.V1.Services; +using Microsoft.Singularity.Processor; + + +namespace Microsoft.Singularity.Applications +{ + public class PingPongIntTest + { + public static int Main(String[] args) + { + Console.WriteLine("PingPongIntTest World!"); + + //uint a, b, c, d; + //Processor.ReadCpuid(0, out a, out b, out c, out d); + + int retval = ProcessService.RunPingPongInt(7); + if (retval == 0) { + Console.WriteLine(" Retval: {0} -- successful", retval); + } + else { + Console.WriteLine(" Retval: {0} -- fail", retval); + } + + return 0; + } + } +} diff --git a/base/Applications/Play/Play.csproj b/base/Applications/Play/Play.csproj new file mode 100644 index 0000000..79b6801 --- /dev/null +++ b/base/Applications/Play/Play.csproj @@ -0,0 +1,32 @@ + + + + + + + Exe + Play + true + {C9030FC5-CDB7-4F5B-980C-5B72F8B92232} + + + + + + WavAudio + Microsoft.Singularity.Applications + Content + true + + + + + diff --git a/base/Applications/Play/Play.sg b/base/Applications/Play/Play.sg new file mode 100644 index 0000000..d2b45b0 --- /dev/null +++ b/base/Applications/Play/Play.sg @@ -0,0 +1,139 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Play.sg +// +// Note: Simple audio test program. +// +using System; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; +using System.Threading; +using Microsoft.Contracts; + +using Microsoft.SingSharp; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; + +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications +{ + // use driver category for now. + // Once the appropriate categories have been defined this will need to change + // Also waiting for Compile Time reflection to eliminate static constructor etc. + + [ConsoleCategory(DefaultAction=true)] + internal sealed class PlayConfiguration + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef ImpRef; + + reflective internal PlayConfiguration(); + + internal int AppMain() { + return Play.AppMain(this); + } + + } + + public class Play + { + private static SoundDeviceContract.Imp:Ready OpenSoundDevice(PlayConfiguration! config) + { + // extract imp handed in as part of process creation + SoundDeviceContract.Imp! imp = (config.ImpRef).Acquire(); + + // get it into the ready state + Console.WriteLine("[{0}] Waiting for SB channel.", Thread.CurrentThread.GetThreadId()); + switch receive + { + case imp.Success(): + Console.WriteLine("[{0}] Got SB channel.", Thread.CurrentThread.GetThreadId()); + break; + case imp.ContractNotSupported(): + delete imp; + throw new Exception("Didn't Get SB channel. (ContractNotSupported)"); + case imp.ChannelClosed(): + delete imp; + throw new Exception("Didn't Get SB channel. (Channel closed)"); + } + return imp; + } + + internal static int AppMain(PlayConfiguration! config) + { + if (WavAudio.Content == null || WavAudio.Content.Length == 0) { + Console.WriteLine("No WAV audio to play."); + return 1; + } + + return DoPlay(config); + + return 0; + } + + private static int DoPlay(PlayConfiguration! config) { + SoundDeviceContract.Imp audio = OpenSoundDevice(config); + if (audio == null) { + Console.WriteLine("Couldn't open audio device."); + return 2; + } + + int threadId = Thread.CurrentThread.GetThreadId(); + + assume WavAudio.Content != null; + + try { + for (int i = 0; i < WavAudio.Content.Length; i++) { + Console.WriteLine("[{1}] Playing WAV audio {0}.", i, threadId); + + byte[] wav = (!)WavAudio.Content[i]; + + byte[] in ExHeap buffer = Bitter.FromByteArray(wav); + + // Copy contents into buffer WavAudio.Content[i] + + audio.SendPlayWav(buffer); + switch receive + { + case audio.RecvAckPlayWav(oldbuffer): + Console.WriteLine("[{1}] Done playing WAV audio {0}.", i, + threadId); + delete oldbuffer; + break; + + case audio.RecvNakPlayWav(oldbuffer): + Console.WriteLine("[{1}] Failed to play WAV audio {0}.", + i, threadId); + delete oldbuffer; + break; + + case audio.ChannelClosed(): + Console.WriteLine("[{1}] SoundDevice channel closed unexpectedly {0}.", + i, threadId); + return 1; + } + } + } + finally { + delete audio; + } + return 0; + } + } +} diff --git a/base/Applications/Play/Resources/wav16m.wav b/base/Applications/Play/Resources/wav16m.wav new file mode 100644 index 0000000..dd2bbc3 Binary files /dev/null and b/base/Applications/Play/Resources/wav16m.wav differ diff --git a/base/Applications/Play/Resources/wav16s.wav b/base/Applications/Play/Resources/wav16s.wav new file mode 100644 index 0000000..92f206c Binary files /dev/null and b/base/Applications/Play/Resources/wav16s.wav differ diff --git a/base/Applications/Play/Resources/wav8m.wav b/base/Applications/Play/Resources/wav8m.wav new file mode 100644 index 0000000..66e3d9d Binary files /dev/null and b/base/Applications/Play/Resources/wav8m.wav differ diff --git a/base/Applications/Pong/Pong.cs b/base/Applications/Pong/Pong.cs new file mode 100644 index 0000000..4049e59 --- /dev/null +++ b/base/Applications/Pong/Pong.cs @@ -0,0 +1,663 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Pong.cs +// +// Note: +// + +using System; +using System.Text; +using System.GC; +using System.Runtime.Remoting; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Collections; +using System.Diagnostics; + +using Microsoft.Singularity; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.V1.Services; +using Microsoft.Singularity.Io; + +using Microsoft.Singularity.Channels; +using Keyboard = Microsoft.Singularity.Io.Keyboard; + +namespace Microsoft.Singularity.Shell +{ + public class Pong + { + const int screenWidth = 1024; + const int screenHeight = 768; + + const int paddleWidth = 16; + const int paddleHeight = 128; + + const int ballSize = 8; + + const double paddleSpeed = 0.20; + const double ballSpeed = 0.35; + + const double ballStartAngle = Math.PI / 8; + const double ballMaxAngle = Math.PI / 3; + + const int screenMinX = 0; + const int screenMinY = 0; + + const int screenMaxX = screenMinX + screenWidth - 1; + const int screenMaxY = screenMinY + screenHeight - 1; + + const int paddleMin = screenMinY; + const int paddleMax = screenMaxY - paddleHeight; + + const int ballMinX = screenMinX + paddleWidth; + const int ballMaxX = screenMaxX - paddleWidth - ballSize; + + const int ballMinY = screenMinY; + const int ballMaxY = screenMaxY - ballSize; + + const int paddleInit = screenMinY + ((screenHeight - paddleHeight) / 2); + + double ballX = 0.0; + double ballY = 0.0; + double ballAngle = 0.0; + + int ballDrawX = 0; + int ballDrawY = 0; + + double[] paddlesY = new double [2] { paddleInit, paddleInit }; + + int[] paddlesDrawX = new int [2] { screenMinX, + screenMaxX - paddleWidth + 1 }; + + int[] paddlesDrawY = new int [2] { paddleInit, paddleInit }; + + bool[] inputUp = new bool [2] { false, false }; + bool[] inputDown = new bool [2] { false, false }; + + int[] scores = new int [2] { 0, 0 }; + + int lastWinner = 0; + + bool done = false; + bool playing = false; + + ISvgaDevice svga = null; + + Random random = new Random(); + + public static KeyboardDeviceContract.Imp OpenKeyboard(string! devName) + { + KeyboardDeviceContract.Exp! exp; + KeyboardDeviceContract.Imp! imp; + KeyboardDeviceContract.NewChannel(out imp, out exp); + + // get NS endpoint + DirectoryServiceContract.Imp ns = DirectoryService.NewClientEndpoint(); + + bool success = false; + ns.SendBind(Bitter.FromString2(devName),exp); + switch receive + { + case ns.AckBind(): + success = true; + break; + case ns.NakBind(exp): + delete exp; + break; + case ns.ChannelClosed(): + break; + } + + if (!success) + { + DebugStub.Print("OpenKeyboard lookup of {0} failed.\n", + __arglist(devName); + + delete imp; + delete ns; + return null; + } + + switch receive + { + case imp.Success(): + break; + case unsatisfiable: + throw new Exception("Didn't imp.RecvAckConnect"); + break; + } + + delete ns; + return imp; + } + + + public static VideoDeviceContract.Imp OpenVideo(string! devName) + { + VideoDeviceContract.Exp! exp; + VideoDeviceContract.Imp! imp; + VideoDeviceContract.NewChannel(out imp, out exp); + + // get NS endpoint + DirectoryServiceContract.Imp ns = DirectoryService.NewClientEndpoint(); + + bool success = false; + ns.SendBind(Bitter.FromString2(devName),exp); + switch receive + { + case ns.AckBind(): + success = true; + break; + case ns.NakBind(reject): + delete reject; + break; + case ns.ChannelClosed(): + break; + } + + if (!success) + { + DebugStub.Print("OpenVideo lookup of {0} failed.\n", + __arglist(devName)); + + delete imp; + delete ns; + return null; + } + + switch receive + { + case imp.Success(): + break; + case unsatisfiable: + throw new Exception("Didn't imp.RecvAckConnect"); + break; + } + + delete ns; + return imp; + } + + public static int Main(string[] args) + { + VideoDeviceContract.Imp video = OpenVideo("/dev/video"); + + Console.WriteLine("Singularity Slide Show Viewer (PID={0})", + ProcessService.GetCurrentProcessId()); + + if (video == null) + { + Console.WriteLine("Can only display slides on a graphic display."); + return 1; + } + if (Slides.Content == null || Slides.Content.Length == 0) + { + Console.WriteLine("No slides to display."); + delete video; + return 1; + } + + KeyboardDeviceContract.Imp keyboard = OpenKeyboard("/dev/keyboard"); + if (keyboard == null) { + // TODO: show keyboardless slides with timer? + delete video; + return 1; + } + int slide = 0; + + byte[] currentSlide = (!)Slides.Content[slide]; + byte * opt(ExHeap[]) current = new[ExHeap] byte [currentSlide.Length]; + Bitter.FromByteArray(current, 0, currentSlide.Length, + currentSlide, 0); + video.SendFill(0, 0, 1023, 767, 0); + video.RecvAckFill(); + video.SendBitBltBmp(32, 16, current); + video.RecvAckBitBltBmp(out current); + + for (;;) + { + int x; + int y; + bool go_back = false; + bool go_fore = false; + bool go_home = false; + bool go_end = false; + + uint key = 0; + keyboard.SendGetKey(); + switch receive + { + case keyboard.AckKey(ikey): + key = ikey; + break; + case keyboard.NakKey(): + break; + case unsatisfiable: + throw new Exception("Didn't get reply from Keyboard"); + } + + if (key == 0) { + Tracing.Log(Tracing.Warning, "GetKey failed."); + break; + } + if ((key & (uint)Keyboard.Qualifiers.KEY_DOWN) == 0) + { + continue; + } + if ((key & (uint)Keyboard.Qualifiers.KEY_MOUSE) == 0) + { + char c = (char)(key & (uint)Keyboard.Qualifiers.KEY_BASE_CODE); + + switch (c) + { + case (char)Keyboard.Keys.ESCAPE: + delete video; + delete keyboard; + delete current; + return 0; + case (char)Keyboard.Keys.HOME: + go_home = true; + break; + case (char)Keyboard.Keys.UP_ARROW: + case (char)Keyboard.Keys.LEFT_ARROW: + case (char)Keyboard.Keys.PAGE_UP: + case '\b': + go_back = true; + break; + case (char)Keyboard.Keys.DOWN_ARROW: + case (char)Keyboard.Keys.RIGHT_ARROW: + case (char)Keyboard.Keys.PAGE_DOWN: + case '\n': + case ' ': + go_fore = true; + break; + case (char)Keyboard.Keys.END: + go_end = true; + break; + default: + continue; + } + } + else + { + if ((key & (uint)Keyboard.Qualifiers.MOUSE_BUTTON_1) != 0) + { + go_fore = true; + } + else if ((key & (uint)Keyboard.Qualifiers.MOUSE_BUTTON_0) != 0) + { + go_back = true; + } + else + { + continue; + } + } + + if (go_home) + { + slide = 0; + } + else if (go_fore) + { + if (++slide >= Slides.Content.Length) + { + slide = Slides.Content.Length - 1; + } + } + else if (go_back) + { + if (--slide < 0) + { + slide = 0; + } + } + else if (go_end) + { + slide = Slides.Content.Length - 1; + } + + + if (Slides.Content.Length > 0) + { + currentSlide = (!)Slides.Content[slide]; + if (current.Length < currentSlide.Length) { + delete current; + current = new[ExHeap] byte [currentSlide.Length]; + } + Bitter.FromByteArray(current, 0, currentSlide.Length, + currentSlide, 0); + video.SendFill(0, 0, 1023, 767, 0); + video.RecvAckFill(); + video.SendBitBltBmp(32, 16, current); + video.RecvAckBitBltBmp(out current); + } + else { + video.SendFill(0, 0, 1023, 767, 0); + video.RecvAckFill(); + } + } + delete keyboard; + delete video; + delete current; + + return 0; + } + public Pong() + { + svga = IoSystem.FindDeviceWithInterface(typeof(ISvgaDevice)) + as ISvgaDevice; + } + + public void DrawPaddle(int paddle, bool erase) + { + svga.Fill(paddlesDrawX[paddle], + paddlesDrawY[paddle], + paddlesDrawX[paddle] + paddleWidth - 1, + paddlesDrawY[paddle] + paddleHeight - 1, + erase ? RGB.Black : RGB.Blue); + } + + public void RedrawPaddle(int paddle) + { + if (paddlesDrawY[paddle] != (int) paddlesY[paddle]) { + DrawPaddle(paddle, true); + + paddlesDrawY[paddle] = (int) paddlesY[paddle]; + + DrawPaddle(paddle, false); + } + } + + public void MovePaddle(int paddle) + { + paddlesY[paddle] += GetPaddleState(paddle) * paddleSpeed; + + if (paddlesY[paddle] > paddleMax) { + paddlesY[paddle] = paddleMax; + } + else if (paddlesY[paddle] < paddleMin) { + paddlesY[paddle] = paddleMin; + } + + RedrawPaddle(paddle); + } + + public bool PaddleHit(int paddle) + { + return ((ballY > paddlesY[paddle] - ballSize) && + (ballY < paddlesY[paddle] + paddleHeight)); + } + + public void ResetBall() + { + ballY = screenMinY + ((screenHeight - ballSize) / 2); + ballAngle = (random.NextDouble() * ballStartAngle) - + (ballStartAngle / 2); + + if (lastWinner == 0) { + ballX = ballMinX; + if (ballAngle < 0) { + ballAngle += 2 * Math.PI; + } + } + else { + ballX = ballMaxX; + ballAngle += Math.PI; + } + + ballDrawX = (int) ballX; + ballDrawY = (int) ballY; + } + + public void DrawBall(bool erase) + { + svga.Fill(ballDrawX, ballDrawY, + ballDrawX + ballSize - 1, ballDrawY + ballSize - 1, + erase ? RGB.Black : RGB.Red); + } + + public void RedrawBall() + { + if (ballDrawX != (int) ballX || ballDrawY != (int) ballY) { + DrawBall(true); + + ballDrawX = (int) ballX; + ballDrawY = (int) ballY; + + DrawBall(false); + } + } + + public void ReflectBallY(int line) + { + ballY = (2 * line) - ballY; + ballAngle = (2 * Math.PI) - ballAngle; + } + + public void SetAngle(int paddle) + { + // Find out where the ball hit the paddle, from -1 to 1. + double ratio = ((ballY + (ballSize / 2)) - + (paddlesY[paddle] + (paddleHeight / 2))) / + ((paddleHeight + ballSize) / 2); + + // Set the new angle accordingly. + ballAngle = ratio * ballMaxAngle; + + if (paddle == 0) { + if (ballAngle < 0) { + ballAngle += 2 * Math.PI; + } + } + else { + ballAngle = Math.PI - ballAngle; + } + } + + public void MoveBall() + { + ballY += Math.Sin(ballAngle) * ballSpeed; + if (ballY < ballMinY) { + ReflectBallY(ballMinY); + } + else if (ballY > ballMaxY) { + ReflectBallY(ballMaxY); + } + + ballX += Math.Cos(ballAngle) * ballSpeed; + if (ballX < ballMinX) { + if (PaddleHit(0)) { + SetAngle(0); + } + else { + lastWinner = 1; + playing = false; + } + } + else if (ballX > ballMaxX) { + if (PaddleHit(1)) { + SetAngle(1); + } + else { + lastWinner = 0; + playing = false; + } + } + + RedrawBall(); + } + + public int GetPaddleState(int paddle) + { + int result; + + if (inputUp[paddle]) { + result = -1; + } + else if (inputDown[paddle]) { + result = 1; + } + else { + result = 0; + } + + return result; + } + + public void SetStateFromChar(char c, bool @state) + { + switch (c) { + case (char)Keyboard.Keys.UP_ARROW: + inputUp[1] = @state; + break; + case (char)Keyboard.Keys.DOWN_ARROW: + inputDown[1] = @state; + break; + case 'a': + inputUp[0] = @state; + break; + case 'z': + inputDown[0] = @state; + break; + } + } + + public void GetInput(KeyboardDeviceContract.Imp keyboard) + { + uint key = 0; + keyboard.SendPollKey(); + switch receive + { + case keyboard.AckKey(ikey): + key = ikey; + break; + case keyboard.NakKey(): + key = 0; + break; + case unsatisfiable: + throw new Exception("Didn't get reply from Keyboard"); + } + + char c = (char) (key & (uint) Keyboard.Qualifiers.KEY_BASE_CODE); + + if ((key & (uint) Keyboard.Qualifiers.KEY_DOWN) != 0) { + switch (c) { + case (char) Keyboard.Keys.ESCAPE: + done = true; + break; + case ' ': + if (!playing) { + ResetBall(); + ClearScreen(); + DrawPaddle(0, false); + DrawPaddle(1, false); + DrawBall(false); + playing = true; + } + break; + default: + SetStateFromChar(c, true); + break; + } + } + else if ((key & (uint) Keyboard.Qualifiers.KEY_UP) != 0) { + SetStateFromChar(c, false); + } + } + + public void FillScreen(RGB color) + { + svga.Fill(screenMinX, screenMinY, screenMaxX, screenMaxY, color); + } + + public void ClearScreen() + { + FillScreen(RGB.Black); + } + + public void FlashScreen() + { + FillScreen(RGB.Red); + Sleep(1000); + FillScreen(RGB.Green); + Sleep(1000); + FillScreen(RGB.Blue); + Sleep(1000); + } + + public void ShowMessage() + { + ClearScreen(); + + for (int i = 0; i < 100; i++) { + Console.WriteLine(); + } + + Console.Write(" "); + Console.Write("Left: {0,-10}", scores[0]); + Console.Write(" "); + Console.Write("Right: {0,-10}", scores[1]); + Console.WriteLine(); + Console.WriteLine(); + Console.Write(" "); + Console.Write("Press space to begin or escape to quit..."); + Console.WriteLine(); + + DrawPaddle(0, false); + DrawPaddle(1, false); + DrawBall(false); + } + + public void Play() + { + KeyboardDeviceContract.Imp keyboard = Shell.OpenKeyboard("/dev/keyboard"); + + Console.CursorHide(); + + ShowMessage(); + + while (!done) { + GetInput(keyboard); + + if (playing) { + MovePaddle(0); + MovePaddle(1); + MoveBall(); + + if (!playing) { + scores[lastWinner]++; + FlashScreen(); + ShowMessage(); + } + } + + Sleep(10); + } + + ClearScreen(); + + Console.CursorShow(); + } + + public void Sleep(int multiplier) + { + for (int j = 0; j < multiplier; j++) { + for (int i = 0; i < 10000; i++) { + // Do nothing. + } + } + } + + public static int Run(string[] args) + { + (new Pong()).Play(); + return 0; + } + } +} diff --git a/base/Applications/Pong/Pong.csproj b/base/Applications/Pong/Pong.csproj new file mode 100644 index 0000000..05b8c3b --- /dev/null +++ b/base/Applications/Pong/Pong.csproj @@ -0,0 +1,21 @@ + + + + + + Exe + Pong + true + + + + + + + + + + + + + diff --git a/base/Applications/Pong/Pong.sg b/base/Applications/Pong/Pong.sg new file mode 100644 index 0000000..f4ea4d8 --- /dev/null +++ b/base/Applications/Pong/Pong.sg @@ -0,0 +1,510 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Pong.cs +// +// Note: +// + +using System; +using System.Text; +using System.GC; +using System.Runtime.Remoting; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Collections; +using System.Diagnostics; + +using Microsoft.Singularity; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.V1.Services; +using Microsoft.Singularity.Io; + +using Microsoft.Singularity.Channels; +using Keyboard = Microsoft.Singularity.Io.Keyboard; + +namespace Microsoft.Singularity.Applications +{ + public class Pong + { + const uint Black = 0x000000; + const uint Blue = 0x0000ff; + const uint Green = 0x00ff00; + const uint Red = 0xff0000; + const uint White = 0xffffff; + + const int screenWidth = 1024; + const int screenHeight = 768; + + const int paddleWidth = 16; + const int paddleHeight = 128; + + const int ballSize = 8; + + const double paddleSpeed = 0.20; + const double ballSpeed = 0.35; + + const double ballStartAngle = Math.PI / 8; + const double ballMaxAngle = Math.PI / 3; + + const int screenMinX = 0; + const int screenMinY = 0; + + const int screenMaxX = screenMinX + screenWidth - 1; + const int screenMaxY = screenMinY + screenHeight - 1; + + const int paddleMin = screenMinY; + const int paddleMax = screenMaxY - paddleHeight; + + const int ballMinX = screenMinX + paddleWidth; + const int ballMaxX = screenMaxX - paddleWidth - ballSize; + + const int ballMinY = screenMinY; + const int ballMaxY = screenMaxY - ballSize; + + const int paddleInit = screenMinY + ((screenHeight - paddleHeight) / 2); + + static double ballX = 0.0; + static double ballY = 0.0; + static double ballAngle = 0.0; + + static int ballDrawX = 0; + static int ballDrawY = 0; + + static double[] paddlesY = new double [2] { paddleInit, paddleInit }; + + static int[] paddlesDrawX = new int [2] { screenMinX, + screenMaxX - paddleWidth + 1 }; + + static int[] paddlesDrawY = new int [2] { paddleInit, paddleInit }; + + static bool[] inputUp = new bool [2] { false, false }; + static bool[] inputDown = new bool [2] { false, false }; + + static int[] scores = new int [2] { 0, 0 }; + + static int lastWinner = 0; + + static bool done = false; + static bool playing = false; + + static Random random = new Random(); + + public static KeyboardDeviceContract.Imp:Ready OpenKeyboard(string! devName) + { + KeyboardDeviceContract.Exp! exp; + KeyboardDeviceContract.Imp! imp; + KeyboardDeviceContract.NewChannel(out imp, out exp); + + // get NS endpoint + DirectoryServiceContract.Imp ns = DirectoryService.NewClientEndpoint(); + + bool success = false; + + ErrorCode errorOut; + bool ok = SdsUtils.Bind(devName, ns, exp, out errorOut); + if (!ok) { + if (errorOut == ErrorCode.ChannelClosed) + { + throw new Exception("Encountered a ChannelClosed while opening Keyboard"); + } + } + else { + success = true; + } + /* + // ns.SendBind(Bitter.FromString2(devName),exp); + switch receive { + case ns.AckBind(): + success = true; + break; + case ns.NakBind(rejected,error): + delete rejected; + break; + case ns.ChannelClosed(): + delete ns; + throw new Exception("ns unexpectedly closed"); + } + */ + if (!success) { + DebugStub.WriteLine("OpenKeyboard lookup of {0} failed\n", + __arglist(devName)); + + delete imp; + delete ns; + return null; + } + + switch receive { + case imp.Success(): + break; + case imp.ContractNotSupported(): + throw new Exception("Contract not supported"); + case imp.ChannelClosed(): + throw new Exception("Didn't imp.RecvActConnect"); + } + + delete ns; + return imp; + } + + public static VideoDeviceContract.Imp:Ready OpenVideo(string! devName) + { + VideoDeviceContract.Exp! exp; + VideoDeviceContract.Imp! imp; + VideoDeviceContract.NewChannel(out imp, out exp); + + // get NS endpoint + DirectoryServiceContract.Imp ns = DirectoryService.NewClientEndpoint(); + + bool success = false; + ns.SendBind(Bitter.FromString2(devName),exp); + switch receive { + case ns.AckBind(): + success = true; + break; + case ns.NakBind(rejected, error): + delete rejected; + break; + case ns.ChannelClosed(): + delete ns; + throw new Exception("ns unexpectedly closed"); + } + + if (!success) { + DebugStub.WriteLine("OpenVideo lookup of {0} failed\n", + __arglist(devName)); + + delete imp; + delete ns; + return null; + } + + switch receive { + case imp.Success(): + break; + case imp.ContractNotSupported(): + throw new Exception("Contract not supported"); + case imp.ChannelClosed(): + throw new Exception("Didn't imp.RecvActConnect"); + } + + delete ns; + return imp; + } + + private static void DrawPaddle(VideoDeviceContract.Imp:Ready! video, int paddle, bool erase) + { + video.SendFill(paddlesDrawX[paddle], + paddlesDrawY[paddle], + paddlesDrawX[paddle] + paddleWidth - 1, + paddlesDrawY[paddle] + paddleHeight - 1, + erase ? Black : Blue); + video.RecvAckFill(); + } + + private static void RedrawPaddle(VideoDeviceContract.Imp:Ready! video, int paddle) + { + if (paddlesDrawY[paddle] != (int) paddlesY[paddle]) { + DrawPaddle(video, paddle, true); + + paddlesDrawY[paddle] = (int) paddlesY[paddle]; + + DrawPaddle(video, paddle, false); + } + } + + private static void MovePaddle(VideoDeviceContract.Imp:Ready! video, int paddle) + { + paddlesY[paddle] += GetPaddleState(paddle) * paddleSpeed; + + if (paddlesY[paddle] > paddleMax) { + paddlesY[paddle] = paddleMax; + } + else if (paddlesY[paddle] < paddleMin) { + paddlesY[paddle] = paddleMin; + } + + RedrawPaddle(video, paddle); + } + + private static bool PaddleHit(int paddle) + { + return ((ballY > paddlesY[paddle] - ballSize) && + (ballY < paddlesY[paddle] + paddleHeight)); + } + + private static void ResetBall() + { + ballY = screenMinY + ((screenHeight - ballSize) / 2); + ballAngle = (random.NextDouble() * ballStartAngle) - + (ballStartAngle / 2); + + if (lastWinner == 0) { + ballX = ballMinX; + if (ballAngle < 0) { + ballAngle += 2 * Math.PI; + } + } + else { + ballX = ballMaxX; + ballAngle += Math.PI; + } + + ballDrawX = (int) ballX; + ballDrawY = (int) ballY; + } + + private static void DrawBall(VideoDeviceContract.Imp:Ready! video, bool erase) + { + video.SendFill(ballDrawX, ballDrawY, + ballDrawX + ballSize - 1, ballDrawY + ballSize - 1, + erase ? Black : Red); + video.RecvAckFill(); + } + + private static void RedrawBall(VideoDeviceContract.Imp:Ready! video) + { + if (ballDrawX != (int) ballX || ballDrawY != (int) ballY) { + DrawBall(video, true); + + ballDrawX = (int) ballX; + ballDrawY = (int) ballY; + + DrawBall(video, false); + } + } + + private static void ReflectBallY(int line) + { + ballY = (2 * line) - ballY; + ballAngle = (2 * Math.PI) - ballAngle; + } + + private static void SetAngle(int paddle) + { + // Find out where the ball hit the paddle, from -1 to 1. + double ratio = ((ballY + (ballSize / 2)) - + (paddlesY[paddle] + (paddleHeight / 2))) / + ((paddleHeight + ballSize) / 2); + + // Set the new angle accordingly. + ballAngle = ratio * ballMaxAngle; + + if (paddle == 0) { + if (ballAngle < 0) { + ballAngle += 2 * Math.PI; + } + } + else { + ballAngle = Math.PI - ballAngle; + } + } + + private static void MoveBall(VideoDeviceContract.Imp:Ready! video) + { + ballY += Math.Sin(ballAngle) * ballSpeed; + if (ballY < ballMinY) { + ReflectBallY(ballMinY); + } + else if (ballY > ballMaxY) { + ReflectBallY(ballMaxY); + } + + ballX += Math.Cos(ballAngle) * ballSpeed; + if (ballX < ballMinX) { + if (PaddleHit(0)) { + SetAngle(0); + } + else { + lastWinner = 1; + playing = false; + } + } + else if (ballX > ballMaxX) { + if (PaddleHit(1)) { + SetAngle(1); + } + else { + lastWinner = 0; + playing = false; + } + } + + RedrawBall(video); + } + + private static int GetPaddleState(int paddle) + { + if (inputUp[paddle]) { + return -1; + } + else if (inputDown[paddle]) { + return 1; + } + else { + return 0; + } + } + + private static void SetStateFromChar(char c, bool @state) + { + switch (c) { + case (char)Keyboard.Keys.UP_ARROW: + inputUp[1] = @state; + break; + case (char)Keyboard.Keys.DOWN_ARROW: + inputDown[1] = @state; + break; + case 'a': + inputUp[0] = @state; + break; + case 'z': + inputDown[0] = @state; + break; + } + } + + private static void FillScreen(VideoDeviceContract.Imp:Ready! video, uint color) + { + video.SendFill(screenMinX, screenMinY, screenMaxX, screenMaxY, color); + video.RecvAckFill(); + } + + private static void ClearScreen(VideoDeviceContract.Imp:Ready! video) + { + FillScreen(video, Black); + } + + private static void FlashScreen(VideoDeviceContract.Imp:Ready! video) + { + FillScreen(video, Red); + Sleep(1000); + FillScreen(video, Green); + Sleep(1000); + FillScreen(video, Blue); + Sleep(1000); + } + + private static void ShowMessage(VideoDeviceContract.Imp:Ready! video) + { + ClearScreen(video); + + for (int i = 0; i < 100; i++) { + Console.WriteLine(); + } + + Console.Write(" "); + Console.Write("Left: {0,-10}", scores[0]); + Console.Write(" "); + Console.Write("Right: {0,-10}", scores[1]); + Console.WriteLine(); + Console.WriteLine(); + Console.Write(" "); + Console.Write("Press space to begin or escape to quit..."); + Console.WriteLine(); + + DrawPaddle(video, 0, false); + DrawPaddle(video, 1, false); + DrawBall(video, false); + } + + private static void Sleep(int multiplier) + { + for (int j = 0; j < multiplier; j++) { + for (int i = 0; i < 10000; i++) { + // Do nothing. + } + } + } + + public static int Main(string[] args) + { + VideoDeviceContract.Imp video = OpenVideo("/dev/video"); + + Console.WriteLine("Singularity Pong (PID={0})", + ProcessService.GetCurrentProcessId()); + + if (video == null) { + Console.WriteLine("Can only play pong on a graphic display."); + return 1; + } + + KeyboardDeviceContract.Imp keyboard = OpenKeyboard("/dev/keyboard"); + if (keyboard == null) { + // TODO: show keyboardless slides with timer? + delete video; + return 1; + } + + ShowMessage(video); + + while (!done) { + uint key = 0; + keyboard.SendPollKey(); + switch receive + { + case keyboard.AckKey(ikey): + key = ikey; + break; + case keyboard.NakKey(): + key = 0; + break; + case keyboard.ChannelClosed(): + throw new Exception("Didn't get keyboard closed."); + } + + char c = (char) (key & (uint) Keyboard.Qualifiers.KEY_BASE_CODE); + + if ((key & (uint) Keyboard.Qualifiers.KEY_DOWN) != 0) { + switch (c) { + case (char) Keyboard.Keys.ESCAPE: + done = true; + break; + case ' ': + if (!playing) { + ResetBall(); + ClearScreen(video); + DrawPaddle(video, 0, false); + DrawPaddle(video, 1, false); + DrawBall(video, false); + playing = true; + } + break; + default: + SetStateFromChar(c, true); + break; + } + } + else if ((key & (uint) Keyboard.Qualifiers.KEY_UP) != 0) { + SetStateFromChar(c, false); + } + + if (playing) { + MovePaddle(video, 0); + MovePaddle(video, 1); + MoveBall(video); + + if (!playing) { + scores[lastWinner]++; + FlashScreen(video); + ShowMessage(video); + } + } + + Sleep(10); + } + + ClearScreen(video); + + delete keyboard; + delete video; + + return 0; + } + } +} diff --git a/base/Applications/Runtime/AppRuntime.proj b/base/Applications/Runtime/AppRuntime.proj new file mode 100644 index 0000000..9baac18 --- /dev/null +++ b/base/Applications/Runtime/AppRuntime.proj @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + diff --git a/base/Applications/Runtime/Corlib.Native.proj b/base/Applications/Runtime/Corlib.Native.proj new file mode 100644 index 0000000..adea05c --- /dev/null +++ b/base/Applications/Runtime/Corlib.Native.proj @@ -0,0 +1,337 @@ + + + + + + $(APPRUNTIMENATIVEDIR)\Corlib.obj + $(OBJROOT)\$(OBJRELRUNTIMEDIR) + $(CFLAGS) /Gr /I$(BINDIR) /I$(SINGULARITY_ROOT)\boot\include /DSINGULARITY_PROCESS=1 + $(AFLAGS) /DSINGULARITY_PROCESS + $(APPRUNTIMEDIR)\Corlib.dll + $(SINGULARITY_ROOT)\Kernel + $(APPRUNTIMENATIVEDIR)\native.lib + $(COLLECTOR_APP) + + + + + + + + + + + $(BARTOK_FLAGS) /Singularity + $(BARTOK_FLAGS) /UnnameTracedPtrs=true + $(BARTOK_FLAGS) /OmitFramePointer=false + $(BARTOK_FLAGS) /GCInlineAllocations=false + $(BARTOK_FLAGS) /GCInlineWriteBarrier=false + $(BARTOK_FLAGS) /GenCoffLineNumber=false + $(BARTOK_FLAGS) /WholeProgram=true + $(BARTOK_FLAGS) /Warnings=true + $(BARTOK_FLAGS) /DisablePInvoke=true + $(BARTOK_FLAGS) /BackEndComments=true + $(BARTOK_FLAGS) $(BARTOK_COLLECTOR) + + + $(CORLIB_BARTOK_FLAGS) + $(CORLIB_BARTOK_FLAGS) /CompileOnly=true + $(CORLIB_BARTOK_FLAGS) /Warnings=true + $(CORLIB_BARTOK_FLAGS) $(BARTOK_COLLECTOR) + $(CORLIB_BARTOK_FLAGS) /r:$(LIBSDIR)\Singularity.V1.dll + $(CORLIB_BARTOK_FLAGS) /r:$(ILLSDIR)\Console.ill + $(CORLIB_BARTOK_FLAGS) /r:$(APPRUNTIMEDIR)\ILHelpers.dll + $(CORLIB_BARTOK_FLAGS) /out: $(APPRUNTIMENATIVEDIR)\CorLib.obj + $(CORLIB_BARTOK_FLAGS) /outdir: $(APPRUNTIMENATIVEDIR) + $(CORLIB_BARTOK_FLAGS) $(APPRUNTIMEDIR)\Corlib.dll + + + /verbosity:silence + $(TESTAPP_BARTOK_FLAGS) /GenAsmHeader="$(APPRUNTIMENATIVEDIR)\halclass.inc" + $(TESTAPP_BARTOK_FLAGS) /GenCppHeader="$(APPRUNTIMENATIVEDIR)\halclass.h" + $(TESTAPP_BARTOK_FLAGS) /IrTreeShake=false + $(TESTAPP_BARTOK_FLAGS) /IrTreeShakeLate=false + $(TESTAPP_BARTOK_FLAGS) /out:$(APPRUNTIMENATIVEDIR)\testapp.obj + $(TESTAPP_BARTOK_FLAGS) /outdir:$(APPRUNTIMENATIVEDIR) + + + + + + + + + + + + + + + + $(BARTOK_FLAGS) /IrSimpleInliner=false + + + + + + + + + $(BARTOK_FLAGS) /LinkedStacks=true + $(BARTOK_FLAGS) /SymbolicDebug=true + $(MASTER)\Native + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/base/Applications/Runtime/Corlibsg.csproj b/base/Applications/Runtime/Corlibsg.csproj new file mode 100644 index 0000000..e8a90b5 --- /dev/null +++ b/base/Applications/Runtime/Corlibsg.csproj @@ -0,0 +1,41 @@ + + + + + + + Corlibsg + Library + true + true + + + + + + + + + + + + + + + + + true + + + + + + diff --git a/base/Applications/Runtime/ILHelpers.csproj b/base/Applications/Runtime/ILHelpers.csproj new file mode 100644 index 0000000..3ee4ef6 --- /dev/null +++ b/base/Applications/Runtime/ILHelpers.csproj @@ -0,0 +1,55 @@ + + + + + + + + + $(APPRUNTIMEDIR) + $(SINGULARITY_ROOT)\Kernel + $(OutputPath)\ILHelpers.dll + + + + + + + + + + false + + + + + + + + + + + + + + + + + + + + + + diff --git a/base/Applications/Runtime/Singularity/AppRuntime.cs b/base/Applications/Runtime/Singularity/AppRuntime.cs new file mode 100644 index 0000000..1cee5b6 --- /dev/null +++ b/base/Applications/Runtime/Singularity/AppRuntime.cs @@ -0,0 +1,224 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Runtime.cs +// +// Note: +// + +using System; +using System.Collections; +using System.Reflection; +using System.Threading; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using Microsoft.Bartok.Runtime; + +#if !MINRUNTIME + using Microsoft.Singularity.Io; +#endif + using Microsoft.Singularity.V1.Services; + +[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)] + 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; + + 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(); + +#if !MINRUNTIME + ConsoleOutput.Initialize(); + ConsoleInput.Initialize(); +#endif + + 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 (userClass != null) { + VTable.initType((RuntimeType)userClass); + } + + result = CallMain(args); + if (!MainReturnsInt()) result = 0; + Thread.RemoveThread(Thread.CurrentThread.threadIndex); + + Thread.JoinAll(); + +#if !MINRUNTIME + ConsoleOutput.Finalize(); + ConsoleInput.Finalize(); +#endif + 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()); + DebugStub.WriteLine("Caught {0}", __arglist(e.Message)); + result = -1; + } + + Tracing.Log(Tracing.Audit, "Runtime shutdown started."); + VTable.Shutdown(result); + Tracing.Log(Tracing.Audit, "Runtime exiting [{0}]", + (UIntPtr)unchecked((uint)result)); + return result; + } + + [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; + } + } + } +} diff --git a/base/Applications/Runtime/Singularity/DebugStub.cs b/base/Applications/Runtime/Singularity/DebugStub.cs new file mode 100644 index 0000000..af809b2 --- /dev/null +++ b/base/Applications/Runtime/Singularity/DebugStub.cs @@ -0,0 +1,337 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Debug.cs +// +// Note: +// + +using System; +using System.Collections; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Threading; + +using Microsoft.Singularity.V1.Services; + +namespace Microsoft.Singularity +{ + [NoCCtor] + [CLSCompliant(false)] + public class DebugStub + { + /////////////////////////////////////////////////////// Print Methods. + // + [NoHeapAllocation] + public static void Print(byte value) + { + Print("{0:x2}", __arglist(value)); + } + + [NoHeapAllocation] + public static void Print(ushort value) + { + Print("{0:x4}", __arglist(value)); + } + + [NoHeapAllocation] + public static void Print(uint value) + { + Print("{0:x8}", __arglist(value)); + } + + [NoHeapAllocation] + public static void Print(ulong value) + { + Print("{0:x}", __arglist(value)); + } + + [NoHeapAllocation] + public static void Print(UIntPtr value) + { + Print("{0:x8}", __arglist(value)); + } + + [NoHeapAllocation] + public static void Print(sbyte value) + { + Print("{0}", __arglist(value)); + } + + [NoHeapAllocation] + public static void Print(short value) + { + Print("{0}", __arglist(value)); + } + + [NoHeapAllocation] + public static void Print(int value) + { + Print("{0}", __arglist(value)); + } + + [NoHeapAllocation] + public static void Print(long value) + { + Print("{0}", __arglist(value)); + } + + ////////////////////////////////////////////////////////////////////// + // + + [NoHeapAllocation] + public static void Print(String value) + { + if (value != null) { + Print(value, new ArgIterator()); + } + } + + [NoHeapAllocation] + public static void Print(String format, __arglist) + { + Print(format, new ArgIterator(__arglist)); + } + +#if PAGING +[AccessedByRuntime("output to header : defined in debugstub.cpp")] +[MethodImpl(MethodImplOptions.InternalCall)] +[StackBound(64)] +[NoHeapAllocation] +public static extern void Foo(); +//static int ccc = 0; +#endif + [NoHeapAllocation] + public static unsafe void Print(String format, ArgIterator args) + { +#if PAGING +Foo(); +/* +if (ccc == 0) { + DebugStub.Break(); + ccc = 1; +} +*/ +#endif + char *buffer; + int length; + int used = 0; + + DebugService.PrintBegin(out buffer, out length); + try { + if (buffer != null) { + used = String.LimitedFormatTo(format, args, buffer, length); + } + } + finally { + DebugService.PrintComplete(buffer, used); + } + } + + ////////////////////////////////////////////////////////////////////// + // + + [NoHeapAllocation] + public static void Write(String value) + { + if (value != null) { + Write(value, new ArgIterator()); + } + } + + [NoHeapAllocation] + public static void Write(String format, __arglist) + { + Write(format, new ArgIterator(__arglist)); + } + + [NoHeapAllocation] + public static unsafe void Write(String format, ArgIterator args) + { + char *buffer; + int length; + int used = 0; + + DebugService.PrintBegin(out buffer, out length); + try { + if (buffer != null) { + used = String.LimitedFormatTo(format, args, buffer, length); + } + } + finally { + DebugService.PrintComplete(buffer, used); + } + } + + ////////////////////////////////////////////////////////////////////// + // + [NoHeapAllocation] + public static void WriteLine() + { + WriteLine("", new ArgIterator()); + } + + [NoHeapAllocation] + public static void WriteLine(String value) + { + if (value != null) { + WriteLine(value, new ArgIterator()); + } + } + + [NoHeapAllocation] + public static void WriteLine(String format, __arglist) + { + WriteLine(format, new ArgIterator(__arglist)); + } + + [NoHeapAllocation] + public static unsafe void WriteLine(String format, ArgIterator args) + { + char *buffer; + int length; + int used = 0; + + DebugService.PrintBegin(out buffer, out length); + try { + if (buffer != null) { + used = String.LimitedFormatTo(format, args, buffer, length); + if (used < length) { + buffer[used++] = '\n'; + } + } + } + finally { + DebugService.PrintComplete(buffer, used); + } + } + + ////////////////////////////////////////////////////// Assert Methods. + // + [NoHeapAllocation] + public static void NotImplemented() + { + failAssert("Not implemented."); + } + + [NoHeapAllocation] + public static void NotImplemented(String msg) + { + failAssert(/*"Not implemented: "+*/msg); + } + + [Conditional("DEBUG")] + [NoInline] + [NoHeapAllocation] + public static void NotReached() + { + failAssert("Unreachable code reached."); + } + + [Conditional("DEBUG")] + [NoInline] + [NoHeapAllocation] + public static void NotReached(String msg) + { + failAssert(/*"Unreachable code reached: "+*/msg); + } + + [Conditional("DEBUG")] + [NoInline] + [ManualRefCounts] + [NoHeapAllocation] + public static void Assert(bool expr) + { + if (!expr) { + failAssert(null); + } + } + + [Conditional("DEBUG")] + [NoInline] + [ManualRefCounts] + [NoHeapAllocation] + public static void Deny(bool expr) + { + if (expr) { + failAssert(null); + } + } + + [Conditional("DEBUG")] + [NoInline] + [ManualRefCounts] + [NoHeapAllocation] + public static void Assert(bool expr, String s) + { + if (!expr) { + failAssert(s); + } + } + + [Conditional("DEBUG")] + [NoInline] + [NoHeapAllocation] + public static void Deny(bool expr, String s) + { + if (expr) { + failAssert(s); + } + } + + [ManualRefCounts] + [NoHeapAllocation] + private static void failAssert(String s) + { + if (s != null) { + Print("Assertion failed: {0}", __arglist(s)); + } + else { + Print("Assertion failed."); + } + Break(); + } + + ////////////////////////////////////////////////////////////////////// + // + [NoHeapAllocation] + public static ulong ReadPerfCounter(uint which) + { + return DebugService.ReadPerfCounter(which); + } + + + [NoHeapAllocation] + public static bool WritePerfCounter(uint which, ulong value) + { + return DebugService.WritePerfCounter(which, value); + } + + [NoHeapAllocation] + public static bool AddToPerfCounter(uint which, ulong value) + { + return DebugService.AddToPerfCounter(which, value); + } + + /////////////////////////////////////////////////////// State Methods. + // +#if true + [AccessedByRuntime("output to header : defined in halkd.cpp")] + [MethodImpl(MethodImplOptions.InternalCall)] + [StackBound(638)] + [NoHeapAllocation] + public static extern void Break(); +#else + [NoHeapAllocation] + public static void Break() + { + DebugService.Break(); + } +#endif + } +} diff --git a/base/Applications/Runtime/Singularity/Directory/NameService.sg b/base/Applications/Runtime/Singularity/Directory/NameService.sg new file mode 100644 index 0000000..1118e59 --- /dev/null +++ b/base/Applications/Runtime/Singularity/Directory/NameService.sg @@ -0,0 +1,30 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: DirectoryService.sg +// +// Note: +// +// This file provides an implementation of Naming.DirectoryService.NewClientEndpoint +// that calls through the ABI to retrieve the name-service channel endpoint. +// This is for use by applications; kernel components can call the "real" +// DirectoryService class directly. +// + +using Microsoft.Singularity; +using Microsoft.Singularity.Naming; +using Microsoft.Singularity.V1.Services; + +namespace Microsoft.Singularity.Directory +{ + public class DirectoryService + { + public static unsafe DirectoryServiceContract.Imp!:Ready NewClientEndpoint() + { + return (DirectoryServiceContract.Imp!)ProcessService.GetNamespaceEndpoint(); + } + } +} diff --git a/base/Applications/Runtime/Singularity/Io/ConsoleInput.sg b/base/Applications/Runtime/Singularity/Io/ConsoleInput.sg new file mode 100644 index 0000000..20d6e19 --- /dev/null +++ b/base/Applications/Runtime/Singularity/Io/ConsoleInput.sg @@ -0,0 +1,318 @@ +////////////////////////////////////////////////////////////////////////////////// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: ConsoleInput.sg +// +// Note: Read a line or a char of the Console +// + +using DirectoryService.Utils; +using System.GC; +using System.Runtime.Remoting; +using System.Threading; +using System.Collections; +using System.Diagnostics; +using Microsoft.Singularity.V1.Services; + + +namespace Microsoft.Singularity.Io { + using Microsoft.SingSharp; + using Microsoft.Singularity; + using Microsoft.Singularity.V1.Services; + using Microsoft.Singularity.V1.Threads; + using Microsoft.Singularity.Channels; + using Microsoft.Singularity.Directory; + + using System; + using System.Text; + using System.Globalization; + using System.Runtime.CompilerServices; + + using Microsoft.Singularity.Extending; + using Microsoft.Singularity.Runtime; + using Microsoft.Singularity.Io; + using System.Runtime.InteropServices; + + + + public sealed class ConsoleInput /* : ITracked, ISelectable */ + { + private static TContainer consoleContainer; + // protected by TContainer lock. + private static char[]! readLineBuffer = new char[16]; + + /* + + private char[]! in ExHeap side; + private UnicodePipeContract.Exp conn; + private int charCount; + private int charPos; + + private ConsoleInput([Claims] UnicodePipeContract.Exp? pipe) + { + this.side = new[ExHeap] char [280]; + this.charCount = 0; + this.charPos = 0; + this.conn = pipe; + + base(); + } + */ + + private ConsoleInput() {} + + private static UnicodePipeContract.Exp? GetPipe() + { + UnicodePipeContract.Exp con = null; + + Endpoint * in ExHeap pipeep = Process.GetStartupEndpoint(0); + if (pipeep != null) { + con = pipeep as UnicodePipeContract.Exp; + if (con == null) { + // this cannot possibly work! the process is already started +#if DEBUG + DebugStub.WriteLine("ConsoleInput: slot 0 is not a pipe."); +#endif + Process.RetStartupEndpoint(0,pipeep); + return null; + } + else { + //DebugStub.WriteLine("ConsoleInput: connected to pipe."); + return con; + } + } + return null; + } + + + public static void Initialize() + { + UnicodePipeContract.Exp pipe = GetPipe(); + PipeLookAhead bufferedPipe = new PipeLookAhead(pipe, 100); + ConsoleInput.consoleContainer = new TContainer(bufferedPipe); + } + + /* + public void Dispose() + { + delete this.side; + delete this.conn; + } + + void ITracked.Acquire() { + Tracing.Log(Tracing.Debug,"ConsoleInput.Acquire"); + } + void ITracked.Release() { + Tracing.Log(Tracing.Debug,"ConsoleInput.Release"); + } + void ITracked.Expose() { + Tracing.Log(Tracing.Debug,"ConsoleInput.Expose"); + } + void ITracked.UnExpose() { + Tracing.Log(Tracing.Debug,"ConsoleInput.UnExpose"); + } + */ + + public static void Finalize() + { +#if DEBUG + DebugStub.WriteLine("consoleInput: finalizer called"); +#endif + // TContainer chandle = consoleContainer; + TContainer chandle = consoleContainer; + consoleContainer = null; + + if (chandle == null) return; + + PipeLookAhead co = chandle.Acquire(); + co.Dispose(); + } + + /* + private int InternalReadChar() + { + expose (this) { + if (this.conn != null) { + if (this.charCount == 0) { + UnicodePipeContract.Exp pipe = this.conn; + + tryAgain: + switch receive { + case pipe.Write(buffer,a,b): + if (b == 0) { + pipe.SendAckWrite(buffer); + goto tryAgain; + } + if (b == 1) { + int theChar = (int) buffer[a]; + pipe.SendAckWrite(buffer); + return theChar; + } + else { + // switch our buffer with theirs + pipe.SendAckWrite(this.side); + this.side = buffer; + this.charPos = a+1; + this.charCount = b-1; + return (int)buffer[a]; + } + + case pipe.ChannelClosed(): + return -1; + } + } + else { + // there are more chars in the buffer + int theChar = this.side[this.charPos++]; + this.charCount--; + return theChar; + } + } + } //expose + return -1; + } + */ + + public static void Close() + { + } + + public static int ReadChar() + { + if (consoleContainer == null) return -1; + PipeLookAhead co = consoleContainer.Acquire(); + int key = co.ReadChar(); + if (key == -1) { + co.Dispose(); + consoleContainer = null; + return key; + } + consoleContainer.Release(co); + return key; + } //ReadChar + + //////////////////////////////////////////////////////// + // + public static string ReadLine() + { + if (consoleContainer == null) return null; + PipeLookAhead bufferedPipe = consoleContainer.Acquire(); + + int pos = 0; + int key; + + do { + key = bufferedPipe.ReadChar(); + if (key == -1) { + bufferedPipe.Dispose(); + consoleContainer = null; + return null; + } + if (key == '\r') { + // DebugStub.WriteLine("key {0}", key); + continue; + } + if (key == '\n') { + // DebugStub.WriteLine("key {0}", key); + break; + } + if (pos+1 >= readLineBuffer.Length){ + char[] temp = new char[readLineBuffer.Length *2]; + Array.Copy(readLineBuffer,temp,readLineBuffer.Length); + readLineBuffer = temp; + } + readLineBuffer[pos++] = (char) key; + if (key > 31 && key < 126) { + // DebugStub.WriteLine("key {0}", key); + } + } while (key != -1 ); + + string s = new string(readLineBuffer,0,pos); + //DebugStub.WriteLine("in: count={0}, s=({1})",__arglist(pos, s)); + + consoleContainer.Release(bufferedPipe); + return s; + } //ReadLine + + /* + internal enum ReceiveTag { + Any = 1, + GetChar = 2, + } + + [Selectable((int)ReceiveTag.GetChar)] + public void RecvGetChar(out int key) { + key = this.InternalReadChar(); + } + + /// + /// Tests if the message at the head of the queue matches the given tag. If so, + /// returns true. + /// + /// If no match is possible in the future given the current message, possible must + /// be set to false. + /// Implementations are disallowed from setting possible to true + /// so that the context can chain them. + /// + /// If the underlying object is an endpoint set, it also returns an object that + /// serves to extract the endpoint having the match from the set later. + /// + /// Again, implementations are disallowed from setting match setMatch to null + /// so that the context can chain the calls. + /// + /// + bool ISelectable.HeadMatches(int tag, ref bool possible, ref object setMatch) { + // Only handle pipe case + expose (this) { + if (this.conn != null) { + if (this.charCount == 0) { + UnicodePipeContract.Exp pipe = this.conn; + + // negative tag is channel closed + int pipeTag = (tag < 0)?tag : UnicodePipeContract.Tags.Write; + + return pipe.HeadMatches(pipeTag, ref possible, ref setMatch); + } + else { + // there are more chars in the buffer + if (tag < 0) { + // not closed + possible = false; + return false; + } + return true; + } + } + else { + // no pipe + possible = false; + return false; + } + } //expose + } + + SyncHandle ISelectable.GetWaitHandle() { + expose (this) { + assert(this.conn != null); + return this.conn.GetWaitHandle(); + } + } + + */ + public static PipeLookAhead! AcquireInput() { + assert consoleContainer != null; + + PipeLookAhead bufferedPipe = consoleContainer.Acquire(); + return bufferedPipe; + } + + public static void ReleaseInput([Claims] PipeLookAhead! bufferedPipe) { + assert consoleContainer != null; + + consoleContainer.Release(bufferedPipe); + } + + } //ConsoleInput +}//namespace diff --git a/base/Applications/Runtime/Singularity/Io/ConsoleOutput.sg b/base/Applications/Runtime/Singularity/Io/ConsoleOutput.sg new file mode 100644 index 0000000..9fbdeb9 --- /dev/null +++ b/base/Applications/Runtime/Singularity/Io/ConsoleOutput.sg @@ -0,0 +1,461 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: ConsoleOutput.sg +// +// Note: Uses /dev/conout to display console output. +// + +namespace Microsoft.Singularity.Io { + using Microsoft.SingSharp; + using Microsoft.Singularity; + using Microsoft.Singularity.V1.Services; + using Microsoft.Singularity.Channels; + using Microsoft.Singularity.Directory; + + using System; + using System.Text; + using System.Globalization; + using System.Runtime.CompilerServices; + + using System.Runtime.InteropServices; + + public sealed class ConsoleOutput : ITracked + { + private static TContainer consoleContainer; + + private struct PipeData : ITracked { + public UnicodePipeContract.Imp channel; + public void Dispose() + { + delete channel; + } + void ITracked.Acquire() {} + void ITracked.Release() {} + public void Expose() {} + public void UnExpose() {} + + public UnicodePipeContract.Imp:READY Swap([Claims] UnicodePipeContract.Imp:READY newPipe) { + expose (this) { + UnicodePipeContract.Imp result = this.channel; + this.channel = newPipe; + return result; + } + } + } + + /* + private struct DeviceData : ITracked { + public ConsoleDeviceContract.Imp:Ready channel; + public void Dispose() + { + delete channel; + } + void ITracked.Acquire() {} + void ITracked.Release() {} + public void Expose() {} + public void UnExpose() {} + } + */ + + private char[]! in ExHeap side; + private PipeData pipe; + /* + private DeviceData device; + */ + private ConsoleOutput([Claims] UnicodePipeContract.Imp? pipe) + { + this.side = new[ExHeap] char [280]; + this.pipe.channel = pipe; + } + + private static UnicodePipeContract.Imp GetPipe() + { + UnicodePipeContract.Imp con = null; + + Endpoint* in ExHeap pipeep = Process.GetStartupEndpoint(1); + if (pipeep != null) { + con = pipeep as UnicodePipeContract.Imp; + if (con == null) { + Process.RetStartupEndpoint(1,pipeep); + return null; + } + return con; + } + return null; + } + + public static void Initialize() + { + /* + ConsoleDeviceContract.Imp imp = null; + + imp = OpenConsole("/dev/video-text"); + if (imp == null) { + imp = OpenConsole("/dev/conout"); + if (imp == null) { + DebugStub.Print("Couldn't open console.\n"); + return; + } + } + */ + UnicodePipeContract.Imp pipe = GetPipe(); + ConsoleOutput co = new ConsoleOutput(pipe); + consoleContainer = new TContainer(co); + } + + public void Dispose() + { + this.pipe.Dispose(); + // this.device.Dispose(); + delete this.side; + } + + void ITracked.Acquire() { + //Tracing.Log(Tracing.Debug,"ConsoleOutput.Acquire"); + } + void ITracked.Release() { + //Tracing.Log(Tracing.Debug,"ConsoleOutput.Release"); + } + void ITracked.Expose() { + //Tracing.Log(Tracing.Debug,"ConsoleOutput.Expose"); + } + void ITracked.UnExpose() { + //Tracing.Log(Tracing.Debug,"ConsoleOutput.UnExpose"); + } + + public static void Finalize() + { + TContainer chandle = consoleContainer; + consoleContainer = null; + + if (chandle == null) return; + + ConsoleOutput co = chandle.Acquire(); + if (co != null) co.Dispose(); + } + + /* + private static ConsoleDeviceContract.Imp + OpenConsoleInternal(DirectoryServiceContract.Imp! nsImp, + [Claims] char[]! in ExHeap deviceName) + { + ConsoleDeviceContract.Exp! exp; + ConsoleDeviceContract.Imp! imp; + ConsoleDeviceContract.NewChannel(out imp, out exp); + + nsImp.SendBind(deviceName, exp); + switch receive + { + case nsImp.AckBind(): + return imp; + break; + case nsImp.NakBind(rejectImp, error): + delete rejectImp; + delete imp; + break; + case nsImp.ChannelClosed(): + throw new Exception("Channel closed during Console bind."); + delete imp; + break; + case nsImp.NakBindReparse(path, rest, linked, backExp): + assert linked == true; + assert rest == null; + delete backExp; + delete imp; + + return OpenConsoleInternal(nsImp, path); + break; + } + return null; + } + + private static ConsoleDeviceContract.Imp OpenConsole(string! devName) + { + DirectoryServiceContract.Imp ns = DirectoryService.NewClientEndpoint(); + ConsoleDeviceContract.Imp imp = + OpenConsoleInternal(ns, Bitter.FromString2(devName)); + delete ns; + + if (imp != null) { + switch receive + { + case imp.Success(): + break; + case imp.ContractNotSupported(): + throw new Exception("ConsoleOutput: ContractNotSupported"); + break; + case imp.ChannelClosed(): + throw new Exception("ConsoleOutput: ChannelClosed"); + break; + } + } + return imp; + } + + public static void Clear() + { + if (consoleContainer == null) return; + + ConsoleOutput co = consoleContainer.Acquire(); + + expose (co) { + ConsoleDeviceContract.Imp ep = co.device.channel; + if (ep != null) + { + ep.SendClear(); + switch receive + { + case ep.AckClear(): + break; + case ep.NakClear(): + break; + case ep.ChannelClosed(): + delete ep; + co.device.channel = null; + break; + } + } + } + consoleContainer.Release(co); + } + + public static void CursorFlash() + { + if (consoleContainer == null) return; + + ConsoleOutput co = consoleContainer.Acquire(); + + expose (co) { + ConsoleDeviceContract.Imp ep = co.device.channel; + if (ep != null) + { + ep.SendCursorFlash(); + switch receive + { + case ep.AckCursorFlash(): + break; + case ep.NakCursorFlash(): + break; + case ep.ChannelClosed(): + delete ep; + co.device.channel = null; + break; + } + } + } + consoleContainer.Release(co); + } + + public static void CursorHide() + { + if (consoleContainer == null) return; + + ConsoleOutput co = consoleContainer.Acquire(); + + expose (co) { + ConsoleDeviceContract.Imp ep = co.device.channel; + if (ep != null) { + ep.SendCursorHide(); + switch receive { + case ep.AckCursorHide(): + break; + case ep.NakCursorHide(): + break; + case ep.ChannelClosed(): + delete ep; + co.device.channel = null; + break; + } + } + } + consoleContainer.Release(co); + } + + public static void CursorShow() + { + if (consoleContainer == null) return; + + ConsoleOutput co = consoleContainer.Acquire(); + + expose (co) { + ConsoleDeviceContract.Imp ep = co.device.channel; + if (ep != null) { + ep.SendCursorShow(); + switch receive { + case ep.AckCursorShow(): + break; + case ep.NakCursorShow(): + break; + case ep.ChannelClosed(): + delete ep; + co.device.channel = null; + break; + } + } + } + consoleContainer.Release(co); + } + */ + + public static char[]! in ExHeap Write([Claims] char[]! in ExHeap buffer, + int index, int count) + { + if (consoleContainer == null) return buffer; + ConsoleOutput co = consoleContainer.Acquire(); + try { + expose (co) { + if (co.pipe.channel != null) { + return Write(buffer, index, count, ref co.pipe); + } + else { + return buffer; + } + } + } + finally { + consoleContainer.Release(co); + } + } + + /* + private static char[]! in ExHeap Write([Claims] char[]! in ExHeap buffer, + int index, int count, + ref DeviceData device) + { + expose (device) { + ConsoleDeviceContract.Imp channel = device.channel; + if (channel != null) + { + channel.SendWrite(buffer, index, count); + switch receive { + case channel.AckWrite(localside): + return localside; + + case channel.NakWrite(localside): + return localside; + + case channel.ChannelClosed(): + delete channel; + device.channel = null; + return new[ExHeap] char[0]; + } + } + else { + return buffer; + } + } + } + */ + + private static char[]! in ExHeap Write([Claims] char[]! in ExHeap buffer, + int index, int count, + ref PipeData pipe) + { + expose (pipe) { + UnicodePipeContract.Imp channel = pipe.channel; + if (channel != null) { + // char[]! in ExHeap buffer=Bitter.FromString2(value); + channel.SendWrite(buffer, index, count); + switch receive { + case channel.AckWrite(i_buffer): + return i_buffer; + + case channel.ChannelClosed(): + delete channel; + pipe.channel = null; + return new[ExHeap] char[0]; + + case unsatisfiable: + DebugStub.Break(); + throw new Exception("Pipe unsatisfiable "); + } + } + else { + return buffer; + } + } + } + + public static void Write(char[]! buffer, int index, int count) + { + if (consoleContainer == null) return; + + ConsoleOutput co = consoleContainer.Acquire(); + + expose (co) { + char[] in ExHeap side = co.side; + + if (side.Length < count) { + delete side; + co.side = side = new[ExHeap] char [count]; + } + + for (int i = 0; i < count; i++) { + side[i] = buffer[index + i]; + } + + if (co.pipe.channel != null) { + co.side = Write(side, index, count, ref co.pipe); + } + /* + else { + co.side = Write(side, index, count, ref co.device); + } + */ + } + consoleContainer.Release(co); + } + + public static void Write(String! value) + { + if (consoleContainer == null) return; + + ConsoleOutput co = consoleContainer.Acquire(); + + expose (co) { + + char[] in ExHeap side = co.side; + if (side.Length < value.Length) { + delete side; + co.side = side = new[ExHeap] char [value.Length]; + } + + for (int i = 0; i < value.Length; i++) { + side[i] = value[i]; + } + + if (co.pipe.channel != null) { + co.side = Write(side, 0, value.Length, ref co.pipe); + } + /* + else { + co.side = Write(side, 0, value.Length, ref co.device); + } + */ + } + consoleContainer.Release(co); + return; + } + + public static UnicodePipeContract.Imp:READY Swap([Claims] UnicodePipeContract.Imp:READY newOutput) { + if (consoleContainer == null) { + delete newOutput; + return null; + } + + ConsoleOutput co = consoleContainer.Acquire(); + + UnicodePipeContract.Imp result; + expose(co) { + result = co.pipe.Swap(newOutput); + } + consoleContainer.Release(co); + return result; + } + + } +} diff --git a/base/Applications/Runtime/Singularity/Io/IoIrq.cs b/base/Applications/Runtime/Singularity/Io/IoIrq.cs new file mode 100644 index 0000000..326c90e --- /dev/null +++ b/base/Applications/Runtime/Singularity/Io/IoIrq.cs @@ -0,0 +1,87 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: IoIrq.cs - Process Code +// + +using System; +using System.Threading; + +using Microsoft.Singularity.V1.Threads; + +namespace Microsoft.Singularity.Io +{ + [CLSCompliant(false)] + public sealed class IoIrq : IoRange + { + private readonly byte irq; + private InterruptHandle handle; + + internal IoIrq(byte irq) + { + this.irq = irq; + } + + ~IoIrq() + { + if (handle.id != UIntPtr.Zero) + { + ReleaseInterrupt(); + } + } + + public byte Irq + { + get { return irq; } + } + + public bool RegisterInterrupt() + { + InterruptHandle handleOnStack; + bool success = InterruptHandle.Create(irq, out handleOnStack); + handle = handleOnStack; + return success; + } + + public bool ReleaseInterrupt() + { + bool ret = InterruptHandle.Dispose(handle); + handle = new InterruptHandle(); + return ret; + } + + public bool WaitForInterrupt() + { + if (handle.id != UIntPtr.Zero) + { + return InterruptHandle.Wait(handle); + } + return false; + } + + public void Pulse() + { + if (handle.id != UIntPtr.Zero) + { + InterruptHandle.Pulse(handle); + } + } + + public bool AckInterrupt() + { + if (handle.id != UIntPtr.Zero) + { + return InterruptHandle.Ack(handle); + } + return false; + } + + public override string ToString() + { + return String.Format("IRQ:{0,2:x2}", irq); + } + } +} diff --git a/base/Applications/Runtime/Singularity/Io/PipeLookAhead.sg b/base/Applications/Runtime/Singularity/Io/PipeLookAhead.sg new file mode 100644 index 0000000..e73c2da --- /dev/null +++ b/base/Applications/Runtime/Singularity/Io/PipeLookAhead.sg @@ -0,0 +1,402 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: PipeLookAhead.sg +// +// Note: Implements a selectable abstraction that looks ahead on a pipe channels +// for control-C and exports separate logical receivable messages for +// non-control-C characters and control-C, effectively allowing one to +// consume Ctrl-C's out of order. +// +using System; +using Microsoft.SingSharp; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.V1.Threads; +using Tty = Microsoft.Singularity.Io.Tty2006; + +namespace Microsoft.Singularity.Io { + + public sealed class PipeLookAhead : ITracked, ISelectable { + + private struct CircularBuffer : ITracked { + + private char[]! in ExHeap buffer; // circular buffer + private int nextReadIndex; + private int nextWriteIndex; + private int controlC_Count; // ctrl-c's in buffer + private int controlC_Consumed; // ctrl-c's consumed in buffer + private int controlZ_Count; // ctrl-z's in buffer + private int controlZ_Consumed; // ctrl-z's consumed in buffer + + public bool HasControlC { + get { return controlC_Count > 0; } + } + + public bool HasControlZ { + get { return controlZ_Count > 0; } + } + + private int CharsInBuffer { + get { + if (nextWriteIndex >= nextReadIndex) { + return nextWriteIndex - nextReadIndex; + } + else { + expose (this) { + return buffer.Length - nextReadIndex + nextWriteIndex; + } + } + } + } + + public int CharsAvailable { + get { + int available = CharsInBuffer - controlC_Consumed - controlZ_Consumed; + return available; + } + } + + + public CircularBuffer(int lookAhead) { + this.buffer = new[ExHeap] char[lookAhead+256]; + this.nextReadIndex = 0; + this.nextWriteIndex = 0; + this.controlC_Count = 0; + this.controlC_Consumed = 0; + this.controlZ_Count = 0; + this.controlZ_Consumed = 0; + } + + private int FreeSpace { + get { + // Careful, circular buffer can't be filled completely. + // Need 1 extra space to distinguish full from empty buffer. + expose (this) { + return this.buffer.Length - this.CharsInBuffer - 1; + } + } + } + public void Add(char[]! in ExHeap buffer, int index, int count) { + EnsureCapacity(count); + for (int i=0; i= this.nextReadIndex) { + // copy area between indices + Bitter.Copy(newBuffer, 0, charsBuffered, + oldBuffer, this.nextReadIndex); + } + else { + // copy areas from read to end and from start to write. + int suffix = this.buffer.Length - this.nextReadIndex; + Bitter.Copy(newBuffer, 0, suffix, + oldBuffer, this.nextReadIndex); + Bitter.Copy(newBuffer, suffix, this.nextWriteIndex, + oldBuffer, 0); + } + delete this.buffer; + this.buffer = newBuffer; + this.nextReadIndex = 0; + this.nextWriteIndex = charsBuffered; + } + } + } + + public void Dispose() + { + delete this.buffer; + } + + void ITracked.Acquire() {} + void ITracked.Release() {} + void ITracked.Expose() {} + void ITracked.UnExpose() {} + + public void GetChar(out char ch) { + expose (this) { + tryAgain: + assert CharsAvailable > 0; + ch = this.buffer[this.nextReadIndex++]; + if (this.nextReadIndex == this.buffer.Length) { + this.nextReadIndex = 0; // wrap around + } + if (ch == (int)Tty.ControlCodes.CTRL_C) { + if (this.controlC_Consumed > 0) { + // filter. already consumed via Ctrl_C + this.controlC_Consumed--; + goto tryAgain; + } + else { + this.controlC_Count--; + } + } + if (ch == (int)Tty.ControlCodes.CTRL_Z) { + if (this.controlZ_Consumed > 0) { + // filter. already consumed via Ctrl_Z + this.controlZ_Consumed--; + goto tryAgain; + } + else { + this.controlZ_Count--; + } + } + /* + char c = ch; + DebugStub.WriteLine("GetChar {0} writeIndex={1} readIndex={2} CtrlC={3} CtrlZ={4} C-Used={5} Z-Used={6}", + __arglist(c, this.nextWriteIndex, + this.nextReadIndex, + this.controlC_Count, + this.controlZ_Count, + this.controlC_Consumed, + this.controlZ_Consumed + )); + */ + + } + } + + public void ConsumeControlC() { + assert this.controlC_Count > 0; + this.controlC_Count--; + this.controlC_Consumed++; + } + + public void ConsumeControlZ() { + assert this.controlZ_Count > 0; + this.controlZ_Count--; + this.controlZ_Consumed++; + } + } + + private UnicodePipeContract.Exp pipe; // null when pipe is closed + + private int lookAhead; + private CircularBuffer buffer; + + public PipeLookAhead([Claims] UnicodePipeContract.Exp pipe, int lookAhead) + { + this.pipe = pipe; + this.lookAhead = lookAhead; + this.buffer = new CircularBuffer(lookAhead); + } + + public void Dispose() + { + this.buffer.Dispose(); + delete this.pipe; + } + + void ITracked.Acquire() {} + void ITracked.Release() {} + void ITracked.Expose() {} + void ITracked.UnExpose() {} + + + SyncHandle ISelectable.GetWaitHandle() { + expose (this) { + // non-null checker was right in pointing out issue if pipe is null. + // Design problem: what handle do we return in this case? + if (this.pipe != null) { + return this.pipe.GetWaitHandle(); + } + else { + DebugStub.Break(); + return new SyncHandle(); // null handle. Could cause null-deref + // should we make kernel tolerate this? + } + } + } + + void ISelectable.ResetWaitSignal() { + // dummy + } + + private void FillToLookAheadWithoutBlock() + { + expose (this) { + UnicodePipeContract.Exp pipe = this.pipe; + if (pipe == null) return; + while (this.buffer.CharsAvailable < this.lookAhead) + { + switch receive { + case pipe.Write(buffer,index,count): + this.buffer.Add(buffer, index, count); + pipe.SendAckWrite(buffer); + break; + + case pipe.ChannelClosed(): + delete pipe; + this.pipe = null; + return; + + case timeout: + return; + } + } + } //expose + } + + private bool IsClosed { + get { + expose(this) { + return (this.pipe == null && this.buffer.CharsAvailable==0); + } + } + } + + private bool HasCharacter { + get { + expose(this) { + return this.buffer.CharsAvailable > 0; + } + } + } + + private int CharsAvailable { + get { + expose(this) { + return this.buffer.CharsAvailable; + } + } + } + + private bool HasControlC { + get { + expose(this) { + return this.buffer.HasControlC; + } + } + } + + private bool HasControlZ { + get { + expose(this) { + return this.buffer.HasControlZ; + } + } + } + + enum SelectTag { + ChannelClosed = -1, + Any = 1, + Char = 2, + ControlC = 3, + ControlZ = 4, + } + + /// + /// blocks until a character is available + /// + public int ReadChar() { + PipeLookAhead pipe = this; + switch receive { + case pipe.Char(ch): + return ch; + case pipe.ChannelClosed(): + return -1; + } + } + + public bool HeadMatches(int tag, ref bool possible, ref object setMatch) { + + this.FillToLookAheadWithoutBlock(); + + switch ((SelectTag)tag) { + case SelectTag.ChannelClosed: + if (this.IsClosed) { + return true; + } + if (this.HasCharacter) { + possible = false; + } + return false; + + case SelectTag.Char: + if (this.HasCharacter) { + return true; + } + if (this.IsClosed) { + possible = false; + } + return false; + + case SelectTag.ControlC: + if (this.HasControlC) { + return true; + } + if (this.IsClosed) { + possible = false; + } + return false; + + case SelectTag.ControlZ: + if (this.HasControlZ) { + return true; + } + if (this.IsClosed) { + possible = false; + } + return false; + + } + return false; + } + + [Selectable((int)SelectTag.Char)] + public void RecvChar(out char ch) { + expose(this) { + this.buffer.GetChar(out ch); + } + } + + [Selectable((int)SelectTag.ControlC)] + public void RecvControlC() { + expose(this) { + this.buffer.ConsumeControlC(); + } + } + + [Selectable((int)SelectTag.ControlZ)] + public void RecvControlZ() { + expose(this) { + this.buffer.ConsumeControlZ(); + } + } + + } +} diff --git a/base/Applications/Runtime/Singularity/Io/PipeMultiplexer.sg b/base/Applications/Runtime/Singularity/Io/PipeMultiplexer.sg new file mode 100644 index 0000000..c02ada4 --- /dev/null +++ b/base/Applications/Runtime/Singularity/Io/PipeMultiplexer.sg @@ -0,0 +1,214 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: PipeMultiplexer.sg +// +// Note: Multiplexes any number of input pipes to a single output pipe. +// Also features a channel to submit new input pipes. +// +using System; +using System.Threading; +using Microsoft.SingSharp; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Tty = Microsoft.Singularity.Io.Tty2006; + +namespace Microsoft.Singularity.Io { + + public contract PipeMultiplexControl { + in message NewInput(UnicodePipeContract.Exp:EXPMOVABLE! client); + out message Ack(); + + state START: NewInput? -> Ack! -> START; + } + + /// + /// Allows creating and managing a multiplexer that forwards data from several pipes + /// to a single output pipe. + /// + public sealed class PipeMultiplexer : ITracked { + + private class PipeThread { + TRef initialClientArgument; + TRef! threadStartupArgument1; + TRef! threadStartupArgument2; + + + public PipeThread([Claims] UnicodePipeContract.Imp:READY! output, + [Claims] PipeMultiplexControl.Exp:START! control, + [Claims] UnicodePipeContract.Exp:READY? initialClient) + { + this.threadStartupArgument1 = new TRef(output); + this.threadStartupArgument2 = new TRef(control); + if (initialClient != null) { + this.initialClientArgument = + new TRef(initialClient); + } + } + + + public void Start() { + UnicodePipeContract.Exp:READY? initialClient = null; + if (this.initialClientArgument != null) { + initialClient = this.initialClientArgument.Acquire(); + } + MessagePump(this.threadStartupArgument1.Acquire(), + this.threadStartupArgument2.Acquire(), + initialClient); + } + + + private static void MessagePump([Claims] UnicodePipeContract.Imp:READY! output, + [Claims] PipeMultiplexControl.Exp:START! control, + [Claims] UnicodePipeContract.Exp:READY? initialClient) + { + ESet waitingForOutputAck = + new ESet(); + + ESet clientWaitingForAck = + new ESet(); + + ESet outputReady = + new ESet(); + + ESet clients = + new ESet(); + + if (initialClient != null) { + clients.Add(initialClient); + } + outputReady.Add(output); + + bool done = false; + + try { + while (!done) { + switch receive { + + case control.NewInput(client): + //DebugStub.WriteLine("pipe multiplexer new client [{0}]", + // __arglist(clients.Count+1)); + client.SendMoved(); + clients.Add(client); + control.SendAck(); + break; + + case control.ChannelClosed(): + //DebugStub.WriteLine("pipe multiplexer control channel closed"); + done = true; + break; + + case client.Write(buffer, index, count) in clients && + outputReady.Head(outputEp): + // a client wants to write and the output is ready + //DebugStub.WriteLine("pipe multiplexer [{0}] client writes", + // __arglist(clients.Count+1)); + outputEp.SendWrite(buffer, index, count); + clientWaitingForAck.Add(client); + waitingForOutputAck.Add(outputEp); + continue; + + case outputEp.AckWrite(buffer) in waitingForOutputAck && + clientWaitingForAck.Head(client): + // a client is waiting for ack and output sent us ack + //DebugStub.WriteLine("pipe multiplexer: output Acks"); + client.SendAckWrite(buffer); + clients.Add(client); + outputReady.Add(outputEp); + continue; + + case client.ChannelClosed() in clients: + //DebugStub.WriteLine("pipe multiplexer: client departs"); + delete client; + continue; + + case outputEp.ChannelClosed() in waitingForOutputAck: + DebugStub.WriteLine("pipe multiplexer: output closes"); + delete outputEp; + done = true; + break; + } + } + } + finally { + waitingForOutputAck.Dispose(); + outputReady.Dispose(); + clientWaitingForAck.Dispose(); + clients.Dispose(); + delete control; + } + } + } + + /// Can be null when control channel closed + private PipeMultiplexControl.Imp:START controlChannel; + + private PipeMultiplexer([Claims] PipeMultiplexControl.Imp:START! control) { + this.controlChannel = control; + } + + public static PipeMultiplexer! + Start([Claims] UnicodePipeContract.Imp:READY! output, + [Claims] UnicodePipeContract.Exp:READY? initialClient) + { + PipeMultiplexControl.Imp! controlImp; + PipeMultiplexControl.Exp! controlExp; + PipeMultiplexControl.NewChannel(out controlImp, out controlExp); + + PipeThread pipeThread = new PipeThread(output, controlExp, initialClient); + + Thread t = new Thread(new ThreadStart(pipeThread.Start)); + t.Start(); + return new PipeMultiplexer(controlImp); + } + + /// + /// Adds a fresh input pipe to the multiplexer and returns the client end. + /// + public UnicodePipeContract.Imp:READY FreshClient() { + expose (this) { + PipeMultiplexControl.Imp control = this.controlChannel; + if (control == null) return null; // channel closed + + UnicodePipeContract.Imp! client; + UnicodePipeContract.Exp! exp; + UnicodePipeContract.NewChannel(out client, out exp, UnicodePipeContract.EXPMOVABLE.Value); + control.SendNewInput(exp); + switch receive { + case control.Ack(): + // put client into correct state: + + switch receive { + case client.Moved(): + return client; + + case client.ChannelClosed(): + delete client; + return null; + } + + case control.ChannelClosed(): + delete control; + delete client; + this.controlChannel = null; + return null; + } + } + + } + + public void Dispose() + { + delete this.controlChannel; + } + + void ITracked.Acquire() {} + void ITracked.Release() {} + void ITracked.Expose() {} + void ITracked.UnExpose() {} + + } +} diff --git a/base/Applications/Runtime/Singularity/Memory/Stacks.cs b/base/Applications/Runtime/Singularity/Memory/Stacks.cs new file mode 100644 index 0000000..5388274 --- /dev/null +++ b/base/Applications/Runtime/Singularity/Memory/Stacks.cs @@ -0,0 +1,161 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Stacks.cs - Primitive stack segment manager +// +// Note: +// + +namespace Microsoft.Singularity.Memory { + + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + using Microsoft.Singularity; + using Microsoft.Singularity.X86; + using Microsoft.Singularity.V1.Services; + + [NoCCtor] + [CLSCompliant(false)] + [RequiredByBartok] + internal class Stacks { + + internal static unsafe void Initialize() + { + DebugStub.Print("Stacks.Initialize() called\n"); + } + + internal static unsafe void Finalize() + { + DebugStub.Print("Stacks.Finalize() called\n"); + } + + [StackBound(64)] + [NoStackLinkCheck] + [NoStackOverflowCheck] + [MethodImpl(MethodImplOptions.InternalCall)] + [RequiredByBartok] + internal static extern void LinkStack0(); // Copy 0 bytes of arguments on stack. + + [StackBound(64)] + [NoStackLinkCheck] + [NoStackOverflowCheck] + [MethodImpl(MethodImplOptions.InternalCall)] + [RequiredByBartok] + internal static extern void LinkStack4(); // Copy 4 bytes of arguments on stack. + + [StackBound(64)] + [NoStackLinkCheck] + [NoStackOverflowCheck] + [MethodImpl(MethodImplOptions.InternalCall)] + [RequiredByBartok] + internal static extern void LinkStack8(); // Copy 8 bytes of arguments on stack. + + [StackBound(64)] + [NoStackLinkCheck] + [NoStackOverflowCheck] + [MethodImpl(MethodImplOptions.InternalCall)] + [RequiredByBartok] + internal static extern void LinkStack12(); // Copy 12 bytes of arguments on stack. + + [StackBound(64)] + [NoStackLinkCheck] + [NoStackOverflowCheck] + [MethodImpl(MethodImplOptions.InternalCall)] + [RequiredByBartok] + internal static extern void LinkStack16(); // Copy 16 bytes of arguments on stack. + + [StackBound(64)] + [NoStackLinkCheck] + [NoStackOverflowCheck] + [MethodImpl(MethodImplOptions.InternalCall)] + [RequiredByBartok] + internal static extern void LinkStack20(); // Copy 20 bytes of arguments on stack. + + [StackBound(64)] + [NoStackLinkCheck] + [NoStackOverflowCheck] + [MethodImpl(MethodImplOptions.InternalCall)] + [RequiredByBartok] + internal static extern void LinkStack24(); // Copy 24 bytes of arguments on stack. + + [StackBound(64)] + [NoStackLinkCheck] + [NoStackOverflowCheck] + [MethodImpl(MethodImplOptions.InternalCall)] + [RequiredByBartok] + internal static extern void LinkStack28(); // Copy 28 bytes of arguments on stack. + + [StackBound(64)] + [NoStackLinkCheck] + [NoStackOverflowCheck] + [MethodImpl(MethodImplOptions.InternalCall)] + [RequiredByBartok] + internal static extern void LinkStack32(); // Copy 32 bytes of arguments on stack. + + [StackBound(64)] + [NoStackLinkCheck] + [NoStackOverflowCheck] + [MethodImpl(MethodImplOptions.InternalCall)] + [RequiredByBartok] + internal static extern void LinkStack36(); // Copy 36 bytes of arguments on stack. + + [StackBound(64)] + [NoStackLinkCheck] + [NoStackOverflowCheck] + [MethodImpl(MethodImplOptions.InternalCall)] + [RequiredByBartok] + internal static extern void LinkStack40(); // Copy 40 bytes of arguments on stack. + + [StackBound(64)] + [NoStackLinkCheck] + [NoStackOverflowCheck] + [MethodImpl(MethodImplOptions.InternalCall)] + [RequiredByBartok] + internal static extern void LinkStack44(); // Copy 44 bytes of arguments on stack. + + [StackBound(64)] + [NoStackLinkCheck] + [NoStackOverflowCheck] + [MethodImpl(MethodImplOptions.InternalCall)] + [RequiredByBartok] + internal static extern void LinkStack48(); // Copy 48 bytes of arguments on stack. + + [StackBound(64)] + [NoStackLinkCheck] + [NoStackOverflowCheck] + [MethodImpl(MethodImplOptions.InternalCall)] + [RequiredByBartok] + internal static extern void LinkStack52(); // Copy 52 bytes of arguments on stack. + + [StackBound(64)] + [NoStackLinkCheck] + [NoStackOverflowCheck] + [MethodImpl(MethodImplOptions.InternalCall)] + [RequiredByBartok] + internal static extern void LinkStack56(); // Copy 56 bytes of arguments on stack. + + [StackBound(64)] + [NoStackLinkCheck] + [NoStackOverflowCheck] + [MethodImpl(MethodImplOptions.InternalCall)] + [RequiredByBartok] + internal static extern void LinkStack60(); // Copy 60 bytes of arguments on stack. + + [StackBound(64)] + [NoStackLinkCheck] + [NoStackOverflowCheck] + [MethodImpl(MethodImplOptions.InternalCall)] + [RequiredByBartok] + internal static extern void LinkStack64(); // Copy 64 bytes of arguments on stack. + + [ExternalStaticData] + internal static byte UnlinkStackBegin; + + [ExternalStaticData] + internal static byte UnlinkStackLimit; + } +} diff --git a/base/Applications/Runtime/Singularity/Naming/NameService.sg b/base/Applications/Runtime/Singularity/Naming/NameService.sg new file mode 100644 index 0000000..c7ecf1f --- /dev/null +++ b/base/Applications/Runtime/Singularity/Naming/NameService.sg @@ -0,0 +1,30 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: DirectoryService.sg +// +// Note: +// +// This file provides an implementation of Directory.DirectoryService.NewClientEndpoint +// that calls through the ABI to retrieve the name-service channel endpoint. +// This is for use by applications; kernel components can call the "real" +// DirectoryService class directly. +// + +using Microsoft.Singularity; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.V1.Services; + +namespace Microsoft.Singularity.Directory +{ + public class DirectoryService + { + public static unsafe DirectoryServiceContract.Imp!:Ready NewClientEndpoint() + { + return (DirectoryServiceContract.Imp!)ProcessService.GetNamespaceEndpoint(); + } + } +} diff --git a/base/Applications/Runtime/Singularity/Processor.cs b/base/Applications/Runtime/Singularity/Processor.cs new file mode 100644 index 0000000..9ef1c6f --- /dev/null +++ b/base/Applications/Runtime/Singularity/Processor.cs @@ -0,0 +1,237 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Processor.cs +// +// Note: +// + +namespace Microsoft.Singularity +{ + using System; + using System.Runtime.InteropServices; + using System.Runtime.CompilerServices; + using System.Threading; + + using Microsoft.Singularity.X86; + using Microsoft.Singularity.V1.Services; + + [CLSCompliant(false)] + [NoCCtor] + public class Processor + { + public static long CyclesPerSecond + { + [NoHeapAllocation] + get { return ProcessService.GetCyclesPerSecond(); } + } + + public static ulong CycleCount + { + [NoHeapAllocation] + get { return GetCycleCount(); } + } + + //////////////////////////////////////////////////// External Methods. + // + [AccessedByRuntime("output to header : defined in Processor.cpp")] + [MethodImpl(MethodImplOptions.InternalCall)] + [StackBound(32)] + [NoHeapAllocation] + public static extern ulong GetCycleCount(); + + [AccessedByRuntime("output to header : defined in Processor.cpp")] + [MethodImpl(MethodImplOptions.InternalCall)] + [StackBound(32)] + [NoHeapAllocation] + internal static unsafe extern UIntPtr GetFrameEip(UIntPtr ebp); + + [AccessedByRuntime("output to header : defined in Processor.cpp")] + [MethodImpl(MethodImplOptions.InternalCall)] + [StackBound(32)] + [NoHeapAllocation] + internal static unsafe extern UIntPtr GetFrameEbp(UIntPtr ebp); + + [AccessedByRuntime("output to header : defined in Processor.cpp")] + [MethodImpl(MethodImplOptions.InternalCall)] + [GCAnnotation(GCOption.NOGC)] + [StackBound(32)] + [NoHeapAllocation] + internal static extern UIntPtr GetStackPointer(); + + [AccessedByRuntime("output to header : defined in Processor.cpp")] + [MethodImpl(MethodImplOptions.InternalCall)] + [GCAnnotation(GCOption.NOGC)] + [StackBound(32)] + [NoHeapAllocation] + internal static extern UIntPtr GetFramePointer(); + + [AccessedByRuntime("output to header : defined in Processor.cpp")] + [MethodImpl(MethodImplOptions.InternalCall)] + [GCAnnotation(GCOption.NOGC)] + [StackBound(32)] + [NoHeapAllocation] + internal static unsafe extern ThreadContext * GetCurrentThreadContext(); + + [AccessedByRuntime("output to header : defined in Processor.cpp")] + [MethodImpl(MethodImplOptions.InternalCall)] + [GCAnnotation(GCOption.NOGC)] + [StackBound(32)] + [NoHeapAllocation] + internal static unsafe extern ProcessorContext * GetCurrentProcessorContext(); + + [AccessedByRuntime("output to header : defined in Processor.cpp")] + [MethodImpl(MethodImplOptions.InternalCall)] + [GCAnnotation(GCOption.NOGC)] + [StackBound(32)] + [NoHeapAllocation] + internal static extern Thread GetCurrentThread(); + + ////////////////////////////////////////////////////////////////////////////// + // + [AccessedByRuntime("output to header : defined in Processor.cpp")] + [MethodImpl(MethodImplOptions.InternalCall)] + [GCAnnotation(GCOption.NOGC)] + [StackBound(16)] + [NoHeapAllocation] + public static extern void WriteMsr(uint offset, + ulong value); + + [AccessedByRuntime("output to header : defined in Processor.cpp")] + [MethodImpl(MethodImplOptions.InternalCall)] + [GCAnnotation(GCOption.NOGC)] + [StackBound(16)] + [NoHeapAllocation] + public static extern ulong ReadMsr(uint offset); + + [AccessedByRuntime("output to header : defined in Processor.cpp")] + [MethodImpl(MethodImplOptions.InternalCall)] + [GCAnnotation(GCOption.NOGC)] + [StackBound(64)] + [NoHeapAllocation] + public static extern void ReadCpuid(uint feature, + out uint v0, + out uint v1, + out uint v2, + out uint v3); + + [AccessedByRuntime("output to header : defined in Processor.cpp")] + [MethodImpl(MethodImplOptions.InternalCall)] + [GCAnnotation(GCOption.NOGC)] + [StackBound(16)] + [NoHeapAllocation] + public static extern ulong ReadPmc(uint offset); + + [AccessedByRuntime("output to header : defined in Processor.cpp")] + [MethodImpl(MethodImplOptions.InternalCall)] + [GCAnnotation(GCOption.NOGC)] + [StackBound(32)] + [NoHeapAllocation] + internal static extern void EnterRing3(); + + [AccessedByRuntime("output to header : defined in Processor.cpp")] + [MethodImpl(MethodImplOptions.InternalCall)] + [GCAnnotation(GCOption.NOGC)] + [StackBound(32)] + [NoHeapAllocation] + public static extern bool AtKernelPrivilege(); + + ////////////////////////////////////////////////////////////////////// + // + // + // These methods are currently marked external because they are used + // by device drivers. We need a tool to verify that device drivers + // are in fact using them correctly! + // + [AccessedByRuntime("output to header : defined in Processor.cpp")] + [MethodImpl(MethodImplOptions.InternalCall)] + [GCAnnotation(GCOption.NOGC)] + [StackBound(16)] + [NoHeapAllocation] + public static extern bool DisableInterrupts(); + + [AccessedByRuntime("output to header : defined in Processor.cpp")] + [MethodImpl(MethodImplOptions.InternalCall)] + [GCAnnotation(GCOption.NOGC)] + [StackBound(16)] + [NoHeapAllocation] + public static extern void RestoreInterrupts(bool enabled); + + // Use this method for assertions only! + [AccessedByRuntime("output to header : defined in Processor.cpp")] + [MethodImpl(MethodImplOptions.InternalCall)] + [GCAnnotation(GCOption.NOGC)] + [StackBound(16)] + [NoHeapAllocation] + public static extern bool InterruptsDisabled(); + + ////////////////////////////////////////////////////////////////////// + // + // + // These methods are public and safe to use from any where provided + // there's at least 2 call frame on the stack. + // + [NoHeapAllocation] + public static UIntPtr GetCallerEip() + { + UIntPtr currentFrame = GetFramePointer(); + UIntPtr callerFrame = GetFrameEbp(currentFrame); + if (callerFrame == UIntPtr.Zero) { + return UIntPtr.Zero; + } + UIntPtr callersCaller = GetFrameEip(callerFrame); + return callersCaller; + } + + /// + /// Provides a mini stack trace starting from the caller of the caller + /// of this method. + /// + [NoHeapAllocation] + public static void GetStackEips(out UIntPtr pc1, out UIntPtr pc2, out UIntPtr pc3) + { + pc1 = UIntPtr.Zero; + pc2 = UIntPtr.Zero; + pc3 = UIntPtr.Zero; + + UIntPtr currentFrame = GetFramePointer(); + UIntPtr callerFrame = GetFrameEbp(currentFrame); + if (callerFrame == UIntPtr.Zero) { + return; + } + pc1 = GetFrameEip(callerFrame); + callerFrame = GetFrameEbp(callerFrame); + if (callerFrame == UIntPtr.Zero) { + return; + } + pc2 = GetFrameEip(callerFrame); + callerFrame = GetFrameEbp(callerFrame); + if (callerFrame == UIntPtr.Zero) { + return; + } + pc3 = GetFrameEip(callerFrame); + } + + /// + /// Provides the full stack trace starting from the caller of the caller + /// of this method. + /// + /// Eip values in stack array from top to bottom + [NoHeapAllocation] + public static void GetStackEips(UIntPtr[] stack) + { + if (stack == null) { + return; + } + UIntPtr currentFrame = GetFramePointer(); + UIntPtr callerFrame = GetFrameEbp(currentFrame); + for (int index = 0; callerFrame != UIntPtr.Zero && index < stack.Length; index++) { + stack[index] = GetFrameEip(callerFrame); + callerFrame = GetFrameEbp(callerFrame); + } + } + } +} diff --git a/base/Applications/Runtime/System/Console.cs b/base/Applications/Runtime/System/Console.cs new file mode 100644 index 0000000..0cd4eb6 --- /dev/null +++ b/base/Applications/Runtime/System/Console.cs @@ -0,0 +1,319 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== + +namespace System { + using Microsoft.Singularity; +#if !MINRUNTIME + using Microsoft.Singularity.Io; +#endif + using System; + using System.Text; + using System.Globalization; + using System.Runtime.CompilerServices; + + using System.Runtime.InteropServices; + + // Provides static fields for console input and output. Use + // Console.In for input from the standard input stream (stdin), + // Console.Out for output to stdout, and Console.Error + // for output to stderr. If any of those console streams are + // redirected from the command line, these streams will be redirected. + // A program can also redirect its own output or input with the + // SetIn, SetOut, and SetError methods. + // + // The distinction between Console.Out and Console.Error is useful + // for programs that redirect output to a file or a pipe. Note that + // stdout and stderr can be output to different files at the same + // time from the DOS command line: + // + // someProgram 1> out 2> err + // + //| + public sealed class Console + { + private Console() + { + throw new NotSupportedException("NotSupported_Constructor"); + } + + static Console() { + } + + + private static void WriteInternal(char[] buffer, int index, int count) + { +#if !MINRUNTIME + ConsoleOutput.Write(buffer, index, count); +#else + for (int i = 0; i < count; i++) { + DebugStub.Print(buffer[index + i]); + } +#endif + } + + private static void WriteInternal(String value) + { +#if !MINRUNTIME + ConsoleOutput.Write(value); +#else + DebugStub.Print(value); +#endif + } + + private static void WriteNewLine() + { + WriteInternal(Environment.NewLine); + } + + //| + public static void WriteLine() + { + WriteNewLine(); + } + + //| + public static void WriteLine(String value) + { + WriteInternal(value); + WriteNewLine(); + } + + //| + public static void WriteLine(bool value) + { + WriteInternal(value.ToString()); + WriteNewLine(); + } + + //| + public static void WriteLine(char value) + { + WriteInternal(value.ToString()); + WriteNewLine(); + } + + //| + public static void WriteLine(char[] buffer) + { + WriteInternal(buffer, 0, buffer.Length); + WriteNewLine(); + } + + //| + public static void WriteLine(char[] buffer, int index, int count) + { + WriteInternal(buffer, index, count); + WriteNewLine(); + } + + //| + public static void WriteLine(decimal value) + { + WriteInternal(value.ToString()); + WriteNewLine(); + } + + //| + public static void WriteLine(double value) + { + WriteInternal(value.ToString()); + WriteNewLine(); + } + + //| + public static void WriteLine(float value) + { + WriteInternal(value.ToString()); + WriteNewLine(); + } + + //| + public static void WriteLine(int value) + { + WriteInternal(value.ToString()); + WriteNewLine(); + } + + //| + [CLSCompliant(false)] + public static void WriteLine(uint value) + { + WriteInternal(value.ToString()); + WriteNewLine(); + } + + //| + public static void WriteLine(long value) + { + WriteInternal(value.ToString()); + WriteNewLine(); + } + + //| + [CLSCompliant(false)] + public static void WriteLine(ulong value) + { + WriteInternal(value.ToString()); + WriteNewLine(); + } + + //| + public static void WriteLine(Object value) + { + WriteInternal(value.ToString()); + WriteNewLine(); + } + + //| + public static void WriteLine(String format, Object arg0) + { + WriteInternal(String.Format(format, arg0)); + WriteNewLine(); + } + + //| + public static void WriteLine(String format, Object arg0, Object arg1) + { + WriteInternal(String.Format(format, arg0, arg1)); + WriteNewLine(); + } + + //| + public static void WriteLine(String format, Object arg0, Object arg1, Object arg2) + { + WriteInternal(String.Format(format, arg0, arg1, arg2)); + WriteNewLine(); + } + + //| + public static void WriteLine(String format, params Object[] args) + { + WriteInternal(String.Format(format, args)); + WriteNewLine(); + } + + //| + public static void Write(String format, Object arg0) + { + WriteInternal(String.Format(format, arg0)); + } + + //| + public static void Write(String format, Object arg0, Object arg1) + { + WriteInternal(String.Format(format, arg0, arg1)); + } + + //| + public static void Write(String format, Object arg0, Object arg1, Object arg2) + { + WriteInternal(String.Format(format, arg0, arg1, arg2)); + } + + //| + public static void Write(String format, params Object[] args) + { + WriteInternal(String.Format(format, args)); + } + + //| + public static void Write(bool value) + { + WriteInternal(value.ToString()); + } + + //| + public static void Write(char value) + { + WriteInternal(value.ToString()); + } + + //| + public static void Write(char[] buffer) + { + WriteInternal(buffer, 0, buffer.Length); + } + + //| + public static void Write(char[] buffer, int index, int count) + { + WriteInternal(buffer, index, count); + } + + //| + public static void Write(double value) + { + WriteInternal(value.ToString()); + } + + //| + public static void Write(decimal value) + { + WriteInternal(value.ToString()); + } + + //| + public static void Write(float value) + { + WriteInternal(value.ToString()); + } + + //| + public static void Write(int value) + { + WriteInternal(value.ToString()); + } + + //| + [CLSCompliant(false)] + public static void Write(uint value) + { + WriteInternal(value.ToString()); + } + + //| + public static void Write(long value) + { + WriteInternal(value.ToString()); + } + + //| + [CLSCompliant(false)] + public static void Write(ulong value) + { + WriteInternal(value.ToString()); + } + + //| + public static void Write(Object value) + { + WriteInternal(value.ToString()); + } + + //| + public static void Write(String value) + { + WriteInternal(value); + } + + public static int Read() + { +#if !MINRUNTIME + return ConsoleInput.ReadChar(); +#else + return -1; +#endif + } + public static string ReadLine() + { +#if !MINRUNTIME + return ConsoleInput.ReadLine(); +#else + return ""; +#endif + } + } +} diff --git a/base/Applications/Runtime/System/DateTime.cs b/base/Applications/Runtime/System/DateTime.cs new file mode 100644 index 0000000..72ccac3 --- /dev/null +++ b/base/Applications/Runtime/System/DateTime.cs @@ -0,0 +1,783 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +namespace System { + + using System; + using System.Threading; + using System.Globalization; + using System.Runtime.InteropServices; + using System.Runtime.CompilerServices; + using CultureInfo = System.Globalization.CultureInfo; + using Microsoft.Singularity.V1.Services; + + // This value type represents a date and time. Every DateTime + // object has a private field (Ticks) of type Int64 that stores the + // date and time as the number of 100 nanosecond intervals since + // 12:00 AM January 1, year 1 A.D. in the proleptic Gregorian Calendar. + // + // DateTime spans from 1 A.D. to ~29247 A.D. + // + // For a description of various calendar issues, look at + // + // Calendar Studies web site, at + // http://serendipity.nofadz.com/hermetic/cal_stud.htm. + // + // + // Warning about 2 digit years + // As a temporary hack until we get new DateTime <;->; String code, + // some systems won't be able to round trip dates less than 1930. This + // is because we're using OleAut's string parsing routines, which look + // at your computer's default short date string format, which uses 2 digit + // years on most computers. To fix this, go to Control Panel ->; Regional + // Settings ->; Date and change the short date style to something like + // "M/d/yyyy" (specifying four digits for the year). + // + //| + [StructLayout(LayoutKind.Auto)] + public struct DateTime : IComparable, IFormattable + { + // Number of 100ns ticks per time unit + public const long TicksPerMillisecond = 10000; + public const long TicksPerSecond = TicksPerMillisecond * 1000; + public const long TicksPerMinute = TicksPerSecond * 60; + public const long TicksPerHour = TicksPerMinute * 60; + public const long TicksPerDay = TicksPerHour * 24; + + // Number of milliseconds per time unit + private const int MillisPerSecond = 1000; + private const int MillisPerMinute = MillisPerSecond * 60; + private const int MillisPerHour = MillisPerMinute * 60; + private const int MillisPerDay = MillisPerHour * 24; + + // Number of days in a non-leap year + private const int DaysPerYear = 365; + // Number of days in 4 years + private const int DaysPer4Years = DaysPerYear * 4 + 1; + // Number of days in 100 years + private const int DaysPer100Years = DaysPer4Years * 25 - 1; + // Number of days in 400 years + private const int DaysPer400Years = DaysPer100Years * 4 + 1; + + // Number of days from 1/1/0001 to 12/31/1600 + private const int DaysTo1601 = DaysPer400Years * 4; + // Number of days from 1/1/0001 to 12/30/1899 + private const int DaysTo1899 = DaysPer400Years * 4 + DaysPer100Years * 3 - 367; + // Number of days from 1/1/0001 to 12/31/9999 + private const int DaysTo10000 = DaysPer400Years * 25 - 366; + + private const long MinTicks = 0; + private const long MaxTicks = DaysTo10000 * TicksPerDay - 1; + private const long MaxMillis = (long)DaysTo10000 * MillisPerDay; + + private const long FileTimeOffset = DaysTo1601 * TicksPerDay; + + private const int DatePartYear = 0; + private const int DatePartDayOfYear = 1; + private const int DatePartMonth = 2; + private const int DatePartDay = 3; + + private static readonly int[] DaysToMonth365 = { + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}; + private static readonly int[] DaysToMonth366 = { + 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}; + + //| + public static readonly DateTime MinValue = new DateTime(MinTicks); + //| + public static readonly DateTime MaxValue = new DateTime(MaxTicks); + + // + // NOTE yslin: Before the time zone is introduced, ticks is based on 1/1/0001 local time. + // + private long ticks; + + // Constructs a DateTime from a tick count. The ticks + // argument specifies the date as the number of 100-nanosecond intervals + // that have elapsed since 1/1/0001 12:00am. + // + //| + public DateTime(long ticks) { + if (ticks < MinTicks || ticks > MaxTicks) + throw new ArgumentOutOfRangeException("ticks", "ArgumentOutOfRange_DateTimeBadTicks"); + this.ticks = ticks; + } + + [NoHeapAllocation] + private DateTime(long ticksFound, int ignoreMe) { + this.ticks = ticksFound; + if ((ulong)ticks>(ulong)MaxTicks) { + if (ticks>MaxTicks) { + ticks = MaxTicks; + } else { + ticks = MinTicks; + } + } + } + + // Constructs a DateTime from a given year, month, and day. The + // time-of-day of the resulting DateTime is always midnight. + // + //| + public DateTime(int year, int month, int day) { + ticks = DateToTicks(year, month, day); + } + + // Constructs a DateTime from a given year, month, day, hour, + // minute, and second. + // + //| + public DateTime(int year, int month, int day, int hour, int minute, int second) { + ticks = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second); + } + + // Constructs a DateTime from a given year, month, day, hour, + // minute, and second. + // + //| + public DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond) { + ticks = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second); + if (millisecond < 0 || millisecond >= MillisPerSecond) { + throw new ArgumentOutOfRangeException("millisecond", String.Format("ArgumentOutOfRange_Range", 0, MillisPerSecond - 1)); + } + ticks += millisecond * TicksPerMillisecond; + if (ticks < MinTicks || ticks > MaxTicks) + throw new ArgumentException("Arg_DateTimeRange"); + } + + // Returns the DateTime resulting from adding the given + // TimeSpan to this DateTime. + // + //| + public DateTime Add(TimeSpan value) { + return new DateTime(ticks + value._ticks); + } + + // Returns the DateTime resulting from adding a number of + // time units to this DateTime. + private DateTime Add(long value, int scale) { + long millis = value * scale; + if (millis <= -MaxMillis || millis >= MaxMillis) { + throw new ArgumentOutOfRangeException("ArgumentOutOfRange_AddValue"); + } + return new DateTime(ticks + millis * TicksPerMillisecond); + } + + // Returns the DateTime resulting from adding a number of + // days to this DateTime. The result is computed by rounding the + // fractional number of days given by value to the nearest + // millisecond, and adding that interval to this DateTime. The + // value argument is permitted to be negative. + // + //| + public DateTime AddDays(long value) { + return Add(value, MillisPerDay); + } + + // Returns the DateTime resulting from adding a number of + // hours to this DateTime. The result is computed by rounding the + // fractional number of hours given by value to the nearest + // millisecond, and adding that interval to this DateTime. The + // value argument is permitted to be negative. + // + //| + public DateTime AddHours(long value) { + return Add(value, MillisPerHour); + } + + // Returns the DateTime resulting from the given number of + // milliseconds to this DateTime. The result is computed by rounding + // the number of milliseconds given by value to the nearest integer, + // and adding that interval to this DateTime. The value + // argument is permitted to be negative. + // + //| + public DateTime AddMilliseconds(long value) { + return Add(value, 1); + } + + // Returns the DateTime resulting from adding a number of + // minutes to this DateTime. The result is computed by rounding the + // fractional number of minutes given by value to the nearest + // millisecond, and adding that interval to this DateTime. The + // value argument is permitted to be negative. + // + //| + public DateTime AddMinutes(long value) { + return Add(value, MillisPerMinute); + } + + // Returns the DateTime resulting from adding the given number of + // months to this DateTime. The result is computed by incrementing + // (or decrementing) the year and month parts of this DateTime by + // months months, and, if required, adjusting the day part of the + // resulting date downwards to the last day of the resulting month in the + // resulting year. The time-of-day part of the result is the same as the + // time-of-day part of this DateTime. + // + // In more precise terms, considering this DateTime to be of the + // form y / m / d + t, where y is the + // year, m is the month, d is the day, and t is the + // time-of-day, the result is y1 / m1 / d1 + t, + // where y1 and m1 are computed by adding months months + // to y and m, and d1 is the largest value less than + // or equal to d that denotes a valid day in month m1 of year + // y1. + // + //| + public DateTime AddMonths(int months) { + if (months < -120000 || months > 120000) throw new ArgumentOutOfRangeException("months", "ArgumentOutOfRange_DateTimeBadMonths"); + int y = GetDatePart(DatePartYear); + int m = GetDatePart(DatePartMonth); + int d = GetDatePart(DatePartDay); + int i = m - 1 + months; + if (i >= 0) { + m = i % 12 + 1; + y = y + i / 12; + } + else { + m = 12 + (i + 1) % 12; + y = y + (i - 11) / 12; + } + int days = DaysInMonth(y, m); + if (d > days) d = days; + return new DateTime(DateToTicks(y, m, d) + ticks % TicksPerDay); + } + + // Returns the DateTime resulting from adding a number of + // seconds to this DateTime. The result is computed by rounding the + // fractional number of seconds given by value to the nearest + // millisecond, and adding that interval to this DateTime. The + // value argument is permitted to be negative. + // + //| + public DateTime AddSeconds(long value) { + return Add(value, MillisPerSecond); + } + + // Returns the DateTime resulting from adding the given number of + // 100-nanosecond ticks to this DateTime. The value argument + // is permitted to be negative. + // + //| + public DateTime AddTicks(long value) { + return new DateTime(ticks + value); + } + + // Returns the DateTime resulting from adding the given number of + // years to this DateTime. The result is computed by incrementing + // (or decrementing) the year part of this DateTime by value + // years. If the month and day of this DateTime is 2/29, and if the + // resulting year is not a leap year, the month and day of the resulting + // DateTime becomes 2/28. Otherwise, the month, day, and time-of-day + // parts of the result are the same as those of this DateTime. + // + //| + public DateTime AddYears(int value) { + return AddMonths(value * 12); + } + + + + // Compares two DateTime values, returning an integer that indicates + // their relationship. + // + //| + [NoHeapAllocation] + public static int Compare(DateTime t1, DateTime t2) { + if (t1.ticks > t2.ticks) return 1; + if (t1.ticks < t2.ticks) return -1; + return 0; + } + + // Compares this DateTime to a given object. This method provides an + // implementation of the IComparable interface. The object + // argument must be another DateTime, or otherwise an exception + // occurs. Null is considered less than any instance. + // + // Returns a value less than zero if this object + //| + public int CompareTo(Object value) { + if (value == null) return 1; + if (!(value is DateTime)) { + throw new ArgumentException("Arg_MustBeDateTime"); + } + + long t = ((DateTime)value).ticks; + if (ticks > t) return 1; + if (ticks < t) return -1; + return 0; + } + + // Returns the tick count corresponding to the given year, month, and day. + // Will check the if the parameters are valid. + private static long DateToTicks(int year, int month, int day) { + if (year >= 1 && year <= 9999 && month >= 1 && month <= 12) { + int[] days = IsLeapYear(year)? DaysToMonth366: DaysToMonth365; + if (day >= 1 && day <= days[month] - days[month - 1]) { + int y = year - 1; + int n = y * 365 + y / 4 - y / 100 + y / 400 + days[month - 1] + day - 1; + return n * TicksPerDay; + } + } + throw new ArgumentOutOfRangeException("ArgumentOutOfRange_BadYearMonthDay"); + } + + // Return the tick count corresponding to the given hour, minute, second. + // Will check the if the parameters are valid. + private static long TimeToTicks(int hour, int minute, int second) + { + //TimeSpan.TimeToTicks is a family access function which does no error checking, so + //we need to put some error checking out here. + if (hour >= 0 && hour < 24 && minute >= 0 && minute < 60 && second >=0 && second < 60) + { + return (TimeSpan.TimeToTicks(hour, minute, second)); + } + throw new ArgumentOutOfRangeException("ArgumentOutOfRange_BadHourMinuteSecond"); + } + + // Returns the number of days in the month given by the year and + // month arguments. + // + //| + public static int DaysInMonth(int year, int month) { + if (month < 1 || month > 12) throw new ArgumentOutOfRangeException("ArgumentOutOfRange_Month"); + int[] days = IsLeapYear(year)? DaysToMonth366: DaysToMonth365; + return days[month] - days[month - 1]; + } + + // Checks if this DateTime is equal to a given object. Returns + // true if the given object is a boxed DateTime and its value + // is equal to the value of this DateTime. Returns false + // otherwise. + // + //| + public override bool Equals(Object value) { + if (value is DateTime) { + return ticks == ((DateTime)value).ticks; + } + return false; + } + + // Compares two DateTime values for equality. Returns true if + // the two DateTime values are equal, or false if they are + // not equal. + // + //| + [NoHeapAllocation] + public static bool Equals(DateTime t1, DateTime t2) { + return t1.ticks == t2.ticks; + } + + //| + public static DateTime FromFileTimeUtc(long fileTime) { + if (fileTime < 0) + throw new ArgumentOutOfRangeException("ArgumentOutOfRange_FileTimeInvalid"); + + // This is the ticks in Universal time for this fileTime. + long universalTicks = fileTime + FileTimeOffset; + return new DateTime(universalTicks); + } + + // Returns the date part of this DateTime. The resulting value + // corresponds to this DateTime with the time-of-day part set to + // zero (midnight). + // + //| + public DateTime Date { + get { return new DateTime(ticks - ticks % TicksPerDay); } + } + + // Returns a given date part of this DateTime. This method is used + // to compute the year, day-of-year, month, or day part. + [NoHeapAllocation] + private int GetDatePart(int part) { + // n = number of days since 1/1/0001 + int n = (int)(ticks / TicksPerDay); + // y400 = number of whole 400-year periods since 1/1/0001 + int y400 = n / DaysPer400Years; + // n = day number within 400-year period + n -= y400 * DaysPer400Years; + // y100 = number of whole 100-year periods within 400-year period + int y100 = n / DaysPer100Years; + // Last 100-year period has an extra day, so decrement result if 4 + if (y100 == 4) y100 = 3; + // n = day number within 100-year period + n -= y100 * DaysPer100Years; + // y4 = number of whole 4-year periods within 100-year period + int y4 = n / DaysPer4Years; + // n = day number within 4-year period + n -= y4 * DaysPer4Years; + // y1 = number of whole years within 4-year period + int y1 = n / DaysPerYear; + // Last year has an extra day, so decrement result if 4 + if (y1 == 4) y1 = 3; + // If year was requested, compute and return it + if (part == DatePartYear) { + return y400 * 400 + y100 * 100 + y4 * 4 + y1 + 1; + } + // n = day number within year + n -= y1 * DaysPerYear; + // If day-of-year was requested, return it + if (part == DatePartDayOfYear) return n + 1; + // Leap year calculation looks different from IsLeapYear since y1, y4, + // and y100 are relative to year 1, not year 0 + bool leapYear = y1 == 3 && (y4 != 24 || y100 == 3); + int[] days = leapYear? DaysToMonth366: DaysToMonth365; + // All months have less than 32 days, so n >> 5 is a good conservative + // estimate for the month + int m = n >> 5 + 1; + // m = 1-based month number + while (n >= days[m]) m++; + // If month was requested, return it + if (part == DatePartMonth) return m; + // Return 1-based day-of-month + return n - days[m - 1] + 1; + } + + // Returns the day-of-month part of this DateTime. The returned + // value is an integer between 1 and 31. + // + //| + public int Day { + [NoHeapAllocation] + get { return GetDatePart(DatePartDay); } + } + + // Returns the day-of-week part of this DateTime. The returned value + // is an integer between 0 and 6, where 0 indicates Sunday, 1 indicates + // Monday, 2 indicates Tuesday, 3 indicates Wednesday, 4 indicates + // Thursday, 5 indicates Friday, and 6 indicates Saturday. + // + //| + public DayOfWeek DayOfWeek { + [NoHeapAllocation] + get { return (DayOfWeek)((ticks / TicksPerDay + 1) % 7); } + } + + // Returns the day-of-year part of this DateTime. The returned value + // is an integer between 1 and 366. + // + //| + public int DayOfYear { + [NoHeapAllocation] + get { return GetDatePart(DatePartDayOfYear); } + } + + // Returns the hash code for this DateTime. + // + //| + public override int GetHashCode() { + return (int)ticks ^ (int)(ticks >> 32); + } + + // Returns the hour part of this DateTime. The returned value is an + // integer between 0 and 23. + // + //| + public int Hour { + [NoHeapAllocation] + get { return (int)((ticks / TicksPerHour) % 24); } + } + + // Returns the millisecond part of this DateTime. The returned value + // is an integer between 0 and 999. + // + //| + public int Millisecond { + [NoHeapAllocation] + get { return (int)((ticks / TicksPerMillisecond) % 1000); } + } + + // Returns the minute part of this DateTime. The returned value is + // an integer between 0 and 59. + // + //| + public int Minute { + [NoHeapAllocation] + get { return (int)((ticks / TicksPerMinute) % 60); } + } + + // Returns the month part of this DateTime. The returned value is an + // integer between 1 and 12. + // + //| + public int Month { + [NoHeapAllocation] + get { return GetDatePart(DatePartMonth); } + } + + [NoHeapAllocation] + private static DateTime GetUtcTime() + { + return ProcessService.GetUtcTime(); + } + + // Returns a DateTime representing the current date and time. The + // resolution of the returned value depends on the system timer. For + // Windows NT 3.5 and later the timer resolution is approximately 10ms, + // for Windows NT 3.1 it is approximately 16ms, and for Windows 95 and 98 + // it is approximately 55ms. + // + //| + public static DateTime Now { + [NoHeapAllocation] + get { return GetUtcTime(); } + } + + //| + public static DateTime UtcNow { + [NoHeapAllocation] + get { return GetUtcTime(); } + } + + public static DateTime BootTime { + get { return Now - ProcessService.GetUpTime(); } + } + + // Returns the second part of this DateTime. The returned value is + // an integer between 0 and 59. + // + //| + public int Second { + [NoHeapAllocation] + get { return (int)((ticks / TicksPerSecond) % 60); } + } + + // Returns the tick count for this DateTime. The returned value is + // the number of 100-nanosecond intervals that have elapsed since 1/1/0001 + // 12:00am. + // + //| + public long Ticks { + [NoHeapAllocation] + get { return ticks; } + } + + // Returns the time-of-day part of this DateTime. The returned value + // is a TimeSpan that indicates the time elapsed since midnight. + // + //| + public TimeSpan TimeOfDay { + get { return new TimeSpan(ticks % TicksPerDay); } + } + + // Returns a DateTime representing the current date. The date part + // of the returned value is the current date, and the time-of-day part of + // the returned value is zero (midnight). + // + //| + public static DateTime Today { + get { + long ticks = Now.Ticks; + return new DateTime(ticks - ticks % TicksPerDay); + } + } + + // Returns the year part of this DateTime. The returned value is an + // integer between 1 and 9999. + // + //| + public int Year { + [NoHeapAllocation] + get { return GetDatePart(DatePartYear); } + } + + // Checks whether a given year is a leap year. This method returns true if + // year is a leap year, or false if not. + // + //| + [NoHeapAllocation] + public static bool IsLeapYear(int year) { + return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); + } + + // Constructs a DateTime from a string. The string must specify a + // date and optionally a time in a culture-specific or universal format. + // Leading and trailing whitespace characters are allowed. + // + //| + public static DateTime Parse(String s) { + throw new Exception("Parse not supported in Bartok"); + } + + // Constructs a DateTime from a string. The string must specify a + // date and optionally a time in a culture-specific or universal format. + // Leading and trailing whitespace characters are allowed. + // + //| + public static DateTime ParseExact(String s, String format) { + throw new Exception("Parse not supported in Bartok"); + } + + //| + public TimeSpan Subtract(DateTime value) { + return new TimeSpan(ticks - value.ticks); + } + + //| + public DateTime Subtract(TimeSpan value) { + return new DateTime(ticks - value._ticks); + } + + //| + public long ToFileTimeUtc() { + long t = this.ticks - FileTimeOffset; + if (t < 0) throw new ArgumentOutOfRangeException("ArgumentOutOfRange_FileTimeInvalid"); + return t; + } + + //| + public String ToLongDateString() { + return (ToString("D")); + } + + //| + public String ToLongTimeString() { + return (ToString("T")); + } + + //| + public String ToShortDateString() { + return (ToString("d")); + } + + //| + public String ToShortTimeString() { + return (ToString("t")); + } + + //| + public override String ToString() { + return ToString(null); + } + + //| + public String ToString(String format) { + // US-centric representation for now, until we have proper + // globalization in Singularity. + // + // The only special support here is for RFC1123 ("R" / "r") + if (format != null && (format.Equals("R") || format.Equals("r"))) { + return String.Format("{0:s}, {1:d02} {2:s} {3:d} {4:d02}:{5:d02}:{6:d02} GMT", + GetShortWeekday(), Day, GetShortMonth(), Year, + Hour, Minute, Second); + } else { + return String.Format("{0:d}/{1:d}/{2:d} {3:d}:{4:d}:{5:d}", + Month, Day, Year, Hour, Minute, Second); + } + } + + public DateTime ToLocalTime() { + long tickCount = this.ticks; + return new DateTime(tickCount); + } + + //| + public DateTime ToUniversalTime() { + long tickCount = this.ticks; + return new DateTime(tickCount); + } + + + //| + public static DateTime operator +(DateTime d, TimeSpan t) { + return new DateTime(d.ticks + t._ticks); + } + + //| + public static DateTime operator -(DateTime d, TimeSpan t) { + return new DateTime(d.ticks - t._ticks); + } + + //| + public static TimeSpan operator -(DateTime d1, DateTime d2) { + return new TimeSpan(d1.ticks - d2.ticks); + } + + //| + [NoHeapAllocation] + public static bool operator ==(DateTime d1, DateTime d2) { + return d1.ticks == d2.ticks; + } + + //| + [NoHeapAllocation] + public static bool operator !=(DateTime d1, DateTime d2) { + return d1.ticks != d2.ticks; + } + + //| + [NoHeapAllocation] + public static bool operator <(DateTime t1, DateTime t2) { + return t1.ticks < t2.ticks; + } + + //| + [NoHeapAllocation] + public static bool operator <=(DateTime t1, DateTime t2) { + return t1.ticks <= t2.ticks; + } + + //| + [NoHeapAllocation] + public static bool operator >(DateTime t1, DateTime t2) { + return t1.ticks > t2.ticks; + } + + //| + [NoHeapAllocation] + public static bool operator >=(DateTime t1, DateTime t2) { + return t1.ticks >= t2.ticks; + } + + // + // IValue implementation + // + + //| + [NoHeapAllocation] + public override TypeCode GetTypeCode() { + return TypeCode.DateTime; + } + + private string GetShortWeekday() + { + // Hardcoded USA-English until we support globalization + switch(DayOfWeek) { + case DayOfWeek.Monday : return "Mon"; + case DayOfWeek.Tuesday : return "Tue"; + case DayOfWeek.Wednesday : return "Wed"; + case DayOfWeek.Thursday : return "Thu"; + case DayOfWeek.Friday : return "Fri"; + case DayOfWeek.Saturday : return "Sat"; + case DayOfWeek.Sunday : return "Sun"; + } + + return null; + } + + private string GetShortMonth() + { + // Hardcoded USA-English until we support globalization + switch(Month) { + case 1 : return "Jan"; + case 2 : return "Feb"; + case 3 : return "Mar"; + case 4 : return "Apr"; + case 5 : return "May"; + case 6 : return "Jun"; + case 7 : return "Jul"; + case 8 : return "Aug"; + case 9 : return "Sep"; + case 10 : return "Oct"; + case 11 : return "Nov"; + case 12 : return "Dec"; + } + + return null; + } + } +} diff --git a/base/Applications/Runtime/System/Environment.cs b/base/Applications/Runtime/System/Environment.cs new file mode 100644 index 0000000..9eb2883 --- /dev/null +++ b/base/Applications/Runtime/System/Environment.cs @@ -0,0 +1,73 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +/*============================================================ +** +** Class: Environment +** +** +** Purpose: Provides some basic access to some environment +** functionality. +** +** Date: March 3, 2000 +** +============================================================*/ +namespace System { + using System.Globalization; + using System.Collections; + using System.Text; + using System.Runtime.InteropServices; + using System.Runtime.CompilerServices; + using System.Reflection; + using System.Diagnostics; + using Microsoft.Singularity; + using Microsoft.Singularity.V1.Services; + + //| + public sealed class Environment { + + private Environment() {} // Prevent from begin created + + /*==================================TickCount=================================== + **Action: Gets the number of ticks since the system was started. + **Returns: The number of ticks since the system was started. + **Arguments: None + **Exceptions: None + ==============================================================================*/ + //| + public static int TickCount { + get { + return unchecked((int)(ProcessService.GetUpTime().Ticks / 10000)); + } + } + + /*===================================NewLine==================================== + **Action: A property which returns the appropriate newline string for the given + ** platform. + **Returns: \r\n on Win32. + **Arguments: None. + **Exceptions: None. + ==============================================================================*/ + //| + public static String NewLine { + get { + return "\r\n"; + } + } + + //| + public static void Exit(int exitCode) { + ProcessService.Stop(exitCode); + } + + // + public static String StackTrace + { + get { + return " + /// A Principal struct is a representation of a principal. + /// There are methods here to retrieve the Principal of a process + /// and to resolve the principal name of a Principal. + /// See the security library for methods to evaluate whether + /// Principals satisfy ACLs. + /// + + // This is the process library version of Principal.sg. The + // kernel side is similar, but has additional methods and constructors. + + // This struct layers PrincipalHandle to hide the ABI type from clients. + + public struct Principal + { + private readonly PrincipalHandle handle; + + internal Principal(PrincipalHandle h) + { + this.handle = h; + } + + public Principal(Endpoint*! in ExHeap ep) + { + this.handle = ep->PeerPrincipalHandle; + } + + public static Principal Self() + { + return new Principal(PrincipalHandle.SelfPrincipalHandle()); + } + + public static Principal EndpointPeer(Endpoint*! in ExHeap ep) + { + return new Principal(ep->PeerPrincipalHandle); + } + + public static string ExpandAclIndirection (string! name) + { + return PrincipalHandle.ExpandAclIndirection(name); + } + + public ulong Val { get { return this.handle.val; } } + + public bool Equal(Principal p) { return (this.Val == p.Val); } + + public string! GetName() + { + return (!)PrincipalHandle.GetPrincipalName(this.handle); + } + } +} + + diff --git a/base/Applications/Runtime/System/Process.sg b/base/Applications/Runtime/System/Process.sg new file mode 100644 index 0000000..ceab039 --- /dev/null +++ b/base/Applications/Runtime/System/Process.sg @@ -0,0 +1,591 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Process.sg +// +// 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); + //Review for now NotSet is ignored and we return a string[1] below + 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; + } + if ( len == 0 ) { + // should this be "" or null? + 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]; + for (int i=0; i < value.Length; i++){ + 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]; + } + } + + /// + /// 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 + /// + 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) + { + + 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) + if (action != null) { + 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) + if (role != null) { + 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) + : this((!)arguments[0], null, null) + { + 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, + String roll) + : this(arguments, roll, 0) + { + } + + [Microsoft.Contracts.NotDelayed] + public unsafe Process(String[]! arguments) + : this(arguments, null, 0) + { + } + + /// + /// Finalizer is responsible for freeing handle that keeps corresponding + /// kernel AutoResetEvent object live. + /// + ~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 + { + if (handle.id == 0) + { + 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; + } + } + + } +} diff --git a/base/Applications/Runtime/System/ProcessCreateException.cs b/base/Applications/Runtime/System/ProcessCreateException.cs new file mode 100644 index 0000000..2f4635f --- /dev/null +++ b/base/Applications/Runtime/System/ProcessCreateException.cs @@ -0,0 +1,24 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== + +namespace System +{ + public class ProcessCreateException : SystemException + { + public ProcessCreateException() : base("Arg_ProcessCreateException") + { + } + + public ProcessCreateException(String message) : base(message) + { + } + + public ProcessCreateException(String message, Exception innerException) + : base(message, innerException) + { + } + } +} diff --git a/base/Applications/Runtime/System/Threading/AutoResetEvent.cs b/base/Applications/Runtime/System/Threading/AutoResetEvent.cs new file mode 100644 index 0000000..39996fa --- /dev/null +++ b/base/Applications/Runtime/System/Threading/AutoResetEvent.cs @@ -0,0 +1,114 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +namespace System.Threading { + + using System; + using System.Runtime.CompilerServices; + using Microsoft.Singularity; + using Microsoft.Singularity.V1.Threads; + using Microsoft.Singularity.V1.Services; + + //| + [CLSCompliant(false)] + public sealed class AutoResetEvent : WaitHandle + { + private AutoResetEventHandle handle; + + //| + public AutoResetEvent(bool initialState) + { + AutoResetEventHandle handleOnStack; + if (!AutoResetEventHandle.Create(initialState, out handleOnStack)) { + throw new HandleCreateException(); + } + handle = handleOnStack; + } + + /// + /// Finalizer is responsible for freeing handle that keeps corresponding + /// kernel AutoResetEvent object live. + /// + ~AutoResetEvent() { + if (this.handle.id != 0) { + AutoResetEventHandle.Dispose(this.handle); + this.handle = new AutoResetEventHandle(); + } + } + + //| + public void Reset() + { + AutoResetEventHandle.Reset(handle); + GC.KeepAlive(this); + } + + //| + public void Set() + { + AutoResetEventHandle.Set(handle); + GC.KeepAlive(this); + } + + //| + public void SetAll() + { + AutoResetEventHandle.SetAll(handle); + GC.KeepAlive(this); + } + + internal void SetNoGC() + { + AutoResetEventHandle.SetNoGC(handle); + GC.KeepAlive(this); + } + + protected override SyncHandle Handle{ + get { + return handle; + } + } + + //| + public override bool WaitOne(TimeSpan timeout) + { + bool b = SyncHandle.WaitOne(handle, timeout); + GC.KeepAlive(this); + return b; + } + + //| + public override bool WaitOne(SchedulerTime stop) + { + bool b = SyncHandle.WaitOne(handle, stop); + GC.KeepAlive(this); + return b; + } + + //| + public override bool WaitOne() + { + bool b = SyncHandle.WaitOne(handle); + GC.KeepAlive(this); + return b; + } + + internal bool WaitOneNoGC() + { + bool b = SyncHandle.WaitOneNoGC(handle); + GC.KeepAlive(this); + return b; + } + + //| + protected override void Dispose(bool explicitDisposing) + { + if (handle.id != 0) { + AutoResetEventHandle.Dispose(handle); + handle = new AutoResetEventHandle(); + } + } + } +} diff --git a/base/Applications/Runtime/System/Threading/ManualResetEvent.cs b/base/Applications/Runtime/System/Threading/ManualResetEvent.cs new file mode 100644 index 0000000..3452d2c --- /dev/null +++ b/base/Applications/Runtime/System/Threading/ManualResetEvent.cs @@ -0,0 +1,95 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +namespace System.Threading { + + using System; + using System.Runtime.CompilerServices; + using Microsoft.Singularity; + using Microsoft.Singularity.V1.Threads; + using Microsoft.Singularity.V1.Services; + + //| + [CLSCompliant(false)] + public sealed class ManualResetEvent : WaitHandle + { + private ManualResetEventHandle handle; + + //| + public ManualResetEvent(bool initialState) + { + ManualResetEventHandle handleOnStack; + if (!ManualResetEventHandle.Create(initialState, out handleOnStack)) { + throw new HandleCreateException(); + } + handle = handleOnStack; + } + + /// + /// Finalizer is responsible for freeing handle that keeps corresponding + /// kernel object live. + /// + ~ManualResetEvent() { + if (this.handle.id != 0) { + ManualResetEventHandle.Dispose(this.handle); + this.handle = new ManualResetEventHandle(); + } + } + + //| + public void Reset() + { + ManualResetEventHandle.Reset(handle); + GC.KeepAlive(this); + } + + //| + public bool Set() + { + bool b = ManualResetEventHandle.Set(handle); + GC.KeepAlive(this); + return b; + } + + protected override SyncHandle Handle{ + get { + return handle; + } + } + + //| + public override bool WaitOne(TimeSpan timeout) + { + bool b = SyncHandle.WaitOne(handle, timeout); + GC.KeepAlive(this); + return b; + } + + //| + public override bool WaitOne(SchedulerTime stop) + { + bool b = SyncHandle.WaitOne(handle, stop); + GC.KeepAlive(this); + return b; + } + + //| + public override bool WaitOne() + { + bool b = SyncHandle.WaitOne(handle); + GC.KeepAlive(this); + return b; + } + + //| + protected override void Dispose(bool explicitDisposing) + { + if (handle.id != 0) { + ManualResetEventHandle.Dispose(handle); + handle = new ManualResetEventHandle(); + } + } + } +} diff --git a/base/Applications/Runtime/System/Threading/Mutex.cs b/base/Applications/Runtime/System/Threading/Mutex.cs new file mode 100644 index 0000000..b2bdc31 --- /dev/null +++ b/base/Applications/Runtime/System/Threading/Mutex.cs @@ -0,0 +1,117 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +namespace System.Threading +{ + using System; + using System.Threading; + using System.Runtime.CompilerServices; + using Microsoft.Singularity; + using Microsoft.Singularity.V1.Threads; + using Microsoft.Singularity.V1.Services; + + //| + [CLSCompliant(false)] + public sealed class Mutex : WaitHandle + { + private MutexHandle handle; + + //| + public Mutex(bool initiallyOwned) + { + MutexHandle handleOnStack; + if (!MutexHandle.Create(initiallyOwned, out handleOnStack)) { + throw new HandleCreateException(); + } + handle = handleOnStack; + } + + //| + public Mutex() + { + MutexHandle handleOnStack; + if (!MutexHandle.Create(false, out handleOnStack)) { + throw new HandleCreateException(); + } + handle = handleOnStack; + } + + /// + /// Finalizer is responsible for freeing handle that keeps corresponding + /// kernel AutoResetEvent object live. + /// + ~Mutex() { + if (this.handle.id != 0) { + MutexHandle.Dispose(this.handle); + this.handle = new MutexHandle(); + } + } + + public bool AcquireMutex() + { + return WaitOne(); + } + + public bool AcquireMutex(SchedulerTime stop) + { + return WaitOne(stop); + } + + + //| + public void ReleaseMutex() + { + MutexHandle.Release(handle); + GC.KeepAlive(this); + } + + // Called by monitor to see if its lock is held by the current thread. + internal bool IsOwnedByCurrentThread() + { + bool b = MutexHandle.IsOwnedByCurrentThread(handle); + GC.KeepAlive(this); + return b; + } + + protected override SyncHandle Handle{ + get { + return handle; + } + } + + //| + public override bool WaitOne(TimeSpan timeout) + { + bool b = SyncHandle.WaitOne(handle, timeout); + GC.KeepAlive(this); + return b; + } + + //| + public override bool WaitOne(SchedulerTime stop) + { + bool b = SyncHandle.WaitOne(handle, stop); + GC.KeepAlive(this); + return b; + } + + //| + public override bool WaitOne() + { + bool b = SyncHandle.WaitOne(handle); + GC.KeepAlive(this); + return b; + } + + //| + protected override void Dispose(bool explicitDisposing) + { + if (handle.id != 0) { + MutexHandle.Dispose(handle); + handle = new MutexHandle(); + } + } + } +} diff --git a/base/Applications/Runtime/System/Threading/Thread.cs b/base/Applications/Runtime/System/Threading/Thread.cs new file mode 100644 index 0000000..976233f --- /dev/null +++ b/base/Applications/Runtime/System/Threading/Thread.cs @@ -0,0 +1,1165 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== + +// #define DEBUG_SWITCH + +namespace System.Threading +{ + using System.Threading; + using System.Runtime.InteropServices; + using System; + using System.Diagnostics; + using System.GCs; + using System.Globalization; + using System.Collections; + using System.Runtime.CompilerServices; + + using Microsoft.Bartok.Runtime; + + using Microsoft.Singularity; + using Microsoft.Singularity.Channels; + using Microsoft.Singularity.X86; + using Microsoft.Singularity.V1.Services; + using Microsoft.Singularity.V1.Threads; + + //| + [CCtorIsRunDuringStartup] + [StructLayout(LayoutKind.Sequential)] + [CLSCompliant(false)] + [RequiredByBartok] + public sealed class Thread + { + // Singularity specific fields + // Need CPU context + // Need stack + + // Bartok specific fields + [RequiredByBartok] // Thread-specific alloc heap + internal SegregatedFreeList segregatedFreeList; + [RequiredByBartok] // Thread-specific bump allocator + internal BumpAllocator bumpAllocator; + + internal AutoResetEvent processGcEvent; + + private AutoResetEvent autoEvent; + private ManualResetEvent joinEvent; + + internal Thread blockingCctorThread; + + // Singularity specific fields + [AccessedByRuntime("referenced from halforgc.asm")] + internal unsafe ThreadContext * context; + internal ThreadHandle threadHandle; + + // Most recently thrown exception object that the thread + // did not catch at all (i.e. that propagated to the bottom + // of the stack or to a kernel/process boundary without + // encountering an appropriate catch clause). + private Exception lastUncaughtException; + + private bool ignoredByJoinAll; // for "service" threads + + private Object m_ExceptionStateInfo; // Exception info latched to the thread on a thread abort + + // Bartok specific fields + internal Thread nextThread; // Link for linked lists of threads + + // This array is of length 1 and contains a queue item for this + // thread. It allows WaitOne and the scheduler to add this thread + // to their queues without allocating memory. + internal ThreadQueueItem[] singleQueueItem; + + // MultiUseWord (object header) fields. + internal UIntPtr externalMultiUseObjAllocListHead; + internal UIntPtr externalMultiUseObjAllocListTail; + + // Bartok specific fields + internal int threadIndex; + private ThreadStart threadStart; + private ThreadState threadState; + internal int waitingCriticalSectionDepth; + internal Object waitingObject; // Not used, but useful for debugging + + [RequiredByBartok] + internal TryAllManager tryAllManager; + + private static bool closing; + private static long totalArrayAllocations; + private static long totalArrayBytesAllocated; + private static long totalBytes; + private static long totalStructBytesAllocated; + + internal static Thread[] threadTable; + private static SpinLock threadTableLock; + + private static LocalDataStore localDataStore; + + internal static Thread initialThread; + + // This is used by the Bartok backend. When Bartok tries to generate + // callback stub for delegate, it checks to see if it is + // ThreadProc, if it is not, Bartok adds leaveGCSafeState and + // enterGCSafeState around the delegate call. + [RequiredByBartok] + private unsafe delegate uint ThreadProc(void *param); + + /*========================================================================= + ** This manager is responsible for storing the global data that is + ** shared amongst all the thread local stores. + =========================================================================*/ + static private LocalDataStoreMgr m_LocalDataStoreMgr; + + internal const int maxThreads = 1024; // Must be power of 2 >= 64 + private static int threadIndexGenerator; + + /*========================================================================= + ** Creates a new Thread object which will begin execution at + ** start.ThreadStart on a new thread when the Start method is called. + ** + ** Exceptions: ArgumentNullException if start == null. + =========================================================================*/ + //| + public unsafe Thread(ThreadStart start) + { + Tracing.Log(Tracing.Audit, "Application Thread()"); + + if (start == null) { + throw new ArgumentNullException("start"); + } + + threadIndex = -1; + threadState = ThreadState.Unstarted; + threadStart = start; + + // Create the event for the thread to wait upon + autoEvent = new AutoResetEvent(false); + joinEvent = new ManualResetEvent(false); + processGcEvent = new AutoResetEvent(false); + singleQueueItem = new ThreadQueueItem [1] { new ThreadQueueItem(this) }; + + // Find a usable entry in the thread table + bool disabled = Processor.DisableInterrupts(); + Thread.threadTableLock.Acquire(CurrentThread); + try { + for (int i = 0; i < threadTable.Length; i++) { + int index = (threadIndexGenerator + i) % threadTable.Length; + if (threadTable[index] == null) { + threadTable[index] = this; + this.threadIndex = index; + threadIndexGenerator = index + 1; + // NB: We call this once, afterwards the GC visitor calls it. + break; + } + } + } finally { + Thread.threadTableLock.Release(CurrentThread); + Processor.RestoreInterrupts(disabled); + } + + VTable.Assert(threadIndex >= 0, "Out of thread slots!"); + + //MemoryBarrier(); + + // Must check closing after being insert into table to avoid race condition. + if (closing) { + threadState = ThreadState.Stopped; + joinEvent.Set(); + Tracing.Log(Tracing.Warning, "Aborting: Runtime closing."); + return; + } + + ThreadHandle handleOnStack; + UIntPtr threadContext; + if (!ThreadHandle.Create(threadIndex, + new ContainerHandle(), + out handleOnStack, + out threadContext)) { + Tracing.Log(Tracing.Warning, "Aborting: ThreadHandle.Create failed."); + threadState = ThreadState.Stopped; + joinEvent.Set(); + return; + } + this.threadHandle = handleOnStack; + this.context = (ThreadContext *) threadContext; + this.context->threadIndex = unchecked((ushort) threadIndex); + this.context->UpdateAfterGC(this); + } + + + + /// + /// Finalizer is responsible for freeing handle that keeps corresponding + /// kernel object live. + /// + ~Thread() { + if (this.threadHandle.id != 0) { + ThreadHandle.Dispose(this.threadHandle); + this.threadHandle = new ThreadHandle(); + } + } + + /*========================================================================= + ** Spawns off a new thread which will begin executing at the ThreadStart + ** method on the IThreadable interface passed in the constructor. Once the + ** thread is dead, it cannot be restarted with another call to Start. + ** + ** Exceptions: ThreadStateException if the thread has already been started. + =========================================================================*/ + //| + public void Start() + { + lock ((Object) this) { + if (closing) { + throw new ThreadStateException("Cannot start thread when closing"); + } + + ThreadState oldState = threadState; + if (oldState != ThreadState.Unstarted) { + throw new ThreadStateException("Cannot start thread in state "+oldState); + } + + threadState = ThreadState.Running; + + // Tell the GC that we have created the thread + GC.NewThreadNotification(this, false); + + ThreadHandle.Start(threadHandle); + GC.KeepAlive(this); + } + } + + // HalInitContext sets ThreadStub as the first process code to be + // executed in a new thread context. + [AccessedByRuntime("referenced from hal.cpp")] + private static unsafe void ThreadStub(int threadIndex) + { + Transitions.ThreadStart(); + GC.ThreadStartNotification(threadIndex); + Thread currentThread = threadTable[threadIndex]; + if (AddThread(threadIndex)) { + Tracing.Log(Tracing.Audit, "ThreadStub(atid={0}) Entered", + (UIntPtr)unchecked((uint)threadIndex)); + + ThreadStart startFun = currentThread.threadStart; + + try { + startFun(); + } catch (Exception e) { + DebugStub.WriteLine("Thread {0} failed with exception {1}\n", + __arglist(threadIndex, e)); + currentThread.lastUncaughtException = e; + VTable.Assert(e == null, "Thread "+threadIndex+ + " failed with exception "+e); + } + Tracing.Log(Tracing.Audit, "ThreadStub(atid={0}) Exiting", + (UIntPtr)unchecked((uint)threadIndex)); + } + + currentThread.joinEvent.Set(); + RemoveThread(threadIndex); + GC.DeadThreadNotification(currentThread); + + bool disabled = Processor.DisableInterrupts(); + // 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.RestoreInterrupts(disabled); + } + } + + /*==================================================================== + * Support for service threads. Service threads should not count + * towards keeping a process alive. When all non-service threads + * have terminated, the service threads are asked to stop themselves + * so the process can terminate gracefully. + *===================================================================*/ + + // The number of non-service threads running in the process + private static int threadCount; + private static Object notificationTableObject; + private static Object[] notificationTable; + + public delegate void StopServiceNotice(); + + public void MakeServiceThread(StopServiceNotice notification) + { + Tracing.Log(Tracing.Audit, "MakeServiceThread {0}", + (UIntPtr) threadIndex); + if (this != Thread.CurrentThread) { + throw new Exception("Only the thread itself may call MakeServiceThread"); + } + if (notificationTable == null) { + int tableSize = threadTable.Length; + Interlocked.CompareExchange(ref notificationTableObject, + new Object[tableSize], + null); + notificationTable = (Object[]) notificationTableObject; + } + Tracing.Log(Tracing.Audit, " previous notification: {0:x8}", + Magic.addressOf(notificationTable[threadIndex])); + // BUGBUG: Should have been Interlocked.Exchange, but that + // doesn't work due to a Bartok codegen bug. + Object oldNotification = notificationTable[threadIndex]; + while (Interlocked.CompareExchange(ref notificationTable[threadIndex], notification, oldNotification) != oldNotification) { + oldNotification = notificationTable[threadIndex]; + } + if (oldNotification == null) { + // We made the thread a service thread for the first time. + if (Interlocked.Decrement(ref threadCount) == 0) { + NotifyServiceThreads(); + } + } + VTable.Assert(threadCount >= 0); + } + + public void ClearServiceThread(Thread thread) + { + Tracing.Log(Tracing.Audit, "ClearServiceThread"); + if (this != Thread.CurrentThread) { + throw new Exception("Only the thread itself may call ClearServiceThread"); + } + if (notificationTable == null) { + return; + } + if (Interlocked.Exchange(ref notificationTable[threadIndex], + null) != null) { + // We cleared the notification + Interlocked.Increment(ref threadCount); + } + VTable.Assert(threadCount >= 0); + } + + private static bool AddThread(int index) + { + Tracing.Log(Tracing.Audit, "AddThread {0} ({1})", + (UIntPtr) index, (UIntPtr) threadCount); + VTable.Assert(threadCount >= 0); + if (Interlocked.Increment(ref threadCount) == 1 && + notificationTable != null) { + // The thread was started after we started sending out + // notifications, so indicate that the thread should not + // really be started + return false; + } else { + return true; + } + } + + internal static void RemoveThread(int index) + { + Tracing.Log(Tracing.Audit, "RemoveThread {0} ({1})", + (UIntPtr) index, (UIntPtr) threadCount); + if (Interlocked.Decrement(ref threadCount) == 0) { + NotifyServiceThreads(); + } + VTable.Assert(threadCount >= 0); + } + + private static void NotifyServiceThreads() + { + Tracing.Log(Tracing.Audit, "NotifyServiceThreads"); + if (notificationTable == null) { + return; + } + for (int i = 0; i < notificationTable.Length; i++) { + if (notificationTable[i] != null) { + Tracing.Log(Tracing.Audit, " Notifying thread {0}", + (UIntPtr) i); + ((StopServiceNotice)notificationTable[i])(); + } + } + } + + + /*========================================================================= + ** Returns true if the thread has been started and is not dead. + =========================================================================*/ + //| + public bool IsAlive { + [NoHeapAllocation] + get { return (threadState != ThreadState.Unstarted && + threadState != ThreadState.Stopped); } + } + + + /*========================================================================= + ** Waits for the thread to die. + ** + ** Exceptions: ThreadStateException if the thread has not been started yet. + =========================================================================*/ + //| + public void Join() + { + Join(SchedulerTime.MaxValue); + } + + /*========================================================================= + ** Waits for the thread to die or for timeout milliseconds to elapse. + ** Returns true if the thread died, or false if the wait timed out. + ** + ** Exceptions: ArgumentException if timeout < 0. + ** ThreadStateException if the thread has not been started yet. + =========================================================================*/ + //| + public bool Join(TimeSpan timeout) + { + if (threadState == ThreadState.Unstarted) { + throw new ThreadStateException(); + } + return joinEvent.WaitOne(timeout); + } + + public bool Join(SchedulerTime timeout) + { + if (threadState == ThreadState.Unstarted) { + throw new ThreadStateException(); + } + return joinEvent.WaitOne(timeout); + } + + internal static bool JoinAll() + { + // To avoid races, join all does the following: + // 1) Wait for all known peer threads to terminate. + // 2) Set the closing flag to disallow creating of new threads. + // 3) Wait for any threads that have started in the mean time. + + for (uint iteration = 0; iteration < 2; iteration++) { + for (int i = 0; i < threadTable.Length; i++) { + Thread thread = null; + + bool disabled = Processor.DisableInterrupts(); + Thread.threadTableLock.Acquire(CurrentThread); + try { + thread = threadTable[i]; + } + finally { + Thread.threadTableLock.Release(CurrentThread); + Processor.RestoreInterrupts(disabled); + } + + if (thread != null && + thread != CurrentThread && + thread.threadState != ThreadState.Unstarted && + !thread.ignoredByJoinAll) { + thread.Join(); + } + } + closing = true; + } + return true; + } + + /*========================================================================= + ** Suspends the current thread for timeout milliseconds. If timeout == 0, + ** forces the thread to give up the remainder of its timeslice. + ** + ** Exceptions: ArgumentException if timeout < 0. + =========================================================================*/ + + public static void Sleep(int milliseconds) + { + Sleep(TimeSpan.FromMilliseconds(milliseconds)); + } + + //| + public static void Sleep(TimeSpan timeout) + { + ThreadHandle.Sleep(timeout); + } + + /* wait for a length of time proportional to 'iterations'. Each iteration is should + only take a few machine instructions. Calling this API is preferable to coding + an explicit busy loop because the hardware can be informed that it is busy waiting. */ + + //| + [NoHeapAllocation] + public static void SpinWait(int iterations) + { + for (int i = iterations; i > 0; i--) { + // Ensure that the optimizer doesn't remove this + NativeNoOp(); + } + } + + [Intrinsic] + [NoHeapAllocation] + public static extern void NativeNoOp(); + + internal static int GetCurrentProcessIndex() { + return ProcessService.GetCurrentProcessId(); + } + + internal bool WaitForMonitor(SchedulerTime timeOut) + { + return autoEvent.WaitOne(timeOut); + } + + internal bool WaitForEvent(SchedulerTime timeOut) + { + DebugStub.Break(); + return autoEvent.WaitOne(timeOut); + } + + internal bool WaitForEvent(TimeSpan timeout) + { + DebugStub.Break(); + return autoEvent.WaitOne(timeout); + } + + internal static unsafe bool WaitForGCEvent(int currentThreadIndex) + { + AutoResetEvent are = + threadTable[currentThreadIndex].processGcEvent; + // BUGBUG: The restoration of the gcState should be taken + // care of by the compiler. + return are.WaitOneNoGC(); + } + + internal void SignalMonitor() + { + autoEvent.Set(); + } + + internal void SignalEvent() + { + DebugStub.Break(); + autoEvent.Set(); + } + + [Inline] + internal static void SignalGCEvent(int currentThreadIndex, + int threadIndex) + { + SignalGCEvent(threadIndex); + } + + internal static unsafe void SignalGCEvent(int threadIndex) + { + Thread thread = threadTable[threadIndex]; + if (thread == null) { + return; + } + thread.processGcEvent.SetNoGC(); + } + + //| + public static Thread CurrentThread + { + [NoHeapAllocation] + [NoStackLinkCheck] + get { + return Processor.GetCurrentThread(); + } + } + + internal ThreadHandle Handle + { + [NoHeapAllocation] + get { return threadHandle; } + } + + [NoStackLinkCheck] + [RequiredByBartok] + [NoHeapAllocation] + private static Thread GetCurrentThreadNative() + { + return Processor.GetCurrentThread(); + } + + [NoStackLinkCheck] + [RequiredByBartok] + [NoHeapAllocation] + internal static int GetCurrentThreadIndex() + { + return Processor.GetCurrentThread().threadIndex; + } + + /*========================================================================= + ** Return the thread state as a consistent set of bits. This is more + ** general then IsAlive or IsBackground. + =========================================================================*/ + //| + public ThreadState ThreadState + { + [NoHeapAllocation] + get { return threadState; } + } + + [NoHeapAllocation] + public int GetThreadId() + { + return threadIndex; + } + + /*========================================================================= + ** Allocates an un-named data slot. The slot is allocated on ALL the + ** threads. + =========================================================================*/ + //| + public static LocalDataStoreSlot AllocateDataSlot() + { + return m_LocalDataStoreMgr.AllocateDataSlot(); + } + + /*========================================================================= + ** Allocates a named data slot. The slot is allocated on ALL the + ** threads. Named data slots are "public" and can be manipulated by + ** anyone. + =========================================================================*/ + //| + public static LocalDataStoreSlot AllocateNamedDataSlot(String name) + { + return m_LocalDataStoreMgr.AllocateNamedDataSlot(name); + } + + /*========================================================================= + ** Looks up a named data slot. If the name has not been used, a new slot is + ** allocated. Named data slots are "public" and can be manipulated by + ** anyone. + =========================================================================*/ + //| + public static LocalDataStoreSlot GetNamedDataSlot(String name) + { + return m_LocalDataStoreMgr.GetNamedDataSlot(name); + } + + /*========================================================================= + ** Frees a named data slot. The slot is allocated on ALL the + ** threads. Named data slots are "public" and can be manipulated by + ** anyone. + =========================================================================*/ + //| + public static void FreeNamedDataSlot(String name) + { + m_LocalDataStoreMgr.FreeNamedDataSlot(name); + } + + /*========================================================================= + ** Retrieves the value from the specified slot on the current thread. + =========================================================================*/ + //| + public static Object GetData(LocalDataStoreSlot slot) + { + m_LocalDataStoreMgr.ValidateSlot(slot); + + if (localDataStore != null) { + return localDataStore.GetData(slot); + } + return null; + } + + /*========================================================================= + ** Sets the data in the specified slot on the currently running thread. + =========================================================================*/ + //| + public static void SetData(LocalDataStoreSlot slot, Object data) + { + // Create new DLS if one hasn't been created for this thread. + if (localDataStore == null) { + localDataStore = m_LocalDataStoreMgr.CreateLocalDataStore(); + } + localDataStore.SetData(slot, data); + } + + /*=============================================================*/ + + internal Object ExceptionState + { + [NoHeapAllocation] + get { return m_ExceptionStateInfo;} + [NoHeapAllocation] + set { m_ExceptionStateInfo = value;} + } + + // + // This is just designed to prevent compiler warnings. + // This field is used from native, but we need to prevent the compiler warnings. + // +#if _DEBUG + private void DontTouchThis() + { + threadStart = null; + m_Priority = 0; + } +#endif + /*========================================================================= + ** Volatile Read & Write and MemoryBarrier methods. + ** Provides the ability to read and write values ensuring that the values + ** are read/written each time they are accessed. + =========================================================================*/ + + //| + [Intrinsic] + [NoHeapAllocation] + public static extern byte VolatileRead(ref byte address); + + //| + [Intrinsic] + [NoHeapAllocation] + public static extern short VolatileRead(ref short address); + + //| + [Intrinsic] + [NoHeapAllocation] + public static extern int VolatileRead(ref int address); + + //| + [Intrinsic] + [NoHeapAllocation] + public static extern long VolatileRead(ref long address); + + //| + [CLSCompliant(false)] + [Intrinsic] + [NoHeapAllocation] + public static extern sbyte VolatileRead(ref sbyte address); + + //| + [CLSCompliant(false)] + [Intrinsic] + [NoHeapAllocation] + public static extern ushort VolatileRead(ref ushort address); + + //| + [CLSCompliant(false)] + [Intrinsic] + [NoHeapAllocation] + public static extern uint VolatileRead(ref uint address); + + //| + [Intrinsic] + [NoHeapAllocation] + public static extern IntPtr VolatileRead(ref IntPtr address); + + //| + [CLSCompliant(false)] + [Intrinsic] + [NoHeapAllocation] + public static extern UIntPtr VolatileRead(ref UIntPtr address); + + //| + [CLSCompliant(false)] + [Intrinsic] + [NoHeapAllocation] + public static extern ulong VolatileRead(ref ulong address); + + //| + [Intrinsic] + [NoHeapAllocation] + public static extern float VolatileRead(ref float address); + + //| + [Intrinsic] + [NoHeapAllocation] + public static extern double VolatileRead(ref double address); + + //| + [Intrinsic] + [NoHeapAllocation] + public static extern Object VolatileRead(ref Object address); + + //| + [Intrinsic] + [NoHeapAllocation] + public static extern void VolatileWrite(ref byte address, byte value); + + //| + [Intrinsic] + [NoHeapAllocation] + public static extern void VolatileWrite(ref short address, short value); + + //| + [Intrinsic] + [NoHeapAllocation] + public static extern void VolatileWrite(ref int address, int value); + + //| + [Intrinsic] + [NoHeapAllocation] + public static extern void VolatileWrite(ref long address, long value); + + //| + [CLSCompliant(false)] + [Intrinsic] + [NoHeapAllocation] + public static extern void VolatileWrite(ref sbyte address, sbyte value); + + //| + [CLSCompliant(false)] + [Intrinsic] + [NoHeapAllocation] + public static extern void VolatileWrite(ref ushort address, ushort value); + + //| + [CLSCompliant(false)] + [Intrinsic] + [NoHeapAllocation] + public static extern void VolatileWrite(ref uint address, uint value); + + //| + [Intrinsic] + [NoHeapAllocation] + public static extern void VolatileWrite(ref IntPtr address, IntPtr value); + + //| + [CLSCompliant(false)] + [Intrinsic] + [NoHeapAllocation] + public static extern void VolatileWrite(ref UIntPtr address, UIntPtr value); + + //| + [CLSCompliant(false)] + [Intrinsic] + [NoHeapAllocation] + public static extern void VolatileWrite(ref ulong address, ulong value); + + //| + [Intrinsic] + [NoHeapAllocation] + public static extern void VolatileWrite(ref float address, float value); + + //| + [Intrinsic] + [NoHeapAllocation] + public static extern void VolatileWrite(ref double address, double value); + + //| + [Intrinsic] + [NoHeapAllocation] + public static extern void VolatileWrite(ref Object address, Object value); + + //| + [Intrinsic] + [NoHeapAllocation] + public static extern void MemoryBarrier(); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + [GCAnnotation(GCOption.NOGC)] + [StackBound(12)] + [NoHeapAllocation] + private static unsafe extern Thread HalGetThread(); + + [NoHeapAllocation] + public static void Yield() + { + ThreadHandle.Yield(); + } + + [NoHeapAllocation] + public bool IsStopped() + { + return (threadState == ThreadState.Stopped); + } + + [PreInitRefCounts] + static unsafe Thread() + { + threadIndexGenerator = 1; + + // Enable Thread.CurrentThread as soon as we can! + initialThread = Magic.toThread(BootstrapMemory.Allocate(typeof(Thread))); + initialThread.threadState = ThreadState.Running; + initialThread.threadIndex = 0; + + // Allocate tables for thread management + threadTable = (Thread[]) + BootstrapMemory.Allocate(typeof(Thread[]), maxThreads); + + // Initialize the thread and event tables + threadTable[initialThread.threadIndex] = initialThread; + initialThread.context = Processor.GetCurrentThreadContext(); + initialThread.context->threadIndex = + unchecked((ushort) initialThread.threadIndex); + initialThread.context->UpdateAfterGC(initialThread); + + Tracing.Log(Tracing.Debug, "InitialThread={0:x8}", + Magic.addressOf(initialThread)); + } + + internal static unsafe void FinishInitializeThread() + { + int threadIndex = initialThread.threadIndex; + // Get the GC ready for initialThread + Transitions.RuntimeInitialized(); + Transitions.ThreadStart(); + initialThread.processGcEvent = new AutoResetEvent(false); + initialThread.autoEvent = new AutoResetEvent(false); + initialThread.joinEvent = new ManualResetEvent(false); + initialThread.singleQueueItem = + new ThreadQueueItem [1] { new ThreadQueueItem(initialThread) }; + // Use CurrentThread to find our initial handle: + VTable.Assert(initialThread == CurrentThread); + initialThread.threadHandle = ThreadHandle.CurrentThread(); + // Instantiate the static variable that needs to be initialized + m_LocalDataStoreMgr = new LocalDataStoreMgr(); + AddThread(threadIndex); + } + + public TimeSpan ExecutionTime + { + get { + TimeSpan t = ThreadHandle.GetExecutionTime(threadHandle); + GC.KeepAlive(this); + return t; + } + } + + internal static + void VisitBootstrapData(GCs.NonNullReferenceVisitor visitor) + { + visitor.VisitReferenceFields(Thread.initialThread); + visitor.VisitReferenceFields(Thread.threadTable); + } + + internal static unsafe void UpdateAfterGC() + { + // Update all the thread pointers in the thread contexts + for (int i = 0; i < threadTable.Length; i++) { + Thread thread = threadTable[i]; + if (thread != null) { + thread.context->UpdateAfterGC(thread); + } + } + } + + // Cache for ABI synchronization + private SyncHandle[] syncHandles; + internal SyncHandle[] GetSyncHandles(int length) + { + if (syncHandles == null || + syncHandles.Length < length) { + + syncHandles = new SyncHandle[length + 8]; + } + return syncHandles; + } + + + // Caches for Select synchronization + // We use stacks, because selectable abstractions might + // internally implement HeadMatches using select receive + // which is called from within an outer select. + // NOTE however that internal selects should never block + // (use timeout) + private Stack selectBoolsStack; + private Stack selectObjectsStack; + private Stack selectSyncHandlesStack; + + public bool[] PopSelectBools(int size) + { + if (selectBoolsStack == null) { + selectBoolsStack = new Stack(); + } + if (selectBoolsStack.Count == 0) { + return new bool [size]; + } + bool[] selectBools = (bool[])selectBoolsStack.Pop(); + if (selectBools.Length < size) { + return new bool [size]; + } + return selectBools; + } + + public void PushSelectBools(bool[] cache) { + selectBoolsStack.Push(cache); + } + + public ISelectable[] PopSelectObjects(int size) + { + if (selectObjectsStack == null) { + selectObjectsStack = new Stack(); + } + if (selectObjectsStack.Count == 0) { + return new ISelectable [size]; + } + ISelectable[] selectObjects = (ISelectable[])selectObjectsStack.Pop(); + if (selectObjects.Length < size) { + return new ISelectable [size]; + } + return selectObjects; + } + public void PushSelectObjects(ISelectable[] cache) { + selectObjectsStack.Push(cache); + } + + public SyncHandle[] PopSelectSyncHandles(int size) + { + if (selectSyncHandlesStack == null) { + selectSyncHandlesStack = new Stack(); + } + if (selectSyncHandlesStack.Count == 0) { + return new SyncHandle [size]; + } + SyncHandle[] selectSyncHandles = (SyncHandle[])selectSyncHandlesStack.Pop(); + if (selectSyncHandles.Length < size) { + return new SyncHandle [size]; + } + return selectSyncHandles; + } + public void PushSelectSyncHandles(SyncHandle[] cache) { + selectSyncHandlesStack.Push(cache); + } + + + + // Given a frame's range in memory (its esp/ebp), check whether + // the frame contains the top transition record. If so, + // prepare for making a transition from process mode back + // to kernel mode. + [AccessedByRuntime("referenced from halasm.asm")] + [NoStackLinkCheck] // We don't want to throw an exception here; + // Therefore, we cannot risk allocating stack segments, + // and we should only call other NoStackLinkCheck functions (XXX). + internal static unsafe UIntPtr CheckKernelProcessBoundary(UIntPtr esp, UIntPtr ebp, Exception exn) + { + ThreadContext *context = Processor.GetCurrentThreadContext(); + CallStack.TransitionRecord *topMarker = context->kernelMarkers; + CallStack.TransitionRecord *secondMarker = context->stackMarkers; + UIntPtr topMarkerPtr = (UIntPtr) topMarker; + // If the top marker is in our frame, we've reached a boundary: + if (esp < topMarkerPtr && topMarkerPtr <= ebp) { + context->uncaughtFlag = true; + Thread.CurrentThread.lastUncaughtException = exn; + Processor.GetCurrentThreadContext()->SetKernelMode(); + return 1; + } + else { + return 0; + } + } + + // Most recently thrown exception object that the thread + // did not catch at all (i.e. that propagated to the bottom + // of the stack without encountering an appropriate catch clause). + public Exception LastUncaughtException + { + [NoHeapAllocation] + get { + return lastUncaughtException; + } + } + + // Tell JoinAll not to block waiting for this thread to exit. + // Some special threads (e.g. the finalizer thread) need to run + // only as long as there are other threads running, and should + // not be considered by JoinAll. + [NoHeapAllocation] + internal void SetIgnoredByJoinAll() + { + ignoredByJoinAll = true; + } + } + + // This class is designed to support queues whose enqueue, + // dequeue, and remove operations do not allocate memory. + // This feature is useful when writing code that needs to + // do such operations with interrupts off. + [CLSCompliant(false)] + public class ThreadQueue + { + private ThreadQueueItem head = null; + private ThreadQueueItem tail = null; + + [NoHeapAllocation] + public void Enqueue(ThreadQueueItem item) + { + VTable.Assert(item.Next == null); + VTable.Assert(item.Prev == null); + VTable.Assert(item.Queue == null); + + item.Queue = this; + item.Prev = tail; + + if (tail != null) { + VTable.Assert(tail.Next == null); + tail.Next = item; + } else { + VTable.Assert(head == null); + head = item; + } + + tail = item; + } + + [NoHeapAllocation] + public ThreadQueueItem Dequeue() + { + ThreadQueueItem item = head; + + if (item != null) { + Remove(item); + } + + return item; + } + + [NoHeapAllocation] + public void Remove(ThreadQueueItem item) + { + VTable.Assert(item.Queue == this); + + if (item.Next != null) { + item.Next.Prev = item.Prev; + } else { + VTable.Assert(item == tail); + tail = item.Prev; + } + + if (item.Prev != null) { + item.Prev.Next = item.Next; + } else { + VTable.Assert(item == head); + head = item.Next; + } + + item.Next = null; + item.Prev = null; + item.Queue = null; + } + + [NoHeapAllocation] + public bool IsEmpty() + { + return (head == null); + } + } + + [CLSCompliant(false)] + public class ThreadQueueItem + { + public readonly Thread Thread = null; + + public ThreadQueueItem Next = null; + public ThreadQueueItem Prev = null; + + public ThreadQueue Queue = null; + + public ThreadQueueItem(Thread thread) + { + Thread = thread; + } + + [NoHeapAllocation] + public void Remove() + { + if (Queue != null) { + Queue.Remove(this); + } + + VTable.Assert(Next == null); + VTable.Assert(Prev == null); + VTable.Assert(Queue == null); + } + } +} diff --git a/base/Applications/Runtime/System/Threading/Timeout.cs b/base/Applications/Runtime/System/Threading/Timeout.cs new file mode 100644 index 0000000..c670431 --- /dev/null +++ b/base/Applications/Runtime/System/Threading/Timeout.cs @@ -0,0 +1,25 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== + +namespace System.Threading { + using System.Threading; + using System; + // A constant used by methods that take a timeout (Object.Wait, Thread.Sleep + // etc) to indicate that no timeout should occur. + // + // @todo: this should become an enum. + //| + public sealed class Timeout + { + private Timeout() + { + } + + //| + public static readonly TimeSpan Infinite = TimeSpan.Infinite; + } + +} diff --git a/base/Applications/Runtime/System/Threading/WaitHandle.cs b/base/Applications/Runtime/System/Threading/WaitHandle.cs new file mode 100644 index 0000000..b2f1b06 --- /dev/null +++ b/base/Applications/Runtime/System/Threading/WaitHandle.cs @@ -0,0 +1,119 @@ +// ==++== +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// ==--== +/*============================================================================= +** +** Class: WaitHandle (this name is NOT definitive) +** +** +** Purpose: Class to represent all synchronization objects in the runtime (that allow multiple wait) +** +** Date: August, 1999 +** +=============================================================================*/ + +namespace System.Threading { + using System; + using System.Threading; + using System.Runtime.CompilerServices; + using System.Collections; + using Microsoft.Singularity; + using Microsoft.Singularity.V1.Threads; + using Microsoft.Singularity.V1.Services; + + //| + [CLSCompliant(false)] + public abstract class WaitHandle : IDisposable + { + //| + public const int WaitTimeout = -1; + + protected WaitHandle() + { + } + + protected abstract SyncHandle Handle{ + get; + } + + //| + public abstract bool WaitOne(TimeSpan timeout); + + //| + public abstract bool WaitOne(SchedulerTime stop); + + [Obsolete("Do not use DateTime for scheduling. It is meaningless. Use SchedulerTime")] + public bool WaitOne(DateTime stop) { + SchedulerTime st = SchedulerTime.MinValue + (stop - DateTime.BootTime); + return WaitOne(st); + } + + //| + public abstract bool WaitOne(); + + //| + public static unsafe int WaitAny(WaitHandle[] waitHandles, + TimeSpan timeout) + { + SyncHandle[] handles = Thread.CurrentThread.GetSyncHandles(waitHandles.Length); + for (int i = 0; i < waitHandles.Length; i++) { + handles[i] = waitHandles[i].Handle; + } + fixed (SyncHandle *array = &handles[0]) { + return SyncHandle.WaitAny(array, waitHandles.Length, timeout); + } + } + + //| + public static unsafe int WaitAny(WaitHandle[] waitHandles, + SchedulerTime stop) + { + SyncHandle[] handles = Thread.CurrentThread.GetSyncHandles(waitHandles.Length); + for (int i = 0; i < waitHandles.Length; i++) { + handles[i] = waitHandles[i].Handle; + } + fixed (SyncHandle *array = &handles[0]) { + return SyncHandle.WaitAny(array, waitHandles.Length, stop); + } + } + + //| + public static unsafe int WaitAny(WaitHandle[] waitHandles) + { + SyncHandle[] handles = Thread.CurrentThread.GetSyncHandles(waitHandles.Length); + for (int i = 0; i < waitHandles.Length; i++) { + handles[i] = waitHandles[i].Handle; + } + fixed (SyncHandle *array = &handles[0]) { + return SyncHandle.WaitAny(array, waitHandles.Length); + } + } + + //| + protected abstract void Dispose(bool explicitDisposing); + + //| + public virtual void Close() + { + Dispose(true); + GC.nativeSuppressFinalize(this); + } + + //| + /// + void IDisposable.Dispose() + { + Dispose(true); + GC.nativeSuppressFinalize(this); + } + + //| + ~WaitHandle() + { + Dispose(false); + } + + } +} diff --git a/base/Applications/Runtime/TestApp.csproj b/base/Applications/Runtime/TestApp.csproj new file mode 100644 index 0000000..812cb39 --- /dev/null +++ b/base/Applications/Runtime/TestApp.csproj @@ -0,0 +1,43 @@ + + + + + + + + testapp + Exe + $(APPRUNTIMEDIR) + C# + + + + + + true + + + + + + + + + + + + + + diff --git a/base/Applications/Runtime/testapp.cs b/base/Applications/Runtime/testapp.cs new file mode 100644 index 0000000..8486a53 --- /dev/null +++ b/base/Applications/Runtime/testapp.cs @@ -0,0 +1,34 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: testapp.cs +// +// Note: This file contains the main entry point for the C# +// portion of Singularity. +// +using Microsoft.Singularity; +using System; +using System.Runtime.CompilerServices; +using System.Threading; + +namespace Microsoft.Singularity +{ + public class Iltest + { + public static int Main(String[] args) + { + int i = 10; + long l = 100; + byte b = 1; + + DebugStub.Print("Hello from TestApp.cs\n"); + DebugStub.Print("byte: {0}, int: {1}, long: {2}\n", + __arglist(b, i, l)); + + return 999; + } + } +} diff --git a/base/Applications/SeattleTrafficProxy/SeattleTrafficProxy.csproj b/base/Applications/SeattleTrafficProxy/SeattleTrafficProxy.csproj new file mode 100644 index 0000000..bd0b639 --- /dev/null +++ b/base/Applications/SeattleTrafficProxy/SeattleTrafficProxy.csproj @@ -0,0 +1,39 @@ + + + + + + + Exe + SeattleTraffic + true + + + + + + + + + + + + + + + + + + + + + + diff --git a/base/Applications/SeattleTrafficProxy/SeattleTrafficProxy.sg b/base/Applications/SeattleTrafficProxy/SeattleTrafficProxy.sg new file mode 100644 index 0000000..9e7e376 --- /dev/null +++ b/base/Applications/SeattleTrafficProxy/SeattleTrafficProxy.sg @@ -0,0 +1,250 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: SeattleTrafficProxy.sg +// +// Note: A simple proxy module for the Seattle Traffic web service +// + +using System; +using System.Diagnostics; +using System.Text; +using System.Collections; +using Microsoft.SingSharp; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.SeattleTrafficProxy.Contracts; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Xml; +using System; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications +{ + [ConsoleCategory(HelpMessage="Mappoint proxy service", DefaultAction=true)] + internal class Parameters + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef nsRef; + + reflective internal Parameters(); + + internal int AppMain() { + return SeattleTrafficProxy.AppMain(this); + } + } + + public class SeattleTrafficProxy + { + internal static int AppMain(Parameters! config) + { + + DirectoryServiceContract.Imp ds = (config.nsRef).Acquire(); + if (ds == null) { + throw new Exception("Unable to acquire handle to the Directory Service root"); + } + ds.RecvSuccess(); + + + // Here is the channel we use to communicate with + // the NameServer + ServiceProviderContract.Imp! nsImp; + ServiceProviderContract.Exp! nsExp; + ServiceProviderContract.NewChannel(out nsImp, out nsExp); + + try + { + ds.SendRegister(Bitter.FromString2(SeattleTrafficProxyContract.ModuleName), nsImp); + + switch receive + { + case ds.AckRegister() : + // All is well. + break; + + case ds.NakRegister(ServiceProviderContract.Imp:Start rejectedEP, error) : + // All is very much not well; abort. + Console.WriteLine("Failed to register the SeattleTraffic proxy module as " + + SeattleTrafficProxyContract.ModuleName); + delete nsExp; + delete rejectedEP; + return -1; + + case ds.ChannelClosed(): + Console.WriteLine("ds channel closed"); + delete nsExp; + return -1; + } + } + finally + { + delete ds; + } + + // Here is the set of client channels we service + ESet epSet = new ESet(); + + while(true) + { + switch receive + { + // ------------------------------- Requests for new connections + + case nsExp.Connect(ServiceContract.Exp:Start! newEp) : + { + // We expect people top give us SeattleTrafficProxyContract.Exp instances + SeattleTrafficProxyContract.Exp newClient = newEp as SeattleTrafficProxyContract.Exp; + + if (newClient == null) + { + // Invalid contract type. Fail. + nsExp.SendNackConnect(newEp); + } + else + { + // Signal ready and start servicing this contract + nsExp.SendAckConnect(); + newClient.SendReady(); + epSet.Add(newClient); + } + } + break; + + // ------------------------------- Requests on existing connections + // + // Don't forget that we're selecting endpoints + // from the epSet endpoint-set. In each case that we + // receive a message from one of those endpoints, we + // need to remember to put the endpoint back into epSet + // if we want to keep listening to it. + // + case ep.GetTraffic() in epSet: + { + Console.WriteLine("SeattleTrafficProxy - received a GetTraffic request"); + TrafficInfo[]! in ExHeap trafficInfo = LookupTraffic(); + ep.SendTraffic(trafficInfo); + epSet.Add(ep); + } + break; + + case nsExp.ChannelClosed() && epSet.Empty() : + // The namespace channel is closed and we have no more client + // channels, so pack up and go home. + delete nsExp; + epSet.Dispose(); + return -1; + + case ep.ChannelClosed() in epSet : + // Dispose of channels when our clients close them + delete ep; + break; + } + } + return 0; + } + + // + // HACK: LookupTraffic - This should leverage the Bayesian prediction work + // done by Eric Horvitz to retrieve traffic bottleneck times. + // + private static TrafficInfo[]! in ExHeap LookupTraffic() + { + // HACK: Disable until ready. + /* + try + { + using(WebClient webclient = new WebClient()) + { + // Download traffic data + // TODO: Only download every five minutes. + webclient.DownloadFile(@"http://www.adapt.msresearch.us/smartphlow/Desktop/tip02.dat", "tip02.dat"); + } + // Parse data + byte [] rawTraffic = ParseTipFile("tip02.dat"); + + // Generate the results for the client. + // TODO: Add more value to the traffic response. + TrafficInfo[]! in ExHeap trafficInfo = BuildTrafficInfo(rawTraffic); + return trafficInfo; + } + catch (Exception ex) + { + } + */ + + TrafficInfo[]! in ExHeap trafficInfo = new[ExHeap] TrafficInfo[12]; + + // West side + + // 520 WB at Montlake + trafficInfo[0].minUntilFree = 6; + trafficInfo[0].latitude = 47.64574f; + trafficInfo[0].longitude = -122.30687f; + // 520 EB at Montlake + trafficInfo[1].minUntilFree = 30; + trafficInfo[1].latitude = 47.64314f; + trafficInfo[1].longitude = -122.30634f; + // 5 SB at Lake Union + trafficInfo[2].minUntilFree = 12; + trafficInfo[2].latitude = 47.63600f; + trafficInfo[2].longitude = -122.32949f; + // 5 NB at Lake Union + trafficInfo[3].minUntilFree = 27; + trafficInfo[3].latitude = 47.63519f; + trafficInfo[3].longitude = -122.32143f; + + // East side + + // 520 WB at bridge + trafficInfo[4].minUntilFree = 51; + trafficInfo[4].latitude = 47.64571f; + trafficInfo[4].longitude = -122.21226f; + // 520 EB at bridge + trafficInfo[5].minUntilFree = 0; + trafficInfo[5].latitude = 47.63983f; + trafficInfo[5].longitude = -122.20965f; + // 520 EB at Redmond + trafficInfo[6].minUntilFree = 22; + trafficInfo[6].latitude = 47.66538f; + trafficInfo[6].longitude = -122.11552f; + // 520 WB at Redmond + trafficInfo[7].minUntilFree = 0; + trafficInfo[7].latitude = 47.66986f; + trafficInfo[7].longitude = -122.13050f; + + // 405 N in Bellevue + trafficInfo[8].minUntilFree = 39; + trafficInfo[8].latitude = 47.60998f; + trafficInfo[8].longitude = -122.18467f; + // 405 S in Bellevue + trafficInfo[9].minUntilFree = 16; + trafficInfo[9].latitude = 47.61012f; + trafficInfo[9].longitude = -122.19992f; + // 405 N in Kirkland + trafficInfo[10].minUntilFree = 14; + trafficInfo[10].latitude = 47.66809f; + trafficInfo[10].longitude = -122.18236f; + // 405 S in Kirkland + trafficInfo[11].minUntilFree = 9; + trafficInfo[11].latitude = 47.66761f; + trafficInfo[11].longitude = -122.19861f; + + return trafficInfo; + } + } +} diff --git a/base/Applications/Security/CryptoBvt/CryptoBvt.cs b/base/Applications/Security/CryptoBvt/CryptoBvt.cs new file mode 100644 index 0000000..85bc78d --- /dev/null +++ b/base/Applications/Security/CryptoBvt/CryptoBvt.cs @@ -0,0 +1,47 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: CryptoBvt.cs +// +// + +using System; +using System.Collections.Generic; +using System.Text; + +namespace CryptoBvt +{ + class Program + { + static void Main(string[] args) + { + MD4Test.VerifyKnownDigests(); + DesTest.RunTests(); + } + } + + class Util + { + public const string HexDigits = "0123456789abcdef"; + + public static string! ByteArrayToString(byte[]! buffer, int index, int length) + { + StringBuilder sb = new StringBuilder(length * 2); + for (int i = 0; i < length; i++) + { + byte b = buffer[index + i]; + sb.Append(HexDigits[b >> 4]); + sb.Append(HexDigits[b & 0xf]); + } + return sb.ToString(); + } + + public static string! ByteArrayToStringHex(byte[]! buffer) + { + return ByteArrayToString(buffer, 0, buffer.Length); + } + } +} diff --git a/base/Applications/Security/CryptoBvt/CryptoBvt.csproj b/base/Applications/Security/CryptoBvt/CryptoBvt.csproj new file mode 100644 index 0000000..b94cdc2 --- /dev/null +++ b/base/Applications/Security/CryptoBvt/CryptoBvt.csproj @@ -0,0 +1,35 @@ + + + + + + + Exe + Cryptobvt + true + + + + + + + + + + + + + + + + diff --git a/base/Applications/Security/CryptoBvt/DesTest.cs b/base/Applications/Security/CryptoBvt/DesTest.cs new file mode 100644 index 0000000..6aec86b --- /dev/null +++ b/base/Applications/Security/CryptoBvt/DesTest.cs @@ -0,0 +1,332 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: DesTest.cs +// +// + +using System; +using System.Security.Cryptography; + +interface IDes +{ + void EncryptBlock(byte[] key, byte[] input, byte[] output); + void DecryptBlock(byte[] key, byte[] input, byte[] output); +} + +class ManagedDes : IDes +{ + public void EncryptBlock(byte[] key, byte[] input, byte[] output) + { + Des.EncryptDecrypt(key, input, output, true); + } + + public void DecryptBlock(byte[] key, byte[] input, byte[] output) + { + Des.EncryptDecrypt(key, input, output, false); + } +} + +class DesTest +{ + public static void RunTests() + { + IDes![]! implementations = { + new ManagedDes(), + // no other implementations are available on Singularity yet + }; + + TestKnownCiphers(implementations); + + TestInterop(implementations); + + foreach (IDes! des in implementations) + { + TestRandomCiphers(des); + } + + Console.WriteLine("DES TEST: All tests complete."); + } + + static void TestRandomCiphers(IDes! des) + { + Console.WriteLine("DES TEST: Testing implementation '{0}' for roundtrip encrypt/decrypt.", des.GetType().Name); + int tickStarted = Environment.TickCount; + int tickStopped; + int cipherCount = 0; + + Random random = new Random(); + + for (; ; ) + { + for (int pass = 0; pass < 0x100; pass++) + { + byte[] key = new byte[8]; + for (int i = 0; i < 8; i++) + key[i] = (byte)random.Next(0, 0x100); + + byte[] message = new byte[8]; + for (int i = 0; i < 8; i++) + message[i] = (byte)random.Next(0, 0x100); + + byte[] cipher = new byte[8]; + byte[] roundtrip_clear = new byte[8]; + des.EncryptBlock(key, message, cipher); + cipherCount++; + des.DecryptBlock(key, cipher, roundtrip_clear); + cipherCount++; + + if (Util.CompareArraySpans(message, 0, roundtrip_clear, 0, 8) != 0) + { + Console.WriteLine("DES ERROR: DES implementation '{0}' FAILED an encrypt/decrypt roundtrip test.", des.GetType().Name); + Console.WriteLine(" key: " + Util.ByteArrayToStringHex(key)); + Console.WriteLine(" clear text (input): " + Util.ByteArrayToStringHex(message)); + Console.WriteLine(" cipher text: " + Util.ByteArrayToStringHex(cipher)); + Console.WriteLine(" clear text (output): " + Util.ByteArrayToStringHex(roundtrip_clear)); + return; + } + } + + int now = Environment.TickCount; + int elapsed = now - tickStarted; + + if (elapsed > 5000) + { + tickStopped = now; + break; + } + } + + Console.WriteLine(" PASSED."); + if (cipherCount > 0) + { + int totalElapsedMs = tickStopped - tickStarted; + double ciphersPerSecond = cipherCount / ((double)totalElapsedMs) * 1000.0; + Console.WriteLine(" Approx ciphers/sec: {0}", ciphersPerSecond); + } + } + + static void TestInterop(IDes![]! imps) + { + Console.WriteLine("TEST: Testing interoperability between different implementations."); + Random random = new Random(); + int failureCount = 0; + + for (int pass = 0; pass < 10; pass++) + { + byte[] key = new byte[8]; + for (int i = 0; i < 8; i++) + key[i] = (byte)random.Next(0, 0x100); + + byte[] message = new byte[8]; + for (int i = 0; i < 8; i++) + message[i] = (byte)random.Next(0, 0x100); + + for (int i = 0; i < imps.Length; i++) + { + for (int j = 0; j < imps.Length; j++) + { + IDes! encrypt = imps[i]; + IDes! decrypt = imps[j]; + byte[] cipher = new byte[message.Length]; + byte[] clear = new byte[message.Length]; + encrypt.EncryptBlock(key, message, cipher); + decrypt.DecryptBlock(key, cipher, clear); + + int c = Util.CompareArraySpans(message, 0, clear, 0, message.Length); + if (c != 0) + { + Console.WriteLine("DECRYPTED VALUES ARE DIFFERENT!"); + Console.WriteLine("Encryptor: " + encrypt.GetType().FullName); + Console.WriteLine("Decryptor: " + decrypt.GetType().FullName); + Console.WriteLine("Clear text:"); + Util.DumpBuffer(message); + Console.WriteLine("Cipher text:"); + Util.DumpBuffer(cipher); + Console.WriteLine("Output text"); + Util.DumpBuffer(clear); + failureCount++; + + i = imps.Length; break; + } + else + { + // Console.WriteLine("TEST: encrypt {0,-20} decrypt {1,-20} - ok", encrypt.GetType().Name, decrypt.GetType().Name)); + } + } + } + } + + if (failureCount == 0) + { + Console.WriteLine(" PASSED: All interoperability tests succeeded."); + } + else + { + Console.WriteLine(" FAILED: At least one interop test failed."); + } + } + + static void EmitRandomKnownCiphers() + { + Random random = new Random(); + + Console.WriteLine("static readonly KnownCipher[] _knownCiphers = {"); + for (int i = 0; i < 0x20; i++) + { + byte[] key = new byte[8]; + random.NextBytes(key); + + byte[] message = new byte[8]; + random.NextBytes(message); + + byte[] cipher = new byte[8]; + Des.Encrypt(key, message, cipher); + + Console.WriteLine("new KnownCipher(\"{0}\", \"{1}\", \"{2}\"),", + Util.ByteArrayToStringHex(key), + Util.ByteArrayToStringHex(message), + Util.ByteArrayToStringHex(cipher)); + } + Console.WriteLine("}"); + } + + /// + /// This method verifies that a DES implementation correctly encrypts and decrypts all of the + /// values in the table of known ciphers. + /// + /// The implementation to test. + static void TestKnownCiphers(IDes![]! implementations) + { + Console.WriteLine("TEST: Testing all DES implementations against {0} known ciphers:", _knownCiphers.Length); + foreach (IDes! des in implementations) + { + string! implementationName = (!)des.GetType().Name; + + bool passed = true; + + foreach (KnownCipher known in _knownCiphers) + { + byte[] cipher = new byte[8]; + des.EncryptBlock(known.Key, known.ClearText, cipher); + + if (Util.CompareArraySpans(cipher, 0, known.Cipher, 0, 8) != 0) + { + Console.WriteLine("*** DES implementation '{0}' FAILED to correctly ENCIPHER a block.", implementationName); + Console.WriteLine(" key: " + Util.ByteArrayToStringHex(known.Key)); + Console.WriteLine(" clear text: " + Util.ByteArrayToStringHex(known.ClearText)); + Console.WriteLine(" known good cipher text: " + Util.ByteArrayToStringHex(known.Cipher)); + Console.WriteLine(" failed cipher text: " + Util.ByteArrayToStringHex(cipher)); + passed = false; + break; + } + + byte[] cleartext = new byte[8]; + des.DecryptBlock(known.Key, known.Cipher, cleartext); + + if (Util.CompareArraySpans(cipher, 0, known.Cipher, 0, 8) != 0) + { + Console.WriteLine("*** DES implementation '{0}' FAILED to correctly DECIPHER a block.", implementationName); + Console.WriteLine(" key: " + Util.ByteArrayToStringHex(known.Key)); + Console.WriteLine(" cipher text: " + Util.ByteArrayToStringHex(known.ClearText)); + Console.WriteLine(" known good clear text: " + Util.ByteArrayToStringHex(known.Cipher)); + Console.WriteLine(" failed clear text: " + Util.ByteArrayToStringHex(cipher)); + passed = false; + break; + } + } + + if (passed) + { + Console.WriteLine(" PASSED: " + implementationName); + } + else + { + Console.WriteLine(" FAILED: " + implementationName); + } + } + } + +#if false + void TestPerformance(DesImplementation[] imps) + { + Console.WriteLine("TEST: Estimating performance of implementations:"); + + Random random = new Random(); + + foreach (DesImplementation des in imps) + { + byte[] key = new byte[0]; + random.NextBytes(key); + + byte[] cleartext = new byte[0]; + } + } +#endif + + struct KnownCipher + { + public KnownCipher(string! key, string! cleartext, string! cipher) + : this( + Util.HexStringToByteArray(key), + Util.HexStringToByteArray(cleartext), + Util.HexStringToByteArray(cipher)) + { + } + + public KnownCipher(byte[]! key, byte[]! cleartext, byte[]! cipher) + { + this.Key = key; + this.ClearText = cleartext; + this.Cipher = cipher; + } + + public readonly byte[]! Key; + public readonly byte[]! ClearText; + public readonly byte[]! Cipher; + } + + + static readonly KnownCipher[] _knownCiphers = + { + new KnownCipher("26e9fc83852311d8", "e1402d0f9442d85c", "c0e394fd6490aa0f"), + new KnownCipher("c95e9d039d732b6c", "2eee2417b69692a8", "bcb78b4a1215d78a"), + new KnownCipher("7b331146c590b1d3", "6e376932bb2c030f", "555127f9a4111092"), + new KnownCipher("e83a28ea550972b3", "be905596fff9224b", "f9656d3ec8fbab2d"), + new KnownCipher("ae85936030929638", "adc9946509f9b101", "6b90762b582cad2d"), + new KnownCipher("eb142f7b6da75271", "c05e88353b1ad474", "349b95d1d20d26c1"), + new KnownCipher("141d833598a2df55", "a4f03d8b740ca9c4", "74507d68be5a8638"), + new KnownCipher("df53abeacaa7de06", "3222a0d10961fd92", "c366707e826f47f1"), + new KnownCipher("f52050eb757b6948", "35d9d77c6ac7fdb4", "738b39e892f934fd"), + new KnownCipher("b5c356e76ee9aa6d", "3f7d0376020e4c42", "3b85c78032007603"), + new KnownCipher("f3aa9654bbbd4f63", "ea63b4f0d0619c6a", "75609fcade3f50a3"), + new KnownCipher("25ec1b450b15240b", "75e3acf777f24627", "72021f00c2d5d1ba"), + new KnownCipher("8d9489bf31a8f8f8", "74f2fd0b35ba9cdd", "47b36b2a63ee1625"), + new KnownCipher("e1985116f20637dd", "868aded81057ecf7", "0ef7b7b9e9253675"), + new KnownCipher("1c8d623bd7dd397c", "f322d1181818d6bb", "5d9e33944c860522"), + new KnownCipher("46cf16dea1303487", "5cac38a6ca1fe81d", "b665aef92e365f88"), + new KnownCipher("0605eea757600504", "5ed422d0351fc46e", "744b0036d03d4d9b"), + new KnownCipher("b4229141400d56ec", "59dadf2ba493b2d4", "c480de721320b5a8"), + new KnownCipher("3ab31212292f63e5", "c9127fcc0d64523d", "d45e4fd7fbe7b1fe"), + new KnownCipher("e7caf2a78ea6dcf8", "af024d7d81da5fcb", "37e340853ffde534"), + new KnownCipher("224e95810cb24485", "beab772d8d89def5", "f5f9847dd156ab1b"), + new KnownCipher("88a143daa10a4693", "d6196327e1e664ef", "e752f30bd985b91e"), + new KnownCipher("b3b4aabfced03135", "856de9e22eaf6b26", "627247191de4454e"), + new KnownCipher("2358f4e096852a17", "0801aaf24e1da3d7", "55da1f2d460c0d43"), + new KnownCipher("47887ad8de1e26b7", "6f0e543321636427", "e04edfab22c74acc"), + new KnownCipher("ae3c0389f283592d", "8a93b7cd263ee668", "50889aa8dbafb44c"), + new KnownCipher("c9119ba635924704", "313c708731f6f6a4", "7637d6adbc64209a"), + new KnownCipher("9c834311191ae5c3", "2f4c4e4b67599130", "6ba0e036c4584386"), + new KnownCipher("28eb6a10c8bef21c", "f5fe57b512d1fc93", "e0a4ff1c86883af1"), + new KnownCipher("9d1330a2fbd44fae", "2cd777e843fc9dd7", "54091b5227549171"), + new KnownCipher("aa3f5f468ce5dcdd", "91261c1ac32fb05d", "dd5fe1a60c3fa9ed"), + new KnownCipher("50bbae5428ef3553", "9bbbe3f04709d9f8", "ad28c355c1b48107"), + }; + + + + +} diff --git a/base/Applications/Security/CryptoBvt/MD4Test.cs b/base/Applications/Security/CryptoBvt/MD4Test.cs new file mode 100644 index 0000000..85929bb --- /dev/null +++ b/base/Applications/Security/CryptoBvt/MD4Test.cs @@ -0,0 +1,185 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: MD4Test.cs +// +// + +using System; +using System.Text; +using System.Security.Cryptography; + +public static class MD4Test +{ + + public static void GenerateKnownDigests() + { + Random random = new Random(); + + for (int i = 0; i < 0x40; i++) + { + int length = (random.Next() % 50) + 50; + byte[]! message = new byte[length]; + random.NextBytes(message); + + byte[]! digest = (!)(byte[])MD4Context.GetDigest(message); + + Console.WriteLine("new KnownBinaryDigest(\"{0}\", \"{1}\");", + Util.ByteArrayToStringHex(digest), + Util.ByteArrayToStringHex(message)); + } + } + + struct KnownBinaryDigest + { + public readonly string Digest; + public readonly string HexMessage; + + public KnownBinaryDigest(string digest, string message) + { + this.Digest = digest; + this.HexMessage = message; + } + } + + struct KnownStringDigest + { + public readonly string Digest; + public readonly string TextMessage; + + public KnownStringDigest(string digest, string message) + { + this.Digest = digest; + this.TextMessage = message; + } + } + + #region Known Digests + + static readonly KnownBinaryDigest[] _knownBinaryDigests = + { + new KnownBinaryDigest("f0bfce358c94b997446f92418a8ff037", "c07a95c4781606e4c60ddc8bf99e43ffc5c597e745f1ba55d5166a3c36006d39dc09eddb2c41f18d7a92f056f9afb90513c510882e4650"), + new KnownBinaryDigest("a2a637a9435062b1a0ea99da79b43b30", "bf3fef62acc9aec5a0a3aef0b167d283d40a6cb300635c255c642870efe40a96b91e1bec518ee0b0e42ab65601c953abf38cb424d99cce5ce3ca0548a03dd6bb991736934ce5314529bccfd5ad0523"), + new KnownBinaryDigest("20642ecf402a801b63a84d6bee5c5214", "107d7d6230e5bd1d4fbf098789980fa654fabdea92bf5f0d5b6efb1ccdf8afdda6713723c0748bb35919448cdcaabc91ac2881b2483901511d6f07c1eaa04f56102be1"), + new KnownBinaryDigest("3db0ec870748f4ce621e7f0390c14e47", "61ece5df6f0990787bd230b0b26a70a477fc946c70e605516dc9c8b8c9ed7cb0c8a52fc043a2423ea888d54b3f560f8030abdf139774a67be69472a540d7ae8d567fe8"), + new KnownBinaryDigest("ba47a68179ae71f3bdec8076d3616daa", "3aaf60d5ba55c4e710ba1117ba48881e0e681954feb4d9ae2f9cfdd1d947f4bf6d0245804a0a5941b0bf6a2b825bebf84f907fee65940e85d5b1a51d58f20ec8c651a9b70207d3030ed8a33f49ad2cd4b1058149c8065ad9f4c0aa98653ce9bdb0a1"), + new KnownBinaryDigest("8e3f46b580f612f6689820d6edccb4c0", "31b134f547bc7bdf8cf0ce3b2785d06b5271c500bff7cfc2425c3b9ed2efe68ea848fb227d10398c4c26cde92584821294d0964ceba1a639e271b2ea81dd0d9d0a4093df8aadee413738b4982ae59dbeda280901589aa306a2c1400b5d"), + new KnownBinaryDigest("6d9c5f91951d6910434748c9d8ee16cf", "0b6f1930dfe5f0a288e6e25414b2ed0d0efcd4f31058d30b44709c8d3dc86de2e3e82d457ffa06b7ce37a0221f0385f01995b243376a3eb29b0deb6f486365bf79ff712c84a78d14f61c25d9b8"), + new KnownBinaryDigest("90b25ee968b17d38d2c42681b1fd2276", "ec40eaac73a8162aaa79a97ba9710e976f6bd2e1a91f92586b72079e4d1b4465f9ea21ab849cf0bca84e55f78209fd1c055fadba06d706cdad924001a177dd8f3544"), + new KnownBinaryDigest("06a45aff14d1ec4af4d2cd0345bfed35", "bf4f6312d37a15385bca9bd56274ea98ed6e8a5e22e354fef15bee1b3171c6c23e873ecca24cd93ff19eab0312bcde8db6dfef20aae55fdbfb6420788bf907"), + new KnownBinaryDigest("98dd4304516ecb0238525c249faac59c", "04d896da351df5a1944a6c843851ec357c61645281a517592863d03d2b61b3f797c1ff3926035798e94e8c6078dba3aa78ebfb2a94b5685ec13db2d14db875329775ec7651b20e7809cc683319b7e04dc026"), + new KnownBinaryDigest("06d39ef7b937a9a607703136d4adf64b", "40668962e258a078e851864b31d859c803ee2c58c6dc8220c84c3545095c651126f335cc0d120a1eb13a26278380375abfeedd5e"), + new KnownBinaryDigest("e30551d3ede1ef4bed2666ed88d49bd2", "cdfe63e3689996235a6e8beb75243ea38dbaf0e40da78bb65a9c4814da861a7f067d59f4d2e8a57874fb56cc9a3c0e5bf9b73133ec7a862673ac89cb518148d4530ce5f7cb49d1a51578701250bf1c1e8eec1b2355e6938bf633"), + new KnownBinaryDigest("e08f1c0e503f1daf4a0814bde5a472b4", "255ed926f2b282788d561690afe68b1d740a73d5b48f6a3d6565247e6d79590197c8ab463c517d5fcd468fc7785b6b3dc9c81f81835dcc96f49bc08c8e030b14fd15f8e73a44e1228d13086d00a3c50afae6b4a459d87d"), + new KnownBinaryDigest("5926283b00d681d5773aa905d7e236ad", "fb1552a090f0d1c93b7ac96262840385e7fcf36f555f9550d6b692a74f66ba2597beeb25f240919c423e3186d962a875e32fbd5de40ee59c7f01cada5d297ad5bfa4cba399dd93a76b562c172d0f"), + new KnownBinaryDigest("b8caab8210e57bfa49dc96a4141c3fb8", "740e1cc31fa95d4089d94fa6f076b73e18c35cc6349704dc069c15f28de1ce6e6f8a55cc41665b2b626341ca4a37a230b3181453d14942dc093fbd82936bb3a70be0376520ebfdb2673164d1553a92cffae43e75cd"), + new KnownBinaryDigest("ab526921f32a481ef9a4221423c55717", "9d254879c201a8d897f6b09abf69003c10c81a61eba0e57187cfadee88ae2c3ed99043111da628fc098f996d21bb7b28cebdd4755b6c8efd40d7f2f253ba4fe8c972c02e26ee1e699f1e585c06774fcb"), + new KnownBinaryDigest("49adde580b63efa72da477d9ba4ed6c5", "841fcbdab6e36d0245d046b435a84e3fb0a3aefa4c02e09e6ad63c1432f6c887269ecf9b840e128f522ce01dd8b46a75091c56d4a1d007823f2c6fe0a659cf4f08bf8e97d8b2bba1901fa82021c2c6b56cc70a15a0f4"), + new KnownBinaryDigest("7b9ec86447f0fff3416705a7c8502a50", "55964d5c579e32e8f95c91151826d29c5661b4438128e7607c66ba74de4fbaaf13d938008b5663035e36afc490acad8e992ab4b3ebb1642dafecdff0e4bd09aaa1e2013feed21000fdb0e44a7922d0d0b82bdbb49b07c362740a509e76721fa12c05"), + new KnownBinaryDigest("4d571a449807de18c896d5518c8314e7", "aeab6e9fc619b3b53acc1ab48c1c0f38b8e1550f9a1e9fcae482728a8b91421d740021254a8b159be75188955a56c382663a67bfd7f6878f0ba4bb44a7292aa98afc3f8c"), + new KnownBinaryDigest("d1e3ad29b4df00d0e2e82ad7843dc4da", "eaed2cccba27499509708dbeef23502a82467e789119a6cfd1f3bd27df0b5d1636877b4d3af31dce3efa02342e85b705da7f07b6c11469d1475cfbc66922b6fe12768768a803ef8f28af39971672a14b"), + new KnownBinaryDigest("d81d2be81edf8af4cced6942238f6415", "b74c6003a755221ea905ddf856641c430421b7fd4f5dd78f788d11dbd1bbd5baaf8ab1d556fa6b21654afefd1196d24b1c541250ea4dec5a75d08b1943474cee2f2248ccb247ed0ab69598055fd97de1bbc6"), + new KnownBinaryDigest("b448014e40d44a7e620431061b420de3", "7da985d0619d575f856e51de1efd0fcdee4d0598d466079a55b5e7fa9c53a95d7d88cf45aa52e62e5ae8689b64b779074f0b8e94b52dea16a1ea7aacb55dc331c5f361962dca229c67d73decfd6c359e3bdf"), + new KnownBinaryDigest("9768dc037ed3ce03f1d22724f5db2774", "90c515a84f9db8a4bfd73a78fd2437d67055e3da85e8f22cdef0fd1934b5dc70d6b2326caf4b11f8742563c42c5e3fc8c696c448580524a8d2e8ca5fa09f6f0afbc9a24bf1ca262544ea665f852d007fb035529e"), + new KnownBinaryDigest("245fefc023958a857f6d76db50c3efd1", "9418d18d8a99c781b257d4b658c963bcf4d6fb709f046d9ec422a4e84aaf6b4dd11a66b1d1bd67315fa3919291a92c649dc2bb5f562e5090aa32c867"), + new KnownBinaryDigest("a500920a9ae3817d1c6816b3fcf6479f", "de3603ec87e53e62b1eb376eca10fc72da0d1bf5404b88f30bf6a2c9d6069ef4ff3c806d8ea609c4ee01ebd784f08b1d541dd024ad72b493ae0fe09142748cab4c426f8e908ee3340457073e5fb06e1b"), + new KnownBinaryDigest("38c80b639c54953c6c906e921ddada60", "8575b8367a478d88ecbf7ec578817975408a4280fd8cc53a9b20556b7534fda0c526bdffd375d2fae206a4cf646f8bd58dc91f252c9a6df8af7e9a59f12212b8c1ddff52c47aa1cab8479ef6e8f5d52c957fddac14d7742a"), + new KnownBinaryDigest("cd38041178d9fb3ba75d5f96e304988f", "c44f55da7808c0f4eb0e876f38111327546de4fc760fbaa86dc4724466a4e969d599ff2a4bf0403fde02fce74ebd5c6dca84bf6a8f2e41b495ad6db3967b8d47241d"), + new KnownBinaryDigest("58bfac3ac5f74300c3c70b6e2ba4e376", "9f12e8dc642ca51e7413d25ab068047ae1e47ed9a7584a959e828ca96274b5c23023bd5be1a75a3dea10cda1c252bd4b9101ab63a543f346c753"), + new KnownBinaryDigest("fc4d0efd7403af20e26f7846c9d3d35d", "e1a0fcbbff5d0f2a8caba8983a8941ef968aa8d24cc5411761c8521ded3076938e69799ded54ce44b328309fe96871d964535cbc1f80f1"), + new KnownBinaryDigest("86db265b01b99746cb3b14aa438191c4", "5ee55a360bf23d5c35150ad010a30142bc641f2395a12ef85778b999d4b9740d785d3e08fa9738c0ebd36ad35ea1c8c0521900bb61cd86bdb761df9239a388"), + new KnownBinaryDigest("c3fb7c36e5c7e95d79315e222a90f1e4", "a1fd57b365f948242b5e38c1375a9ab5b0f846bab9b8abaad6815198b8a587474bef32604a155a59d1db8f0395c4865cc72ae2405dcec1e851addce4a7"), + new KnownBinaryDigest("0ae97f2485f43dafea128cab4481dd6c", "6b86d6f1764727396b9b9eede8dd29a81512faf4d08ec347ea7d2d4a0e9c3875b1216f082ca34d3e348dbe47a16fe5e3bea997c9e9b2dfddc38e06f919dd2ace62283cc66d207b71c4bcbf42cf7ca57b974a8b65046e8cff4292459d9d54245762f0"), + new KnownBinaryDigest("74180625f0e3b027bc5a31af7ab79377", "79331e759d2d26052df29c0e46e98b61cf52c5c9f39c3d84dbdbded46f9768dfde972c4878d4ed38de695e0ca583ffb411f354049d26f0ddf59a9ac24f5295968abd2faebc43e8fb658ceb8a3d30df57db29"), + new KnownBinaryDigest("598f0f4c89c5b9b55eb71b73b776d00b", "7c426341b8a74e52de3a2ae88bd4c882e85450f7cd0b599f113b669fc5bb42e6268f1953267b77076ef109c13aa35fb675aef6038b31f571e9c4307d41ae8d23f743c2fcbb745b6ddd4889dc0198656ddbb02a"), + new KnownBinaryDigest("cdb03c829486120b7f77fdb1c9b8ad8c", "c43f5bf499a86a624af9c6bf64e6c9f6e063fa0053892542a7196f505ec3a19084765fb8e8ce62130af922e382ca771bce6e8c77b52ac33b19184d803819038657353bed87100e1200e7f6596641c0dda15481f0372adb59b3249ecf81e1daf0f69c"), + new KnownBinaryDigest("ee324b754479fe1f0eac727532b90008", "4d8f8993be607976cd3369d4d85870dee398124f2d59e13a63723e911e0d0662cab5734d18c0c390bdb30e26494fc6771103f758e34c5ef3ae4f304c21e857c02d070a23e422c622d482"), + new KnownBinaryDigest("7d6db0dbba1dbea008746ede376c2c5f", "7a4bbbf013abc6801b15ae7e7d577f9fc890776ed55b4ef84245a292ee3cd48361bae3a8f35f1ca05b683caa7f888ccc6583fe925c13bc1ffdc2adce093391"), + new KnownBinaryDigest("fe7f9dab6ec7de2f87444b4023dbf5a2", "412a1dc273d7ac6873d7136c1ea378b9b8d62d6b3e42264dfdc4ab30b14e9727d75d69556bc9598ed6951f85005000594af416320625a0fe03cfc4ae2b7c"), + new KnownBinaryDigest("11b24c3637f7c9026cd1e3ea9e51c1e4", "2540eb95c13a234eee7d9e94a823a14dadc451e5bd376421b1bd6a519c04aa625adef94514ba3e1e26a527b46790f7db628217ead996f9eddbcae404cfd1b2e9d33c39ca295b38f38533bf1710b0ba20c58fef19edc089c4e40c6a4ad6"), + new KnownBinaryDigest("daf7697812aa4bdf35210439c83fc5d5", "4e55f33ee12b572db206492364a6d7e2dd2a10c33e40e298fb12b375e51cf1ee1c4ae46923d2ce8ec998dde8d0c95be2ed022f3f3913fc0e725b42ce78e14795155a0719"), + new KnownBinaryDigest("ec9c52bf6541e44e2f591ac088c416ff", "6dbe0a5b81f9a663fac831b7d087e2edb1b5094ed6f6c88f0016e75047d275c2411f804424e3b71955aa78931017a75a65a763a5fdcbec76f57a5b6b12551b27526f75b0079ec8cefdf0f82b7e357fe86f8deba06ecfc476330a4fa9884c06ff8e51"), + new KnownBinaryDigest("155e56998c8a6f255221c841706d3d9f", "a0a2f653c6df95a80dd2c0f8bffb72fb856a7bb882aafe7dfd4f1e46b0e9f89d2cf5de46783924c0d927b7a473118fae155081951298bdf6a379"), + new KnownBinaryDigest("279a54a10ad9ce5766c80f9aa68556f1", "77c04ff724d922cbca1c2c834b45badf5af35a0aebbf6f305f67638b9337e8a2ffe3ad00893093ca5046c592e8cd364f57b96302486f6ab7501e97bc759737923389846798ba562a5f90b9a4fadd4892311333dad4e55a8f78f5af6a98d654b8"), + new KnownBinaryDigest("16d60d34d9250a5d7ab8e810a4dce9a0", "325f5f49ceb69d6338a2b8b5c6bc73d6058a62635cbe4d2ff4efa30aeb92893b0095c87de849635d96779c42a1dab2383c93934cf255b173113055df139277a5197db430f4f5eebc2704cce5220a8d193c6acd57ff3c48abe4546cb8f3834904"), + new KnownBinaryDigest("01c4c8a06a5cb85947f79faee6e888c9", "f6282425824347a5d624ed88cc5107a23ba3a8c420a6dd34084ba08935c8a3bbc8e52ce169f4b92686b128185b2317026415b8e0a03fdf4f4bf01d36a3be6f0e8032bfe625253947e9813e6e7ec4d9e5349d24200fc31a8906dc9578d68282c841"), + new KnownBinaryDigest("f052aea84646daf743e894cdf39de7f8", "97286431dd3fdc71f61f0071d18617380206994ffebd1835e0488fc07066fe762c632db08003bfe4449dccfb89940b0e619e807c2ef21bda102e5094af1b018f2089456d5966"), + new KnownBinaryDigest("9f0b66eff9c7e1aff8c0364a33df09f5", "ff47b50b60f01dac4c3d805fd1e68248394852a052b22a34289c3cdaff4e9eb5fae7803578e6baeaf38104572fbc30a89d410b2507c6644d1c80e2c4b342adfd9ecb64e9664dcf538d68acd0add3056c6c933dbd4379ad3382"), + new KnownBinaryDigest("e5b8d8b5ba714a335cac91297713b40e", "18f804f636b0d407b8635746424f71b8979f19939f497a76581f04f0b9251e30663235d74e9631fcfca61aa2142551ee4b8ae10e1aef93cf7d8d9e17ace34d"), + new KnownBinaryDigest("efc78f3593004050862070a900b1f0cb", "4527df0f1a9a69006d1d97f92ed76132ce16a42e440f16779e6559c1f8194f1858865dec4641d3b121e0a0fc579aa0a52b6c49953f1e4f35116770b540a80854cd7ea0a87a75eb8c42f30d"), + new KnownBinaryDigest("dd0faf606a4a99562a59f5eddf9109d1", "6e1a1f04c4b3958ccfbad9393727dbded01e7078d84c2ed9faf82bb680bd534c10ebc7f7486cf08c127c8413a5667052990dbb2382958b21eb460acb88df0b12668c284c60e496642ee3665bc81b349388d81d72012fc97b60a50b01622404337071ac"), + new KnownBinaryDigest("4e51172bc8aea5c5cabb4d14eb0a5357", "3e24f2b57757f59f2e2f59d0117743b0c1981137c3acebbad8940109df32eb566e1c5463e668fba93a2a4d304b3bf0ebe15471d75f7555913837dce255ebc0fc440262f522dfca599d67fc985fbb"), + new KnownBinaryDigest("6590509a2a5a94afe6d6f417232c4464", "9da416288ac013f7f8c7c32bae8b19534f6a50eb49d9fbc8018a173af778bc317cc83f3e3fc2353b310b692d5eb41bce8314ad2e0fd025c3a84d2700a9d9ff800a91ae"), + new KnownBinaryDigest("c3b8b6368323e3ba4d72186527bd308b", "4cdb148c3515ba3d70cd6a4d6e49b6e3cb8e22aca27b95f19b3492580ce923cd053581a8ff20f9f916e853dbe3da925f221bb47c6f0243d14522f10083613186aa9c4838c70de3aa952896ba27ba0ec0a13235f034"), + new KnownBinaryDigest("f6321f1c7a026655dd110a958b651712", "5d02f2b063dd2ff876b4b6cc3046925a9714380ae7466c88aa8b14305f502c4052043f454517aa067b9cb1e2035a89c72e479a20b82abf16966905d8c8fe982688757a2c074c14806a31"), + new KnownBinaryDigest("ec4f3d19e1ed7f0fbf973b2f52c38828", "4a958a854f014c0117b60b88274528aedc11d13d7c048b598ddf5dc0e1331ab6869b74810ce4b6d77cfc80707ced52e7df9e386e98f412460930f770a38c20e49b54028cd0a6a2f75bfac1"), + new KnownBinaryDigest("0932e93d6d46614616890e7488297535", "831bdca08d76e043fbac1d91882d78dbec4633efdc9cd428ebc51638fb40129d3392c3ee5357e22dabdce9ef367003a22dc60a15c7d2a3e646b4b5c75fa848ba99805ef56a8a889563054300b3e5f17ac2740a3435fcd560efdca79ea21bce"), + new KnownBinaryDigest("cde8caa572037238bc679984e47992a8", "942e55b6110d38a33d75b2c28ea33361c33a05ea9d13849daafd068de2eaf247373f6c84903a69b43c67f6c04a13d14ca946db6816e36680a9b80c1307aac053826a8b4f36aed188d051ae351c"), + new KnownBinaryDigest("59d402089b2cce628d9472afa258bce4", "53962cb9e49c0e8a3153d8ebdad82e56ac91a6a33edf888215fa755297c5353063e56476e74dc62444f73937774bd3f95a7aa41c8f798673"), + new KnownBinaryDigest("de4927482c6025bc9924f98779e0e766", "a9a3e927bcf36b1da787f573b86e5ecb815e46a5510bca267cf81c2018a1ea5ff1683daadcfd8803cd19cfc3de85a10c46510d1b3fcdbc9ed9c3abc3d74b05069d96814f31b4ee"), + new KnownBinaryDigest("e11d15ca495150953358d9a5581d2ee4", "d542d8373b0648f65710dac693ce1f23ac9ed01952c52c8214c925470351da91638946fcf58562d27ab46cc7713e72cf765ea392e3d4320f"), + new KnownBinaryDigest("cca1c646dd4f5b01bbf8ec6beae60767", "562272e100f2053548630a88232d273bfd9e9d596511d65656d1a5ae48ad8e5636e69f62f0f17ac2679128da684653307c56e53595b6b1444c1c8a2f4c56ec9ad5b3513d"), + new KnownBinaryDigest("923fe6402e076748bc2de6e8a031d75b", "c44b0c24daf2d3e8fbed107d7431f1c858c17f345a16d3664a7510a58d05b4f416a3b70ad911bac4dd5c502e7ab1d825fad27cf2d10833ae77a5d964e12e5af6391b67d17a"), + new KnownBinaryDigest("1b5dbdb642bfda82e4388b93e9ddfcbe", "ee4706bb57fec5a5ec999debaabb88c2230e6f0992333756e2af015af45f4a06aa13e335ec16b134e8d2b940c7f6839f6e77f859617054bb10b0d8a7fd6bb08c4f964096d752d50c5d"), + new KnownBinaryDigest("7c9c416a29c3928dd66e94868f7ef6d3", "21c07af68eeb2b62eb7d67f0a53abf28253c3d09377c222cf131b6edc71ba1ebfc264e94411921ed7b9a7f32255ef005d7af2d99ce5303a49e4d055d343e9ad0dc"), + }; + + /// + /// These digests are from RFC 1320. + /// + static readonly KnownStringDigest[] _knownStringDigests = + { + new KnownStringDigest("31d6cfe0d16ae931b73c59d7e0c089c0", ""), + new KnownStringDigest("bde52cb31de33e46245e05fbdbd6fb24", "a"), + new KnownStringDigest("a448017aaf21d8525fc10ae87aa6729d", "abc"), + new KnownStringDigest("d9130a8164549fe818874806e1c7014b", "message digest"), + new KnownStringDigest("d79e1c308aa5bbcdeea8ed63df412da9", "abcdefghijklmnopqrstuvwxyz"), + new KnownStringDigest("043f8582f241db351ce627e153e7f0e4", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"), + new KnownStringDigest("e33b4ddc9c38f2199c3e7b164fcc0536", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"), + }; + + #endregion + + public static void VerifyKnownDigests() + { + foreach (KnownBinaryDigest known in _knownBinaryDigests) + { + byte[]! message = Util.HexStringToByteArray(known.HexMessage); + byte[]! knownDigest = Util.HexStringToByteArray(known.Digest); + byte[]! computedDigest = (!)MD4Context.GetDigest(message).ToArray(); + + if (Util.CompareArraySpans(knownDigest, 0, computedDigest, 0, MD4Context.DigestLength) != 0) + { + Console.WriteLine("*** DIGESTS DIFFER! ***"); + Console.WriteLine("Known digest: " + knownDigest); + Console.WriteLine("Computed digest: " + computedDigest); + Console.WriteLine("MD4 BVT FAILED."); + return; + } + } + + foreach (KnownStringDigest known in _knownStringDigests) + { + byte[]! message = Encoding.ASCII.GetBytes(known.TextMessage); + byte[]! knownDigest = Util.HexStringToByteArray(known.Digest); + byte[]! computedDigest = (!)MD4Context.GetDigest(message).ToArray(); + + if (Util.CompareArraySpans(knownDigest, 0, computedDigest, 0, MD4Context.DigestLength) != 0) + { + Console.WriteLine("*** DIGESTS DIFFER! ***"); + Console.WriteLine("Message: " + known.TextMessage); + Console.WriteLine("Known digest: " + knownDigest); + Console.WriteLine("Computed digest: " + computedDigest); + Console.WriteLine("MD4 BVT FAILED."); + return; + } + } + + Console.WriteLine("PASSED: MD4 BVT"); + Console.WriteLine("Verified {0} known string digests.", _knownStringDigests.Length); + Console.WriteLine("Verified {0} known binary digests.", _knownBinaryDigests.Length); + } +} diff --git a/base/Applications/Security/CryptoBvt/Util.cs b/base/Applications/Security/CryptoBvt/Util.cs new file mode 100644 index 0000000..6ee0854 --- /dev/null +++ b/base/Applications/Security/CryptoBvt/Util.cs @@ -0,0 +1,134 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Util.cs +// +// + +using System; +using System.Text; + +class Util +{ + public const string HexDigits = "0123456789abcdef"; + + public static string! ByteArrayToStringHex(byte[]! buffer, int index, int length) + { + StringBuilder sb = new StringBuilder(length * 2); + for (int i = 0; i < length; i++) + { + byte b = buffer[index + i]; + sb.Append(HexDigits[b >> 4]); + sb.Append(HexDigits[b & 0xf]); + } + return sb.ToString(); + } + + public static string! ByteArrayToStringHex(byte[]! buffer) + { + return ByteArrayToStringHex(buffer, 0, buffer.Length); + } + + static byte CharToHex(char c) + { + if (c >= '0' && c <= '9') + return (byte)(c - '0'); + if (c >= 'a' && c <= 'f') + return (byte)(c - 'a' + 10); + if (c >= 'A' && c <= 'F') + return (byte)(c - 'A' + 10); + throw new ArgumentException("Invalid hex char"); + } + + public static byte[]! HexStringToByteArray(string! str) + { + if ((str.Length % 2) != 0) + throw new Exception("Input string cannot be odd in length."); + + byte[] result = new byte[str.Length / 2]; + for (int i = 0; i < result.Length; i++) + { + byte high = CharToHex(str[i * 2]); + byte low = CharToHex(str[i * 2 + 1]); + result[i] = (byte)((high << 4) | low); + } + + return result; + } + + public static int CompareArraySpans(byte[]! array1, int offset1, byte[]! array2, int offset2, int length) + { + for (int i = 0; i < length; i++) + { + byte element1 = array1[i]; + byte element2 = array2[i]; + if (element1 < element2) + return -1; + if (element1 > element2) + return 1; + } + + return 0; + } + + + public static void DumpBuffer(byte[]! buffer) + { + DumpBuffer(buffer, 0, buffer.Length); + } + + public static void DumpBuffer(byte[]! buffer, int index, int length) + { + StringBuilder line = new StringBuilder(); + + for (int i = 0; i < length; i += 0x10) + { + line.Length = 0; + line.AppendFormat("{0:x04}: ", i); + + for (int j = 0; j < 0x10; j++) + { + + if (i + j < length) + { + line.Append(" "); + byte b = buffer[index + i + j]; + line.Append((Char)HexDigits[b >> 4]); + line.Append((Char)HexDigits[b & 0xf]); + } + else + { + line.Append(" "); + } + } + + line.Append(" : "); + for (int j = 0; j < 0x10; j++) + { + + if (i + j < length) + { + byte b = buffer[index + i + j]; + if (b >= 32 && b <= 127) + { + line.Append((Char)b); + } + else + { + line.Append("."); + } + } + else + { + break; + } + } + + Console.WriteLine(line.ToString()); + } + } + +} diff --git a/base/Applications/Security/bvt/PerfSnap.sg b/base/Applications/Security/bvt/PerfSnap.sg new file mode 100644 index 0000000..b1c3871 --- /dev/null +++ b/base/Applications/Security/bvt/PerfSnap.sg @@ -0,0 +1,286 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: PerfSnap.sg +// +// Note: Performance measurer for Singularity Benchmark +// + +using System; +using Microsoft.Singularity.V1.Services; + +namespace Microsoft.Singularity.Applications +{ + public struct PerfSnap + { + // Global options for all instances + static bool xmlOutput = false; + static bool atRing3 = false; + + private bool disabled; + private long begCycleCount; + private long endCycleCount; + private long begSwitchCount; + private long endSwitchCount; + private long begInterruptCount; + private long endInterruptCount; + private long begKernelGcCount; + private long endKernelGcCount; + private long begProcessGcCount; + private long endProcessGcCount; + private long iterations; + private ulong begAllocatedCount; + private ulong begAllocatedBytes; + private ulong begFreedCount; + private ulong begFreedBytes; + private ulong endAllocatedCount; + private ulong endAllocatedBytes; + private ulong endFreedCount; + private ulong endFreedBytes; + private ulong begStackGets; + private ulong begStackRets; + private ulong endStackGets; + private ulong endStackRets; + + + public long Cycles { get { return endCycleCount - begCycleCount; } } + public long Interrupts { get { return endInterruptCount - begInterruptCount; } } + public long Switches { get { return endSwitchCount - begSwitchCount; } } + public long KernelGCs { get { return endKernelGcCount - begKernelGcCount; } } + public long ProcessGCs { get { return endProcessGcCount - begProcessGcCount; } } + public ulong AllocatedCount { get { return endAllocatedCount-begAllocatedCount; } } + public ulong AllocatedBytes { get { return endAllocatedBytes-begAllocatedBytes; } } + public ulong FreedCount { get { return endFreedCount - begFreedCount; } } + public ulong FreedBytes { get { return endFreedBytes - begFreedBytes; } } + public ulong StackGets { get { return endStackGets - begStackGets; } } + public ulong StackRets { get { return endStackRets - begStackRets; } } + + public void Start() + { + if (!atRing3) { + disabled = Processor.DisableInterrupts(); + } + + int collectorCount; + long collectorMillis; + long collectorBytes; + GC.PerformanceCounters(out collectorCount, + out collectorMillis, + out collectorBytes); + + ulong stackGets; + ulong stackRets; + StackService.GetUsageStatistics(out stackGets, + out stackRets); + begStackGets = stackGets; + begStackRets = stackRets; + + ulong allocatedCount; + ulong allocatedBytes; + ulong freedCount; + ulong freedBytes; + PageTableService.GetUsageStatistics(out allocatedCount, + out allocatedBytes, + out freedCount, + out freedBytes); + begAllocatedCount = allocatedCount; + begAllocatedBytes = allocatedBytes; + begFreedCount = freedCount; + begFreedBytes = freedBytes; + + begInterruptCount = ProcessService.GetKernelInterruptCount(); + begSwitchCount = ProcessService.GetContextSwitchCount(); + begKernelGcCount = ProcessService.GetKernelGcCount(); + begProcessGcCount = collectorCount; + +#if x64_PERF + // Set up for perf counting + if (!atRing3) { + // Reset the performance counters to what we're interested in. + Reset(0, PerfEvtSel.COUNT | PerfEvtSel.CyclesNotHalted); + Reset(1, PerfEvtSel.COUNT | PerfEvtSel.RetiredInstructions); + Reset(2, PerfEvtSel.COUNT | PerfEvtSel.RetiredBranchInstructions); + Reset(3, PerfEvtSel.COUNT | PerfEvtSel.RequestsToL2Cache | 0x400); + } else { + // We're not allowed to reset the perf counters, so take note + // of their current values; we will subtract from this later. + x64_i0 = Processor.ReadPmc(0); + x64_i1 = Processor.ReadPmc(1); + x64_i2 = Processor.ReadPmc(2); + x64_i3 = Processor.ReadPmc(3); + } +#endif + + begCycleCount = unchecked((long)Processor.CycleCount); + } + + public void Finish(long iterations) + { + endCycleCount = unchecked((long)Processor.CycleCount); + +#if X64_PERF + x64_p0 = Processor.ReadPmc(0); + x64_p1 = Processor.ReadPmc(1); + x64_p2 = Processor.ReadPmc(2); + x64_p3 = Processor.ReadPmc(3); +#endif + + endInterruptCount = ProcessService.GetKernelInterruptCount(); + endSwitchCount = ProcessService.GetContextSwitchCount(); + endKernelGcCount = ProcessService.GetKernelGcCount(); + + int collectorCount; + long collectorMillis; + long collectorBytes; + GC.PerformanceCounters(out collectorCount, + out collectorMillis, + out collectorBytes); + endProcessGcCount = collectorCount; + + ulong allocatedCount; + ulong allocatedBytes; + ulong freedCount; + ulong freedBytes; + PageTableService.GetUsageStatistics(out allocatedCount, + out allocatedBytes, + out freedCount, + out freedBytes); + endAllocatedCount = allocatedCount; + endAllocatedBytes = allocatedBytes; + endFreedCount = freedCount; + endFreedBytes = freedBytes; + + ulong stackGets; + ulong stackRets; + StackService.GetUsageStatistics(out stackGets, + out stackRets); + endStackGets = stackGets; + endStackRets = stackRets; + + if (!atRing3) { + Processor.RestoreInterrupts(disabled); + } + + this.iterations = iterations; + } + + public void Display(string name) + { + if (xmlOutput) { + DisplayXml(name); + } else { + DisplayText(name); + } + } + + private static void WriteXmlValue(string name, long value) + { + DualWriteLine( + String.Format(" {0} {1:d} ", name, value) + ); + } + + private static void WriteXmlValue(string name, ulong value) + { + DualWriteLine( + String.Format(" {0} {1:d} ", name, value) + ); + } + + private void DisplayXml(string name) + { + DualWriteLine( + String.Format("", name) + ); + WriteXmlValue("CyclesPerIteration", Cycles / iterations); + WriteXmlValue("Cycles", Cycles); + WriteXmlValue("Iterations", iterations); + WriteXmlValue("Switches", Switches); + WriteXmlValue("Interrupts", Interrupts); + WriteXmlValue("KernelGCs", KernelGCs); + WriteXmlValue("ProcessGCs", ProcessGCs); + WriteXmlValue("AllocationCount", AllocatedCount); + WriteXmlValue("AllocationBytes", AllocatedBytes); + WriteXmlValue("FreedCount", FreedCount); + WriteXmlValue("FreedBytes", FreedBytes); + WriteXmlValue("StackGetCount", StackGets); + WriteXmlValue("StackReturnCount", StackRets); + DualWriteLine(""); + } + + private void DisplayText(string name) + { + DualWriteLine( + String.Format("{0,-16} {1,6:d} x{2,8:d} ={3,12:d} " + + "[swi={4,6:d} int={5,3:d} gc={6:d}/{7:d}]", + name, + iterations, + Cycles / iterations, + Cycles, + Switches, + Interrupts, + KernelGCs, + ProcessGCs) + ); + + if (AllocatedCount > 1 || FreedCount > 1 || StackGets > 1) { + DualWriteLine( + string.Format( + " " + + "[alloc={0,4:d}/{1,8:x} free={2,4:d}/{3,8:x} " + + "stack={4,4:d}/{5,4:d}]", + AllocatedCount, + AllocatedBytes, + FreedCount, + FreedBytes, + StackGets, + StackRets) + ); + } + +#if x64_PERF + if (!atRing3) { + // Read off the current MSR values and turn them + // into nice labels + ulong e0 = Processor.ReadMsr(0xc0010000); + ulong e1 = Processor.ReadMsr(0xc0010001); + ulong e2 = Processor.ReadMsr(0xc0010002); + ulong e3 = Processor.ReadMsr(0xc0010003); + + DualWriteLine( + String.Format("evt: {0,16} {1,16} {2,16} {3,16}", + EvtSelToString(e0), + EvtSelToString(e1), + EvtSelToString(e2), + EvtSelToString(e3))); + } else { + // Subtract from the initial perf-counter values to + // get the delta we want + x64_p0 -= x64_i0; + x64_p1 -= x64_i1; + x64_p2 -= x64_i2; + x64_p3 -= x64_i3; + } + + DualWriteLine( + String.Format("pmc: {0:d16} {1:d16} {2:d16} {3:d16} {4:d16}\n\n", + Cycles, x64_p0, x64_p1, x64_p2, x64_p3)); +#endif + } + + private static void DualWriteLine(string message) + { + Console.WriteLine(message); + DebugStub.WriteLine(message); + } + + public static void SetOptions(bool ring3, bool doXmlOutput) + { + PerfSnap.atRing3 = ring3; + PerfSnap.xmlOutput = doXmlOutput; + } + } +} diff --git a/base/Applications/Security/bvt/SecBVT.sg b/base/Applications/Security/bvt/SecBVT.sg new file mode 100644 index 0000000..0c47f27 --- /dev/null +++ b/base/Applications/Security/bvt/SecBVT.sg @@ -0,0 +1,284 @@ +//////////////////////////////////////////////////////////////////////$ +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: SecBVT.cs +// +// Note: Singularity access control micro-benchmark program. +// + +using System; +using System.Collections; +using System.Text; +using Microsoft.Contracts; + +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity; +using Microsoft.Singularity.Security; +using Microsoft.Singularity.Security.AccessControl; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Configuration; + +[assembly: Transform(typeof(ApplicationResourceTransform))] +[assembly: ApplicationPublisherAttribute("singularity.microsoft.com")] +[assembly: AssertPrivilegeAttribute("$test-privilege.localhost")] +[assembly: AssertPrivilegeAttribute("$register-privilege.localhost")] + +namespace Microsoft.Singularity.Applications +{ + [ConsoleCategory(DefaultAction=true)] + internal class Parameters + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef ImpRef; + + reflective internal Parameters(); + + internal int AppMain() { + return SecBVT.AppMain(this); + } + } + + + /* + * This is a simple program to test access control functionality.using Microsoft.Singularity.Security; + + * + * It tests: + * a) Run the test under a role to ensure that roles work. + * b) Endpoint functionality + * b1) Obtaining the principal ids of channel endpoints. + * b2) Obtaining the principal names of channel endpoints + * c) That the acl cache implementation still works. + * d) Basic ACL/SecurityService functionality.a-zA-Z1-90_ + */ + + public class SecBVT + { + + AclCore! aclCore; + AclConverter! converter; + Parameters! config; + + SecBVT (Parameters! _config) { + config = _config; + AclCore _aclCore = new AclCore(null, new MyAclCoreSupport()); + aclCore = _aclCore; + converter = _aclCore.Converter; + } + + private static void DualWriteLine(string message) + { + Console.WriteLine(message); + DebugStub.WriteLine(message); + } + + private static void DualWrite(string message) + { + Console.Write(message); + DebugStub.Print(message); + } + + private static void DualWrite1(string format, string! s1) + { + Console.Write(format, s1); + DebugStub.Print(format, __arglist(s1)); + } + + private static void DualWrite2(string format, string! s1, string! s2) + { + Console.Write(format, s1, s2); + DebugStub.Print(format, __arglist(s1,s2)); + } + + private static void DualWrite3(string format, string! s1, string! s2, string! s3) + { + Console.Write(format, s1, s2, s3); + DebugStub.Print(format, __arglist(s1,s2,s3)); + } + + private static void DualWrite4(string format, string! s1, string! s2, string! s3, string! s4) + { + Console.Write(format, s1, s2, s3, s4); + DebugStub.Print(format, __arglist(s1,s2,s3,s4)); + } + + internal static int AppMain(Parameters! _config) + { + SecBVT test = new SecBVT(_config); + test.EndpointTest(); + test.SimpleAclTest(); + test.FullAclTest(); + test.CachePerfTest(); + return 0; + } + + private void EndpointTest() + { + DualWriteLine("[Running endpoint test]"); + + KeyboardDeviceContract.Imp! chan = config.ImpRef.Acquire(); + Principal p = AclCore.EndpointPeer(chan); + config.ImpRef.Release(chan); + + Principal self = Principal.Self(); + DualWrite2("Our ep: id={0}, name={1}\n", (!)(self.Val.ToString()), self.GetName()); + DualWrite2("Peer ep: id={0}, name={1}\n", (!)(p.Val.ToString()), p.GetName()); + } + + public class MyAclCoreSupport: IAclCoreSupport + { + Hashtable expnTable; + + [NotDelayed] + public MyAclCoreSupport() { + expnTable = new Hashtable(); + base(); + expnTable["/test-exp-1"] = "{$any}+(test1|test2|test3|test4|SecBVT.!)"; + expnTable["/test-exp-2a"] = "test5|test6|test7|test8"; + expnTable["/test-exp-2b"] = "test9|test10|test11|test12"; + expnTable["/test-exp-2c"] = "test13|test14|test15|test16|(SecBVT.!)"; + expnTable["/test-exp-2"] = "{$any}+({/test-exp-2c})"; + expnTable["/test-exp-3"] = "{$any}+({/test-exp-2a}|{/test-exp-2b}|{/test-exp-2c})"; + } + + public string Expand(string! path) + { + return (string) expnTable[path]; + } + } + + private void SimpleAclTest() + { + DualWriteLine("[Running endpoint test]"); + + KeyboardDeviceContract.Imp! chan = config.ImpRef.Acquire(); + Principal p = AclCore.EndpointPeer(chan); + config.ImpRef.Release(chan); + + string[] resources = new string[]{"{$any}", + "{$anyuser}"}; + bool[] correct = new bool[]{true, false}; + + int i = 0; + foreach (string! resource in resources) + { + + bool result = aclCore.CheckAccess(resource, null, p); + + DualWrite4("Acl: {0}, Principal: {1}, Result: {2} ... {3}\n", + resource, p.GetName(), result.ToString(), + (result==correct[i])?"OK":"failed"); + i++; + } + } + + private void FullAclTest() + { + DualWriteLine("[Running full ACL test]"); + + Principal p = Principal.Self(); + AccessMode mode = new AccessMode("write"); + string[] resources = new string[]{"{$anyall}", + "{$anyuserall}", + "{$any}@(write|read)", + "{$any}@write", + "{$any}@read", + "{$any}+{$test-privilege}@!", + "{$any}+{$test-privilege}@read", + "{$any}+{$test-privilege}@write", + "!@!+!+{$test-privilege}@!", + "!@!(+!)*+{$test-privilege}@!", + "!@!(+!)*+!.microsoft.com@!", + "!@!(+!)*+!.adobe.com@!", + "{/test-exp-3}@!", + "{$dsanyrw}|{$dsregister}" + }; + + bool[] correct = new bool[]{true, // {"{$anyall}", + false, // "{$anyuserall}", + true, // "{$any}@write|read", + true, // "{$any}@write", + false, // "{$any}@read", + true, // "{$any}+{$test-privilege}@!", + false, // "{$any}+{$test-privilege}@read", + true, // "{$any}+{$test-privilege}@write", + true, // "!+!+{$test-privilege}@!", + true, // "!(+!)*+{$test-privilege}@!", + true, // "!(+!)*+!.microsoft.com@!", + false, // "!(+!)*+!.adobe.com@!" + true, // "{/test-exp-3}@!" + true // "{$dsanyrw}|{$dsregister}" + }; + + DualWrite(String.Format("Principal: {0}\n", p.GetName())); + DualWrite(String.Format("Mode: {0}\n", mode.Val)); + int i = 0; + foreach (string! resource in resources) + { + bool result = aclCore.CheckAccessBody(resource, mode, p); + DualWrite3( + "Acl: {0}, Result: {1} ... {2}\n", + resource, result.ToString(), (result==correct[i++])?"OK":"failed"); + } + } + + private void CachePerfTest() + { + DualWriteLine("[Running cache performance test]"); + + Principal p = Principal.Self(); + AccessMode mode = new AccessMode("write"); + string[] resources = new string[]{"{$anyuserall}", + "{$any}+{$test-privilege}@write", + "!@!(+!)*+!.microsoft.com@!", + //{$any}+(foo|bar|baz|brot|waste|waste1|waste2|SecBVT.!)@write", + //"{/test-exp-1}@!", + //"{/test-exp-2}@!", + //"{/test-exp-3}@!", + //"{$any}+Failure.!@write", + "{$dsanyrw}", + "{$dsanyrw}|{$dsregister}" + }; + foreach (string! resource in resources) + { + int nSubExprs = 0; + string! aclConv = converter.ConvertTest(resource, out nSubExprs); + DualWrite1("Acl: {0}\n", resource); + DualWrite3("TopLength: {0}, ConvLength: {1}, nSubExprs {2}\n", + resource.Length.ToString(), aclConv.Length.ToString(), nSubExprs.ToString()); + + for (AclCore.CacheLevel level = AclCore.CacheLevel.All; + level <= AclCore.CacheLevel.None; level++) { + + aclCore.ClearStats(); + aclCore.SetCacheLevel(level); + PerfSnap snap = new PerfSnap(); + // warm cache + aclCore.CheckAccessBody(resource, mode, p); + snap.Start(); + try { + for (int i=0; i<1000; i++) { + aclCore.CheckAccessBody(resource, mode, p); + } + } + finally { + snap.Finish(1000); + } + snap.Display(String.Format("CheckAccess({0})", level.ToString())); + } + } + aclCore.SetCacheLevel(AclCore.CacheLevel.All); + } + } +} diff --git a/base/Applications/Security/bvt/bvt.csproj b/base/Applications/Security/bvt/bvt.csproj new file mode 100644 index 0000000..4522470 --- /dev/null +++ b/base/Applications/Security/bvt/bvt.csproj @@ -0,0 +1,32 @@ + + + + + + + Exe + secbvt + true + + + + + + + + + + + + + + + diff --git a/base/Applications/Security/cachetest/CacheTest.csproj b/base/Applications/Security/cachetest/CacheTest.csproj new file mode 100644 index 0000000..c37329a --- /dev/null +++ b/base/Applications/Security/cachetest/CacheTest.csproj @@ -0,0 +1,33 @@ + + + + + + + Exe + CacheTest + ..\..\..\Kernel + + + + + + + + + + + + + + diff --git a/base/Applications/Security/cachetest/CacheTest.sg b/base/Applications/Security/cachetest/CacheTest.sg new file mode 100644 index 0000000..88db3d5 --- /dev/null +++ b/base/Applications/Security/cachetest/CacheTest.sg @@ -0,0 +1,108 @@ +//////////////////////////////////////////////////////////////////////$ +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: CacheTest.sg +// +// Note: Test function of Cache.sg module. +// + +using System; +using System.Text; +using Microsoft.Singularity.Security.AccessControl; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications +{ + [ConsoleCategory(DefaultAction=true)] + internal class Parameters + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal Parameters(); + + internal int AppMain() { + return CacheTest.AppMain(this); + } + } + + + public class CacheTest + { + internal static int AppMain(Parameters! config) + { + Cache cache = new Cache(10, (15*60), 25, ""); + + Console.WriteLine("Populating cache ..."); + cache.AddEntry("removeMe", new ICacheValue(cache, DateTime.MaxValue)); + cache.AddEntry("removeMe2", new ICacheValue(cache, DateTime.MaxValue)); + cache.AddEntry("a", new ICacheValue(cache, DateTime.MaxValue)); + cache.AddEntry("b", new ICacheValue(cache, DateTime.MaxValue)); + cache.AddEntry("c", new ICacheValue(cache, DateTime.MaxValue)); + cache.AddEntry("d", new ICacheValue(cache, DateTime.MaxValue)); + cache.AddEntry("e", new ICacheValue(cache, DateTime.MaxValue)); + cache.AddEntry("f" ,new ICacheValue(cache, DateTime.MaxValue)); + cache.AddEntry("g", new ICacheValue(cache, DateTime.MaxValue)); + cache.AddEntry("h", new ICacheValue(cache, DateTime.MaxValue)); + + Console.Write(DumpCacheToString(cache)); + Console.Write("Next add should remove \"removeMe*\" entries ..."); + cache.AddEntry("i", new ICacheValue(cache, DateTime.MaxValue)); + + string[] keys = new string[]{"a", "b", "c", "d", "e", "f", "g", "h", "i"}; + bool ok = true; + if (cache.GetEntry("RemoveMe") != null || + cache.GetEntry("RemoveMe1") != null) + ok = false; + else { + for (int i=0; i < keys.Length; i++) { + if (cache.GetEntry((!)(keys[i])) == null) + ok = false; + } + } + if (ok) + Console.WriteLine(" OK"); + else + Console.WriteLine(" FAILED!"); + + Console.Write("Testing LRU, accessing: "); + + Random r = new Random(); + + for (int i = 0; i < keys.Length; i++) + { + int n = r.Next() % keys.Length; + Console.Write(((i==0)? "" : ", ") + keys[n]); + cache.GetEntry((!)keys[n]); + } + Console.WriteLine(); + Console.Write(DumpCacheToString(cache)); + + Console.WriteLine("Adding more, to provoke another pruning"); + cache.AddEntry("y", new ICacheValue(cache, DateTime.MaxValue)); + cache.AddEntry("z", new ICacheValue(cache, DateTime.MaxValue)); + Console.Write(DumpCacheToString(cache)); + return 0; + } + + private static string! DumpCacheToString(Cache! cache) + { + StringBuilder sb = new StringBuilder(); + cache.DumpCache(sb); + return sb.ToString(); + } + } +} diff --git a/base/Applications/Security/security.proj b/base/Applications/Security/security.proj new file mode 100644 index 0000000..39754cf --- /dev/null +++ b/base/Applications/Security/security.proj @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/base/Applications/Security/stats/SecStats.sg b/base/Applications/Security/stats/SecStats.sg new file mode 100644 index 0000000..5a5e0cf --- /dev/null +++ b/base/Applications/Security/stats/SecStats.sg @@ -0,0 +1,79 @@ +//////////////////////////////////////////////////////////////////////$ +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: SecStats.sg +// +// Note: Singularity micro-benchmark program. +// +using System; +using System.Collections; +using System.Text; +using System.Threading; +using System.Diagnostics; +using System.Runtime.CompilerServices; + +using Microsoft.Singularity; +using Microsoft.Singularity.Security; +using Microsoft.Singularity.Channels; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications +{ + [ConsoleCategory(DefaultAction=true)] + internal class Parameters + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [BoolParameter( "c", Default=false, HelpMessage="Clean")] + internal bool doClear; + + [BoolParameter( "d", Default=false, HelpMessage="Disable Kernel Stats")] + internal bool doDisable; + + [BoolParameter( "e", Default=false, HelpMessage="Enable Kernel Stats")] + internal bool doEnable; + + reflective internal Parameters(); + + internal int AppMain() { + return StatisticsTool.AppMain(this); + } + } + + public class StatisticsTool + { + internal static int AppMain(Parameters! config) + { + SecurityDiagnostics sd = new SecurityDiagnostics(); + + string s = sd.GetStatistics(); + Console.Write(s); + + if (config.doClear) { + sd.ClearStatistics(); + Console.Write("Statistics cleared.\n"); + } else if (config.doDisable) { + sd.Disable(true); + Console.Write("Kernel ACL checks disabled.\n"); + } else if (config.doEnable) { + sd.Disable(false); + Console.Write("Kernel ACL checks enabled.\n"); + } + return 0; + } + } +} + diff --git a/base/Applications/Security/stats/stats.csproj b/base/Applications/Security/stats/stats.csproj new file mode 100644 index 0000000..66c74c0 --- /dev/null +++ b/base/Applications/Security/stats/stats.csproj @@ -0,0 +1,31 @@ + + + + + + + Exe + secstats + true + + + + + + + + + + + + + + diff --git a/base/Applications/Seditor/SEditor.cs b/base/Applications/Seditor/SEditor.cs new file mode 100644 index 0000000..7efeeff --- /dev/null +++ b/base/Applications/Seditor/SEditor.cs @@ -0,0 +1,1678 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +/////////////////////////////////////////////////////////////////////////////// + +using DirectoryService.Utils; +using FileSystem.Utils; +using System; +using System.Collections; +using System.Text; +using System.Text.RegularExpressions; +using System.ParseNumbers; + +using Microsoft.Singularity; +using System.IO; + +using System.GC; +using System.Runtime.Remoting; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Diagnostics; + +using Microsoft.SingSharp; +using Microsoft.Singularity.Directory; +using DirectoryServices.Utils; +using Microsoft.Singularity.V1.Services; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.FileSystem; +using Microsoft.Singularity.Channels; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications +{ + [ConsoleCategory(HelpMessage="Stream Editor", DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [StringParameter( "filename", Mandatory=true, Position=0, HelpMessage="Name of file.")] + internal string fileName; + + reflective internal Parameters(); + + internal int AppMain() { + SEditor.AppMain(this); + return 0; + } + } + public class SEditor + { + internal static void AppMain(Parameters! config) + { + // constants + string EditorName = "SEditor"; + int szLineCount = 0; + int nIndex = 0; + + //FOR DEBUG + // Console.WriteLine("Number of cmd line params = {0}", args.Length); + + // FOR DEBUG + // Console.WriteLine("args[1] is {0}", args[1]); + string filename = config.fileName; + + string szSrcLine; + ArrayList szContents = new ArrayList(); + + if (File.Exists(filename)) { + FileStream fsInput = new FileStream(filename, FileMode.Open, FileAccess.Read); + StreamReader srInput = new StreamReader(fsInput); + while ((szSrcLine = srInput.ReadLine()) != null) { + szContents.Add(szSrcLine); + // FOR DEBUG + // Console.WriteLine("{0}", szSrcLine); + // Console.ReadLine(); + // END DEBUG + } + srInput.Close(); + fsInput.Close(); + + // Display number of lines loaded + szLineCount = szContents.Count; + Console.WriteLine("* Number of lines read from {0} was {1}", filename, szLineCount); + + // FOR DEBUG ONLY: display contents of file + // for (nIndex = 0; nIndex < szContents.Count; nIndex++) { + // write line to console with numbering + // Console.WriteLine("{0}: {1}", (nIndex + 1), szContents[nIndex]); + // } + } + else if (System.IO.Directory.Exists(filename)) { // check that it's not a directory + Console.WriteLine("Exiting: {0} is a directory.", filename); + Console.WriteLine("Syntax: {0} filename", EditorName); + return; + } + else { // not a directory, but file doesn't exist, so create it + Console.WriteLine("* Creating new file."); + } + + // Command parser - this is the main program loop + Parser(szContents, nIndex, filename); + } // end Main + + + // Parse incoming commands + static void Parser(ArrayList szArray, int pIndex, string InputFileName) + { + //FOR DEBUG + // Console.WriteLine("* Parser called."); + // Console.WriteLine("* Current line index is {0}," pIndex); + Console.Write("* "); + string ParserInput; + string ParserInputFirstChar; + string BackupFileName = ""; + int tempIndex = 0; + ArrayList tempArray = new ArrayList(); + bool IsTextUpdated = false; + int tempSize = 0; + + // build proper backup file name - look for extension if it exists, and replace it with (or add to) ".bak" + if (Path.HasExtension(InputFileName) && (Path.GetExtension(InputFileName) != ".bak")) { // has an extension other than .bak + BackupFileName = Path.ChangeExtension(InputFileName, ".bak"); + } + else if (Path.HasExtension(InputFileName) && (Path.GetExtension(InputFileName) == ".bak")) { // .bak already in use, use something else + Console.WriteLine("{0} ends in .bak - using .ba2 for backup files...", InputFileName); + Console.Write("* "); + BackupFileName = Path.ChangeExtension(InputFileName, ".ba2"); + } + else { // no extension, so add one + BackupFileName = InputFileName + ".bak"; + } + + while (((ParserInput = GetConsoleInput()) != "q") && (ParserInput != "Q") && (ParserInput != null)) { + if (ParserInput != "") { + //FOR DEBUG + //Console.WriteLine("* Input was {0}", ParserInput); + //Console.Write("* "); + + // ParserInputFirstChar = Convert.ToString(ParserInput[0]); + ParserInputFirstChar = ParserInput[0].ToString(); + } + else { + Console.Write("* "); + continue; + } + + // Simple switch based parsing of commands + switch (ParserInputFirstChar) { + case "h": + case "H": + case "?": + Console.WriteLine("* Commands available are:"); + Console.WriteLine("* ?, (h | H) - prints this message"); + Console.WriteLine("* [number] - start editing at line [number]"); + Console.WriteLine("* (a | A) - append lines at end of file"); + Console.WriteLine("* (c | C)[num1],[num2],[destnum] - copy lines from num1 to num2 to dest num"); + Console.WriteLine("* (d | D); (d | D)[num]; (d | D)[num1],[num2] - delete current line, "); + Console.WriteLine("* line at num, lines from num1 to num2"); + Console.WriteLine("* (e | E) - exit, saving changes"); + Console.WriteLine("* (i | I); (i | I)[num] - insert line above current line, or above line num"); + Console.WriteLine("* (l | L); (l | L)[num]; (l | L)[num1],[num2] - list the whole file, "); + Console.WriteLine("* list the line at num, list the lines from num1 to num2"); + Console.WriteLine("* (m | M)[num1],[num2],[destnum] - move lines from num1 to num2 to dest num"); + Console.WriteLine("* (n | N) - print current line number (location in file)"); + Console.WriteLine("* (p | P) - same as l, only displays one page at a time."); + Console.WriteLine("* (q | Q) - quit, saving no changes since last write"); + Console.WriteLine("* (r | R)[num1],([num2] | ?),[searchstr]^[replacestr] - replace"); + Console.WriteLine("* searchstr with replacestr. If ? is used as second param, sub is prompted"); + Console.WriteLine("* (s | S)[num1],([num2] | ?),[searchstr] - search for searchstr. "); + Console.WriteLine("* If ? is used as second param, occurrence is displayed with prompt"); + Console.WriteLine("* until accepted with y, Y, or newline."); + Console.WriteLine("* (t | T)[num],[filename] - insert contents of filename above line num."); + Console.WriteLine("* (w | W) - write contents of memory to filename. Original contents will be"); + Console.WriteLine("* backed up as for exit command."); + break; + case "a": + case "A": + // FOR DEBUG + // Console.WriteLine("* Input was for AppendAtEOF()"); + + tempSize = szArray.Count; + + tempArray = AppendAtEOF(szArray); + + if (tempArray.Count > tempSize) { // array has grown, so assume text modified + IsTextUpdated = true; + } + + szArray = tempArray; + pIndex = tempArray.Count; // move line pointer to the end of the file + + break; + case "c": + case "C": + // FOR DEBUG + // Console.WriteLine("* Input was for CopyLines()"); + if (szArray.Count == 0) { + Console.WriteLine("* No text available to copy - new empty file"); + } + else { + tempArray = CopyLines(szArray, ParserInput, pIndex); + + if (szArray.Count != pIndex) { // assume the array has changed, ergo text modified + IsTextUpdated = true; + } + + szArray = tempArray; + } + + break; + case "d": + case "D": + // FOR DEBUG + // Console.WriteLine("* Input was for DeleteLines()"); + if (szArray.Count == 0) { + Console.WriteLine("* No text available to delete - new empty file"); + } + else { + tempArray = DeleteLines(szArray, ParserInput, pIndex); + + if (szArray.Count != pIndex) { // assume the array has changed, ergo text modified + IsTextUpdated = true; + } + + szArray = tempArray; + + tempIndex = szArray.Count; + + if (tempIndex < pIndex) { // deletion has reduced line count below pIndex - reset the pointer + pIndex = tempIndex; + } + } + + break; + case "e": + case "E": + // FOR DEBUG + // Console.WriteLine("* Input was for Exit ..."); + + if (szArray.Count == 0) { + Console.WriteLine("* No text to save, exiting without write."); + return; + } + else { + Console.WriteLine("* Exiting...."); + EditorWrite(szArray, InputFileName, BackupFileName); + return; + } + + break; + case "i": + case "I": + // FOR DEBUG + // Console.WriteLine("* Input was for InsertAtLine()"); + + // Insert is a special case. The line pointer for the file needs to move + // to the point of insertion if an argument is given, so we will parse that + // here and pass the results, since we need to get the updated array back. + + if (szArray.Count == 0) { + Console.WriteLine("* No lines to insert above - new empty file"); + } + else { + Regex shortr = new Regex(@"^[iI](?<1>\d+)", RegexOptions.Compiled); + Match shortm; + shortm = shortr.Match(ParserInput); + Group shortg1 = shortm.Groups[1]; + + if ((ParserInput == "i") || (ParserInput == "i")) { //insert above current line pointer pIndex + InsertAtLine(szArray, pIndex); + IsTextUpdated = true; + } + else if (shortm.Success) { // we have one line number + //FOR DEBUG + //Console.WriteLine("Line number {0}", shortm.Groups[1]); + + // write out line + Capture shortc1 = shortg1.Captures[0]; + + // tempIndex = Convert.ToInt32(shortc1.Value); + tempIndex = Int32.Parse(shortc1.Value); + if (tempIndex >= 1 && tempIndex <= szArray.Count) { // check for line numbers in range of file + pIndex = tempIndex; // update pIndex + InsertAtLine(szArray, pIndex); + IsTextUpdated = true; + } + else { + Console.WriteLine("* Line number {0} out of range. File length is {1}", tempIndex, szArray.Count); + } + + } + else { + Console.WriteLine("Invalid match"); + } + } + break; + case "l": + case "L": + // FOR DEBUG + //Console.WriteLine("* Input was for ListText()"); + + tempIndex = ListText(szArray, ParserInput, pIndex); + if (tempIndex != -1) { // update current line number if list command moved the pointer + pIndex = tempIndex; + } + break; + case "m": + case "M": + //FOR DEBUG + //Console.WriteLine("* Input was for MoveLines()"); + + if (szArray.Count == 0) { + Console.WriteLine("* No text available to move - new empty file"); + } + else { + tempArray = MoveLines(szArray, ParserInput, pIndex); + + szArray = tempArray; + + IsTextUpdated = true; + } + break; + case "n": + case "N": + //FOR DEBUG + // Console.WriteLine("* Input was for PrintLineNumber()"); + + Console.WriteLine("* {0}", pIndex); + break; + case "p": + case "P": + // FOR DEBUG + // Console.WriteLine("* Input was for PageText()"); + + tempIndex = PageText(szArray, ParserInput, pIndex); + if (tempIndex != -1) { // update current line number if list command moved the pointer + pIndex = tempIndex; + } + + break; + case "r": + case "R": + //FOR DEBUG + // Console.WriteLine("* Input was for ReplaceText()"); + + if (szArray.Count == 0) { + Console.WriteLine("* No text available to replace"); + } + else { + tempArray = ReplaceText(szArray, ParserInput, pIndex); + szArray = tempArray; + IsTextUpdated = true; + } + break; + case "s": + case "S": + //FOR DEBUG + // Console.WriteLine("* Input was for SearchForText()"); + + if (szArray.Count == 0) { + Console.WriteLine("* No text available to search"); + } + else { + tempIndex = SearchForText(szArray, ParserInput, pIndex); + if (tempIndex != -1) { // update current line number if list command moved the pointer + pIndex = tempIndex; + } + } + break; + case "t": + case "T": + // FOR DEBUG + // Console.WriteLine("* Input was for TransferText()"); + + tempArray = TransferText(szArray, ParserInput); + + if (szArray.Count != pIndex) { // assume the array has changed, ergo text modified + IsTextUpdated = true; + } + + szArray = tempArray; + + break; + case "w": + case "W": + // FOR DEBUG + // Console.WriteLine("* Input was for WriteTextToFile()"); + + if (szArray.Count == 0) { + Console.WriteLine("* No text to save."); + } + else { + EditorWrite(szArray, InputFileName, BackupFileName); + IsTextUpdated = false; + } + + break; + case "": + break; + default: + int LineNumber = 0; + + if (szArray.Count == 0) { + Console.WriteLine("* No lines to edit at - new empty file"); + break; + } + else { + + try { + // LineNumber = Convert.ToInt32(ParserInput); + LineNumber = Int32.Parse(ParserInput); + } + catch (System.ArgumentNullException) { + Console.WriteLine("String is null."); + break; + } + catch (System.FormatException) { + Console.WriteLine("* Unrecognized command"); + break; + } + catch (System.OverflowException) { + Console.WriteLine("* Overflow in string to int conversion."); + break; + } + } + + //FOR DEBUG + // Console.WriteLine("* Input was for EditAtLine() - line {0}", LineNumber); + + // update line pointer to LineNumber + pIndex = LineNumber; + + tempArray = EditAtLine(szArray, pIndex); + + szArray = tempArray; + + IsTextUpdated = true; + + break; + } + Console.Write("* "); + } + if (IsTextUpdated == true) { // ask them if they really wanted to quit without writing text out + Console.WriteLine("* WARNING: modified text not saved."); + Console.Write("* Save? (Y/N) "); + + string SaveReply = GetConsoleInput(); + // string SaveReplyFirstChar = Convert.ToString(SaveReply[0]); + if (SaveReply != "") { + string SaveReplyFirstChar = SaveReply[0].ToString(); + switch (SaveReplyFirstChar) { + case "y": + case "Y": + Console.WriteLine("* Exiting...."); + EditorWrite(szArray, InputFileName, BackupFileName); + break; + default: + Console.WriteLine("* Exiting without save."); + break; + } + } + else { + Console.WriteLine("* Exiting without save."); + } + } + + } // end of Parser + + + // ListText - returns updated list pointer as int + static int ListText(ArrayList szArray, string ParserInput, int nIndex) + { + Regex fullr = new Regex(@"^[lL](?<1>\d+),(?<2>\d+)", RegexOptions.Compiled); + Regex shortr = new Regex(@"^[lL](?<1>\d+)", RegexOptions.Compiled); + Match fullm; + Match shortm; + int listSuccess = 0; + int PAGEWIDTH = 72; // allow for line numbers in printouts - up to 99,999. + // TODO: adjust line number range dynamically for large files + int tempwidth = 0; + string workstring = ""; + string tempstring = ""; + int remainder = 0; + int division = 0; + int linesinline = 0; + int leftinstring = 0; + int lowLine = 0; + int hiLine = 0; + + //FOR DEBUGGING + //Console.WriteLine("Current line number is {0}", nIndex); + + fullm = fullr.Match(ParserInput); + shortm = shortr.Match(ParserInput); + Group fullg1 = fullm.Groups[1]; + Group fullg2 = fullm.Groups[2]; + Group shortg1 = shortm.Groups[1]; + + if (fullm.Success) { // we think we have two line numbers, set lowLine and hiLine accordingly + + //FOR DEBUG + //Console.WriteLine("First line number {0}, last line number {1}", fullm.Groups[1], fullm.Groups[2]); + + Capture fullc1 = fullg1.Captures[0]; + Capture fullc2 = fullg2.Captures[0]; + + // int lowLine = Convert.ToInt32(fullc1.Value); + lowLine = Int32.Parse(fullc1.Value) - 1; // offset by one to allow for difference in starting point... + + // int hiLine = Convert.ToInt32(fullc2.Value); + hiLine = Int32.Parse(fullc2.Value); // but leave this one alone, due to the loop + + // test for numbers out of range or out of order + if ((lowLine <= hiLine) && (lowLine >= 0 && lowLine <= szArray.Count) && (hiLine >= 0 && hiLine <= szArray.Count)) { + // continue on to listing... + } + else { // bad arguments + Console.WriteLine("* Malformed arguments to list, or line out of range."); + Console.WriteLine("* lnum1,num2 where num1 <= num2 and num2 <= length of file."); + Console.WriteLine("* File length is {0}.", szArray.Count); + listSuccess = -1; + return listSuccess; + } + } + else if (shortm.Success) { // we have one line number + //FOR DEBUG + //Console.WriteLine("Line number {0}", shortm.Groups[1]); + + // write out line + Capture shortc1 = shortg1.Captures[0]; + + // nIndex = Convert.ToInt32(shortc1.Value); + nIndex = Int32.Parse(shortc1.Value); + + if (nIndex >= 1 && nIndex <= szArray.Count) { // check for line numbers in range of file + lowLine = nIndex - 1; + hiLine = nIndex; + // proceed to listing + } + else { + Console.WriteLine("* Line number {0} out of range. File length is {1}", nIndex, szArray.Count); + listSuccess = -1; + return listSuccess; + } + } + else if ((ParserInput == "l") || (ParserInput == "L")) { // set lowLine = 0, hiLine = szArray.Count + lowLine = 0; + hiLine = szArray.Count; + } + else { + Console.WriteLine("Invalid match"); + listSuccess = -1; + return listSuccess; + } + + // print out buffer contents between lowLine and hiLine + for (nIndex = lowLine; nIndex < hiLine; nIndex++) + { + workstring = szArray[nIndex].ToString(); + tempwidth = workstring.Length; + if (tempwidth > PAGEWIDTH) + { + //FOR DEBUG + //Console.WriteLine(" need to break up line length"); + while (division != 1) + { + linesinline++; + division = tempwidth / PAGEWIDTH; + remainder = tempwidth % PAGEWIDTH; + tempwidth = tempwidth - PAGEWIDTH; + //FOR DEBUG + //Console.WriteLine("remainder = {0}, division = {1}, tempwidth = {2}, linesinline = {3}", remainder, division, tempwidth, linesinline); + //Console.ReadLine(); + } + if (remainder != 0) + { + linesinline++; + //FOR DEBUG + //Console.WriteLine("remainder = {0}, division = {1}, tempwidth = {2}, linesinline = {3}", remainder, division, tempwidth, linesinline); + //Console.ReadLine(); + } + leftinstring = workstring.Length; + while (linesinline > 0) + { + if (leftinstring >= PAGEWIDTH) + { + tempstring = workstring.Substring(workstring.Length - leftinstring, PAGEWIDTH); + } + else + { + tempstring = workstring.Substring(workstring.Length - leftinstring, remainder); + } + Console.WriteLine("{0,5}: {1}", (nIndex + 1), tempstring); + linesinline--; + if (leftinstring > PAGEWIDTH) + { + leftinstring = leftinstring - PAGEWIDTH; + } + } + + // rezero worker constants + remainder = 0; + division = 0; + linesinline = 0; + leftinstring = 0; + listSuccess = 1; + } + else + { + Console.WriteLine("{0,5}: {1}", (nIndex + 1), szArray[nIndex]); + } + + listSuccess = 1; + } + + if (listSuccess == 1) { + return nIndex; // paging worked + } + else { // note: you should never get here + return -1; // bad arguments, don't move line pointer + } + } // end of ListText + + // CopyLines() - returns updated ArrayList with copies done, or the original ArrayList + static ArrayList CopyLines(ArrayList szArray, string ParserInput, int nIndex) + { + Queue copyQueue = new Queue(); + Regex copyr = new Regex(@"^[cC](?<1>\d+),(?<2>\d+),(?<3>\d+)", RegexOptions.Compiled); + Match copym; + + //FOR DEBUGGING + //Console.WriteLine("Current line number is {0}", nIndex); + + copym = copyr.Match(ParserInput); + Group copyg1 = copym.Groups[1]; + Group copyg2 = copym.Groups[2]; + Group copyg3 = copym.Groups[3]; + + if (copym.Success) { // we think we have two line numbers and a dest number + //FOR DEBUG + //Console.WriteLine("First line number {0}, last line number {1}, dest {2}", copym.Groups[1], copym.Groups[2], copym.Groups[3]); + + //Put array elements to be copied into copyQueue + Capture copyc1 = copyg1.Captures[0]; // first line of copy + Capture copyc2 = copyg2.Captures[0]; // last line of copy + + // int lowLine = Convert.ToInt32(copyc1.Value); + int lowLine = Int32.Parse(copyc1.Value); + + // int hiLine = Convert.ToInt32(copyc2.Value); + int hiLine = Int32.Parse(copyc2.Value); + + // test for numbers out of range or out of order + if ((lowLine <= hiLine) && (lowLine >= 1 && lowLine <= szArray.Count) && (hiLine >= 1 && hiLine <= szArray.Count)) { + for (nIndex = lowLine; nIndex <= hiLine; nIndex++) { + //FOR DEBUG + // Console.WriteLine("{0}: {1}", nIndex, szArray[nIndex - 1]); + + copyQueue.Enqueue(szArray[nIndex - 1]); + } + + // check dest num valid + Capture copyc3 = copyg3.Captures[0]; + + // int destLine = Convert.ToInt32(copyc3.Value); + int destLine = Int32.Parse(copyc3.Value); + + if (destLine >= 1 && destLine <= szArray.Count) { + // insert copyQueue at point dest in szArray + // note that due to the indexing offset you need to decrement destLine by 1 here + szArray.InsertRange(destLine - 1, copyQueue); + } + else if (destLine > szArray.Count) { // ask them if they want the copy at the end of the file + Console.Write("* Copy past end of file - do you want block appended? (y/n) "); + string appendReply = GetConsoleInput(); + // string appendReplyFirstChar = Convert.ToString(appendReply[0]); + if (appendReply != "") { + string appendReplyFirstChar = appendReply[0].ToString(); + switch (appendReplyFirstChar) { + case "y": + case "Y": + szArray.AddRange(copyQueue); + break; + default: + Console.WriteLine("* Aborting copy."); + break; + } + } + else { + Console.WriteLine("* Aborting copy."); + } + } + else { + Console.WriteLine("* Invalid copy destination."); + Console.WriteLine("* cnum1,num2,dest where num1 <= num2, num2 and dest <= length of file."); + Console.WriteLine("* File length is {0}.", szArray.Count); + } + } + else { // bad arguments + Console.WriteLine("* Malformed arguments to copy, or line out of range."); + Console.WriteLine("* cnum1,num2 where num1 <= num2, num2 and dest <= length of file."); + Console.WriteLine("* File length is {0}.", szArray.Count); + } + + return szArray; // c[num1,num2,dest] worked + } + else { + Console.WriteLine("Invalid match"); + return szArray; + } + } // end of CopyLines + + // DeleteLines() - returns updated ArrayList with deletes done, or the original ArrayList + static ArrayList DeleteLines(ArrayList szArray, string ParserInput, int nIndex) + { + Regex fullr = new Regex(@"^[dD](?<1>\d+),(?<2>\d+)", RegexOptions.Compiled); + Regex shortr = new Regex(@"^[dD](?<1>\d+)", RegexOptions.Compiled); + Match fullm; + Match shortm; + + //FOR DEBUGGING + //Console.WriteLine("Current line number is {0}", nIndex); + + fullm = fullr.Match(ParserInput); + shortm = shortr.Match(ParserInput); + Group fullg1 = fullm.Groups[1]; + Group fullg2 = fullm.Groups[2]; + Group shortg1 = shortm.Groups[1]; + + if ((ParserInput == "d") || (ParserInput == "D")) { // delete line at current nIndex (which means subtracting 1) + szArray.RemoveAt(nIndex - 1); + + return szArray; + } + else if (fullm.Success) { // we think we have two line numbers + //FOR DEBUG + //Console.WriteLine("First line number {0}, last line number {1}", fullm.Groups[1], fullm.Groups[2]); + + //delete lines between first and second numbers + Capture fullc1 = fullg1.Captures[0]; + Capture fullc2 = fullg2.Captures[0]; + + // int lowLine = Convert.ToInt32(fullc1.Value); + int lowLine = Int32.Parse(fullc1.Value); + + // int hiLine = Convert.ToInt32(fullc2.Value); + int hiLine = Int32.Parse(fullc2.Value); + + // test for numbers out of range or out of order + if ((lowLine <= hiLine) && (lowLine >= 1 && lowLine <= szArray.Count) && (hiLine >= 1 && hiLine <= szArray.Count) && ((hiLine - lowLine) != 0)) { + szArray.RemoveRange(lowLine - 1, ((hiLine - lowLine) + 1)); + } + else { // bad arguments + Console.WriteLine("* Malformed arguments to list, or line out of range."); + Console.WriteLine("* dnum1,num2 where num1 <= num2 and num2 <= length of file."); + Console.WriteLine("* File length is {0}.", szArray.Count); + } + return szArray; // end of d[num1,num] + } + else if (shortm.Success) { // we have one line number + //FOR DEBUG + //Console.WriteLine("Line number {0}", shortm.Groups[1]); + + // delete line + Capture shortc1 = shortg1.Captures[0]; + + // nIndex = Convert.ToInt32(shortc1.Value); + nIndex = Int32.Parse(shortc1.Value); + + if (nIndex >= 1 && nIndex <= szArray.Count) { // check for line numbers in range of file + szArray.RemoveAt(nIndex - 1); + } + else { + Console.WriteLine("* Line number {0} out of range. File length is {1}", nIndex, szArray.Count); + return szArray; + } + return szArray; + } + else { + Console.WriteLine("Invalid match"); + return szArray; + } + } // end of DeleteLines + + // EditAtLine() - edit the line at nIndex in szArray. Since we know the line number, we don't have + // to parse ParserInput here. + static ArrayList EditAtLine(ArrayList szArray, int nIndex) + { + Queue editQueue = new Queue(); + + if (nIndex >= 1 && nIndex <= szArray.Count) { // check that line number is in range of file + Console.WriteLine("{0}: {1}", nIndex, szArray[nIndex - 1]); + Console.Write("> "); + string editInput = GetConsoleInput(); + if (editInput == "") { + return szArray; + } + else { + editQueue.Enqueue(editInput); + szArray.RemoveAt(nIndex - 1); + szArray.InsertRange(nIndex - 1, editQueue); + } + } + else { + Console.WriteLine("* Line number {0} out of range. File length is {1}", nIndex, szArray.Count); + } + return szArray; + } // end of EditAtLine + + + // InsertAtLine() - insert line(s) above nIndex in szArray. Since we know the line number, we don't have + // to parse ParserInput here. + static ArrayList InsertAtLine(ArrayList szArray, int nIndex) + { + Queue insertQueue = new Queue(); + string insertInput = null; + + Console.WriteLine("* Inserting text above {0}: {1}", nIndex, szArray[nIndex - 1]); + Console.WriteLine("* Press ^^ to end input."); + + while (insertInput != "^^") { // Double carat ^^ ends input - would have used control char, but need tty to understand them.... + Console.Write("> "); + insertInput = GetConsoleInput(); + if (insertInput != "^^") { + insertQueue.Enqueue(insertInput); + } + } + szArray.InsertRange(nIndex - 1, insertQueue); + return szArray; + } // end of InsertAtLine + + // AppendAtEOF() - append line(s) below current end of szArray. Since we are appending, we don't have + // to parse ParserInput here. + static ArrayList AppendAtEOF(ArrayList szArray) + { + Queue appendQueue = new Queue(); + string appendInput = null; + + Console.WriteLine("* Appending text at EOF - Press ^^ to end input."); + + while (appendInput != "^^") { // ^^ ends input + Console.Write("> "); + appendInput = GetConsoleInput(); + if (appendInput != "^^") { + appendQueue.Enqueue(appendInput); + } + } + szArray.AddRange(appendQueue); + return szArray; + } // end of AppendAtEOF() + + // MoveLines() - returns updated ArrayList with moves done, or the original ArrayList + static ArrayList MoveLines(ArrayList szArray, string ParserInput, int nIndex) + { + Queue moveQueue = new Queue(); + Regex mover = new Regex(@"^[mM](?<1>\d+),(?<2>\d+),(?<3>\d+)", RegexOptions.Compiled); + Match movem; + + //FOR DEBUGGING + //Console.WriteLine("Current line number is {0}", nIndex); + + movem = mover.Match(ParserInput); + Group moveg1 = movem.Groups[1]; + Group moveg2 = movem.Groups[2]; + Group moveg3 = movem.Groups[3]; + + if (movem.Success) { // we think we have two line numbers and a dest number + //FOR DEBUG + // Console.WriteLine("First line number {0}, last line number {1}, dest {2}", movem.Groups[1], movem.Groups[2], movem.Groups[3]); + + //Put array elements to be moved into moveQueue + Capture movec1 = moveg1.Captures[0]; // first line of move + Capture movec2 = moveg2.Captures[0]; // last line of move + + // int lowLine = Convert.ToInt32(movec1.Value); + int lowLine = Int32.Parse(movec1.Value); + + // int hiLine = Convert.ToInt32(movec2.Value); + int hiLine = Int32.Parse(movec2.Value); + + // test for numbers out of range or out of order + if ((lowLine <= hiLine) && (lowLine >= 1 && lowLine <= szArray.Count) && (hiLine >= 1 && hiLine <= szArray.Count)) { + for (nIndex = lowLine; nIndex <= hiLine; nIndex++) { + //FOR DEBUG + // Console.WriteLine("{0}: {1}", nIndex, szArray[nIndex - 1]); + + moveQueue.Enqueue(szArray[nIndex - 1]); + } + + // check dest num valid + // However, you can't overlap - dest must either be before the block you're moving, or after it. + Capture movec3 = moveg3.Captures[0]; + + // int destLine = Convert.ToInt32(movec3.Value); + int destLine = Int32.Parse(movec3.Value); + + if ((destLine >= 1 && destLine <= szArray.Count) && ((destLine < lowLine) || (destLine) > hiLine)) { + // insert moveQueue at point dest in szArray + // note that due to the indexing offset you need to decrement destLine by 1 here + szArray.InsertRange(destLine - 1, moveQueue); + + // once the insertion is complete, then you can delete the lines from the original + // however, need to be careful about seeing what happened to the original lines - they + // may have moved their indexes in the array depending on where you did the insertion + if (destLine > hiLine) { // indexes stayed the same for the original block - delete it + szArray.RemoveRange(lowLine - 1, ((hiLine - lowLine) + 1)); + } + else { // destLine above lowLine, need to adjust + int padLine = hiLine - lowLine; + szArray.RemoveRange((lowLine + padLine), ((hiLine - lowLine) + 1)); + } + } + else if (destLine > szArray.Count) { // ask them if they want the move at the end of the file + Console.Write("* Move past end of file - do you want block appended? (y/n) "); + string appendReply = GetConsoleInput(); + // string appendReplyFirstChar = Convert.ToString(appendReply[0]); + if (appendReply != "") { + string appendReplyFirstChar = appendReply[0].ToString(); + switch (appendReplyFirstChar) { + case "y": + case "Y": + szArray.AddRange(moveQueue); + // we don't have to worry about the index adjustment here - we can just remove the lines + // from their original location + szArray.RemoveRange(lowLine - 1, ((hiLine - lowLine) + 1)); + break; + default: + Console.WriteLine("* Aborting move."); + break; + } + } + else { + Console.WriteLine("* Aborting move."); + } + } + else { + Console.WriteLine("* Invalid move destination."); + Console.WriteLine("* mnum1,num2,dest where num1 <= num2, num2 and dest <= length of file,"); + Console.WriteLine("* but dest not within num1 - num2 range."); + Console.WriteLine("* File length is {0}.", szArray.Count); + } + } + else { // bad arguments + Console.WriteLine("* Malformed arguments to move, or line out of range."); + Console.WriteLine("* mnum1,num2 where num1 <= num2, num2 and dest <= length of file,"); + Console.WriteLine("* but dest not within num1 - num2 range."); + Console.WriteLine("* File length is {0}.", szArray.Count); + } + return szArray; // m[num1,num2,dest] worked + } + else { + Console.WriteLine("Invalid match"); + return szArray; + } + } // end of MoveLines + + // SearchForText() - returns updated list pointer, since we're not modifying any text + static int SearchForText(ArrayList szArray, string ParserInput, int nIndex) + { + Regex closedsearchr = new Regex(@"^[sS](?<1>\d+),(?<2>\d+),(?<3>.+)", RegexOptions.Compiled); + Regex opensearchr = new Regex(@"^[sS](?<1>\d+),\?,(?<2>.+)", RegexOptions.Compiled); + Match closedsearchm; + Match opensearchm; + + //FOR DEBUGGING + //Console.WriteLine("Current line number is {0}", nIndex); + + closedsearchm = closedsearchr.Match(ParserInput); + opensearchm = opensearchr.Match(ParserInput); + Group closedsearchg1 = closedsearchm.Groups[1]; + Group closedsearchg2 = closedsearchm.Groups[2]; + Group closedsearchg3 = closedsearchm.Groups[3]; + Group opensearchg1 = opensearchm.Groups[1]; + Group opensearchg2 = opensearchm.Groups[2]; + int searchSuccess = 0; + + if (closedsearchm.Success) { // we think we have two line numbers and a search string + //FOR DEBUG + // Console.WriteLine("First line number {0}, last line number {1}, string {2}", closedsearchm.Groups[1], closedsearchm.Groups[2], closedsearchm.Groups[3]); + + Capture closedsearchc1 = closedsearchg1.Captures[0]; + Capture closedsearchc2 = closedsearchg2.Captures[0]; + Capture closedsearchc3 = closedsearchg3.Captures[0]; + + // int lowLine = Convert.ToInt32(closedsearchc1.Value); + int lowLine = Int32.Parse(closedsearchc1.Value); + + // int hiLine = Convert.ToInt32(closedsearchc2.Value); + int hiLine = Int32.Parse(closedsearchc2.Value); + + Regex searchstringr = new Regex(Regex.Escape(closedsearchc3.Value)); + Match searchstringm; + + // test for numbers out of range or out of order + if ((lowLine <= hiLine) && (lowLine >= 1 && lowLine <= szArray.Count) && (hiLine >= 1 && hiLine <= szArray.Count)) { + for (nIndex = lowLine; nIndex <= hiLine; nIndex++) { + //FOR DEBUG + // Console.WriteLine("{0}: {1}", nIndex, szArray[nIndex - 1]); + + // search for the searchstring in the current line + // searchstringm = searchstringr.Match(Regex.Escape(Convert.ToString(szArray[nIndex - 1]))); + searchstringm = searchstringr.Match(Regex.Escape(szArray[nIndex - 1].ToString())); + if (searchstringm.Success) { // found a match + Console.WriteLine("{0}: {1}", nIndex, szArray[nIndex - 1]); + searchSuccess = 1; + break; + } + else { // no match found + //FOR DEBUG + // Console.WriteLine("* No match found"); + searchSuccess = -1; + } + } + } + else { // bad arguments + Console.WriteLine("* Malformed arguments to search, or line out of range."); + Console.WriteLine("* snum1,[num2 | ?],string where num1 <= num2 and"); + Console.WriteLine("* num2 <= length of file. File length is {0}", szArray.Count); + searchSuccess = -1; + } + + if (searchSuccess == 1) { + return nIndex; + } + else { + Console.WriteLine("* No match found"); + return -1; + } + } + else if (opensearchm.Success) { // we have a starting line number and a string + //FOR DEBUG + // Console.WriteLine("First line number {0}, last line number {1}, string {2}", closedsearchm.Groups[1], closedsearchm.Groups[2], closedsearchm.Groups[3]); + + Capture opensearchc1 = opensearchg1.Captures[0]; + Capture opensearchc2 = opensearchg2.Captures[0]; + + // int lowLine = Convert.ToInt32(opensearchc1.Value); + int lowLine = Int32.Parse(opensearchc1.Value); + + Regex searchstringr = new Regex(Regex.Escape(opensearchc2.Value)); + Match searchstringm; + + // test for start number out of range + if (lowLine >= 1 && lowLine <= szArray.Count) { + for (nIndex = lowLine; nIndex <= szArray.Count; nIndex++) { + //FOR DEBUG + // Console.WriteLine("{0}: {1}", nIndex, szArray[nIndex - 1]); + + // search for the searchstring in the current line + // searchstringm = searchstringr.Match(Regex.Escape(Convert.ToString(szArray[nIndex - 1]))); + searchstringm = searchstringr.Match(Regex.Escape(szArray[nIndex - 1].ToString())); + if (searchstringm.Success) { // found a match + Console.WriteLine("{0}: {1}", nIndex, szArray[nIndex - 1]); + Console.Write("O.K.? "); + string searchReply = GetConsoleInput(); + if (searchReply == "") { + searchSuccess = 1; + } + else { + // string searchReplyFirstChar = Convert.ToString(searchReply[0]); + string searchReplyFirstChar = searchReply[0].ToString(); + switch (searchReplyFirstChar) { + case "y": + case "Y": + searchSuccess = 1; + break; + default: + searchSuccess = -1; + break; + } + } + if (searchSuccess == 1) { // found a match, so stop looking (break from the for loop) + break; + } + } + else { // no match found + //FOR DEBUG + // Console.WriteLine("* No match found"); + searchSuccess = -1; + } + } + } else { // bad arguments + Console.WriteLine("* Malformed arguments to search, or line out of range."); + Console.WriteLine("* snum1,[num2 | ?],string where num1 <= num2 and"); + Console.WriteLine("* num2 <= length of file. File length is {0}", szArray.Count); + searchSuccess = -1; + } + + if (searchSuccess == 1) { + return nIndex; + } + else { + Console.WriteLine("* No match found"); + return -1; + } + } + else { // bad match to initial parse of command args + Console.WriteLine("* Malformed arguments to search, or line out of range."); + Console.WriteLine("* snum1,[num2 | ?],string where num1 <= num2 and"); + Console.WriteLine("* num2 <= length of file. File length is {0}", szArray.Count); + return -1; + } + } // end of SearchForText + + // ReplaceText() - returns updated list pointer, since we're not modifying any text + static ArrayList ReplaceText(ArrayList szArray, string ParserInput, int nIndex) + { + Regex closedreplacer = new Regex(@"^[rR](?<1>\d+),(?<2>\d+),(?<3>.+)\^(?<4>.+)", RegexOptions.Compiled); + Regex openreplacer = new Regex(@"^[rR](?<1>\d+),\?,(?<2>.+)\^(?<3>.+)", RegexOptions.Compiled); + Match closedreplacem; + Match openreplacem; + + //FOR DEBUGGING + //Console.WriteLine("Current line number is {0}", nIndex); + + closedreplacem = closedreplacer.Match(ParserInput); + openreplacem = openreplacer.Match(ParserInput); + Group closedreplaceg1 = closedreplacem.Groups[1]; + Group closedreplaceg2 = closedreplacem.Groups[2]; + Group closedreplaceg3 = closedreplacem.Groups[3]; + Group closedreplaceg4 = closedreplacem.Groups[4]; + Group openreplaceg1 = openreplacem.Groups[1]; + Group openreplaceg2 = openreplacem.Groups[2]; + Group openreplaceg3 = openreplacem.Groups[3]; + + if (closedreplacem.Success) { // we think we have two line numbers, a search string, and a replace string + //FOR DEBUG + // Console.WriteLine("First line number {0}, last line number {1}, string {2}, string {3}", closedreplacem.Groups[1], closedreplacem.Groups[2], closedreplacem.Groups[3], closedreplacem.Groups[4]); + + Capture closedreplacec1 = closedreplaceg1.Captures[0]; + Capture closedreplacec2 = closedreplaceg2.Captures[0]; + Capture closedreplacec3 = closedreplaceg3.Captures[0]; + Capture closedreplacec4 = closedreplaceg4.Captures[0]; + + // int lowLine = Convert.ToInt32(closedreplacec1.Value); + int lowLine = Int32.Parse(closedreplacec1.Value); + + // int hiLine = Convert.ToInt32(closedreplacec2.Value); + int hiLine = Int32.Parse(closedreplacec2.Value); + + Regex searchstringr = new Regex(Regex.Escape(closedreplacec3.Value)); + // Match searchstringm; + Regex replacestringr = new Regex(Regex.Escape(closedreplacec4.Value)); + string replaceresult = null; + + // test for numbers out of range or out of order + if ((lowLine <= hiLine) && (lowLine >= 1 && lowLine <= szArray.Count) && (hiLine >= 1 && hiLine <= szArray.Count)) { + for (nIndex = lowLine; nIndex <= hiLine; nIndex++) { + //FOR DEBUG + // Console.WriteLine("{0}: {1}", nIndex, szArray[nIndex - 1]); + + // search for the searchstring in the current line and replace it with the replacement string if found + // replaceresult = Regex.Replace(Convert.ToString(szArray[nIndex - 1]), Convert.ToString(searchstringr), Convert.ToString(replacestringr)); + replaceresult = Regex.Replace(szArray[nIndex - 1].ToString(), searchstringr.ToString(), replacestringr.ToString()); + Queue replaceQueue = new Queue(); + replaceQueue.Enqueue(replaceresult); + szArray.InsertRange(nIndex - 1, replaceQueue); + szArray.RemoveAt(nIndex); + } + } + else { // bad arguments + Console.WriteLine("* Malformed arguments to replace, or line out of range."); + Console.WriteLine("* rnum1,[num2 | ?],string,string where num1 <= num2 and"); + Console.WriteLine("* num2 <= length of file. File length is {0}", szArray.Count); + } + + return szArray; + } + else if (openreplacem.Success) { // we have a starting line number, a search string and a replace string + //FOR DEBUG + // Console.WriteLine("First line number {0}, string {1}, string {2}", openreplacem.Groups[1], openreplacem.Groups[2], openreplacem.Groups[3]); + + Capture openreplacec1 = openreplaceg1.Captures[0]; + Capture openreplacec2 = openreplaceg2.Captures[0]; + Capture openreplacec3 = openreplaceg3.Captures[0]; + + // int lowLine = Convert.ToInt32(openreplacec1.Value); + int lowLine = Int32.Parse(openreplacec1.Value); + + Regex searchstringr = new Regex(Regex.Escape(openreplacec2.Value)); + Match searchstringm; + Regex replacestringr = new Regex(Regex.Escape(openreplacec3.Value)); + string replaceresult = null; + + // test for start number out of range + if (lowLine >= 1 && lowLine <= szArray.Count) { + for (nIndex = lowLine; nIndex <= szArray.Count; nIndex++) { + //FOR DEBUG + // Console.WriteLine("{0}: {1}", nIndex, szArray[nIndex - 1]); + + // search for the searchstring in the current line + // searchstringm = searchstringr.Match(Regex.Escape(Convert.ToString(szArray[nIndex - 1]))); + searchstringm = searchstringr.Match(Regex.Escape(szArray[nIndex - 1].ToString())); + if (searchstringm.Success) { // found a match + Console.WriteLine("{0}: {1}", nIndex, szArray[nIndex - 1]); + Console.Write("O.K.? "); + string replaceReply = GetConsoleInput(); + if (replaceReply == "") { + // replaceresult = Regex.Replace(Convert.ToString(szArray[nIndex - 1]), Convert.ToString(searchstringr), Convert.ToString(replacestringr)); + replaceresult = Regex.Replace(szArray[nIndex - 1].ToString(), searchstringr.ToString(), replacestringr.ToString()); + Queue replaceQueue = new Queue(); + replaceQueue.Enqueue(replaceresult); + szArray.InsertRange(nIndex - 1, replaceQueue); + szArray.RemoveAt(nIndex); + } + else { + // string replaceReplyFirstChar = Convert.ToString(replaceReply[0]); + string replaceReplyFirstChar = replaceReply[0].ToString(); + switch (replaceReplyFirstChar) { + case "y": + case "Y": + // replaceresult = Regex.Replace(Convert.ToString(szArray[nIndex - 1]), Convert.ToString(searchstringr), Convert.ToString(replacestringr)); + replaceresult = Regex.Replace(szArray[nIndex - 1].ToString(), searchstringr.ToString(), replacestringr.ToString()); + Queue replaceQueue = new Queue(); + replaceQueue.Enqueue(replaceresult); + szArray.InsertRange(nIndex - 1, replaceQueue); + szArray.RemoveAt(nIndex); + break; + default: + break; + } + } + } + else { // no match found + //FOR DEBUG + // Console.WriteLine("* No match found"); + } + } + } + else { // bad arguments + Console.WriteLine("* Malformed arguments to replace, or line out of range."); + Console.WriteLine("* rnum1,[num2 | ?],string,string where num1 <= num2 and"); + Console.WriteLine("* num2 <= length of file. File length is {0}", szArray.Count); + } + return szArray; + } + else { // bad match to initial parse of command args + Console.WriteLine("* Malformed arguments to replace, or line out of range."); + Console.WriteLine("* rnum1,[num2 | ?],string,string where num1 <= num2 and"); + Console.WriteLine("* num2 <= length of file. File length is {0}", szArray.Count); + return szArray; + } + } // end of ReplaceText + + static void EditorWrite(ArrayList szArray, string InputFileName, string BackupFileName) + { + int pIndex = 0; + + // check to see if file exists at all, first - if it doesn't, + // we have to create it, but don't have to back it up. + + if (File.Exists(InputFileName)) { // it does exist, ergo we need to back it up + // Test to see if the backup file exists, if it does, delete it (to clear it) + if (File.Exists(BackupFileName)) { + File.Delete(BackupFileName); + } + + // Then, copy the original file to one with bak at the end + File.Copy(InputFileName, BackupFileName, true); + + // Then delete the original file (to clear it) + File.Delete(InputFileName); + + // Then write out the contents of the buffer to our InputFileName + FileStream fsOutput = new FileStream(InputFileName, FileMode.Create, FileAccess.Write); + StreamWriter srOutput = new StreamWriter(fsOutput); + for (pIndex = 0; pIndex < szArray.Count; pIndex++) { + //FOR DEBUG + // Console.WriteLine("* pIndex = {0}, line = {1}", pIndex, szArray[pIndex]); + + srOutput.WriteLine(szArray[pIndex]); + } + srOutput.Close(); + fsOutput.Close(); + return; + } + else { // file didn't exist, so create it, and don't back it up + FileStream fsOutput = new FileStream(InputFileName, FileMode.Create, FileAccess.Write); + StreamWriter srOutput = new StreamWriter(fsOutput); + for (pIndex = 0; pIndex < szArray.Count; pIndex++) { + srOutput.WriteLine(szArray[pIndex]); + } + srOutput.Close(); + fsOutput.Close(); + return; + } + } // end of EditorWrite(); + + // PageText - returns updated list pointer as int + static int PageText(ArrayList szArray, string ParserInput, int nIndex) + { + Regex fullr = new Regex(@"^[pP](?<1>\d+),(?<2>\d+)", RegexOptions.Compiled); + Regex shortr = new Regex(@"^[pP](?<1>\d+)", RegexOptions.Compiled); + Match fullm; + Match shortm; + int listSuccess = 0; + int pageCounter = 0; + string pageReply = ""; + string pageReplyFirstChar = ""; + int PAGELENGTH = 47; // allow for Singularity "activity" line at top of console + int PAGEWIDTH = 72; // allow for line numbers in printouts - up to 99,999. + // TODO: adjust line number range dynamically for large files + int tempwidth = 0; + string workstring = ""; + string tempstring = ""; + int remainder = 0; + int division = 0; + int linesinline = 0; + int leftinstring = 0; + int lowLine = 0; + int hiLine = 0; + + + //FOR DEBUGGING + //Console.WriteLine("Current line number is {0}", nIndex); + + fullm = fullr.Match(ParserInput); + shortm = shortr.Match(ParserInput); + Group fullg1 = fullm.Groups[1]; + Group fullg2 = fullm.Groups[2]; + Group shortg1 = shortm.Groups[1]; + + if (fullm.Success) { // we think we have two line numbers, set lowLine and hiLine accordingly + + //FOR DEBUG + //Console.WriteLine("First line number {0}, last line number {1}", fullm.Groups[1], fullm.Groups[2]); + + Capture fullc1 = fullg1.Captures[0]; + Capture fullc2 = fullg2.Captures[0]; + + // int lowLine = Convert.ToInt32(fullc1.Value); + lowLine = Int32.Parse(fullc1.Value) - 1; // offset by one to allow for difference in starting point... + + // int hiLine = Convert.ToInt32(fullc2.Value); + hiLine = Int32.Parse(fullc2.Value); // but leave this one alone, due to the loop + + // test for numbers out of range or out of order + if ((lowLine <= hiLine) && (lowLine >= 0 && lowLine <= szArray.Count) && (hiLine >= 0 && hiLine <= szArray.Count)) { + // continue on to listing... + } + else { // bad arguments + Console.WriteLine("* Malformed arguments to page, or line out of range."); + Console.WriteLine("* pnum1,num2 where num1 <= num2 and num2 <= length of file."); + Console.WriteLine("* File length is {0}.", szArray.Count); + listSuccess = -1; + return listSuccess; + } + } + else if (shortm.Success) { // we have one line number + //FOR DEBUG + //Console.WriteLine("Line number {0}", shortm.Groups[1]); + + // write out line + Capture shortc1 = shortg1.Captures[0]; + + // nIndex = Convert.ToInt32(shortc1.Value); + nIndex = Int32.Parse(shortc1.Value); + + if (nIndex >= 1 && nIndex <= szArray.Count) { // check for line numbers in range of file + lowLine = nIndex - 1; + hiLine = nIndex; + // proceed to listing + } + else { + Console.WriteLine("* Line number {0} out of range. File length is {1}", nIndex, szArray.Count); + listSuccess = -1; + return listSuccess; + } + } + else if ((ParserInput == "p") || (ParserInput == "P")) { // set lowLine = 0, hiLine = szArray.Count + lowLine = 0; + hiLine = szArray.Count; + } + else { + Console.WriteLine("Invalid match"); + listSuccess = -1; + return listSuccess; + } + + // print out buffer contents between lowLine and hiLine by pages + for (nIndex = lowLine; nIndex < hiLine; nIndex++) + { + workstring = szArray[nIndex].ToString(); + tempwidth = workstring.Length; + if (tempwidth > PAGEWIDTH) + { + //FOR DEBUG + //Console.WriteLine(" need to break up line length"); + while (division != 1) + { + linesinline++; + division = tempwidth / PAGEWIDTH; + remainder = tempwidth % PAGEWIDTH; + tempwidth = tempwidth - PAGEWIDTH; + //FOR DEBUG + //Console.WriteLine("remainder = {0}, division = {1}, tempwidth = {2}, linesinline = {3}", remainder, division, tempwidth, linesinline); + //Console.ReadLine(); + } + if (remainder != 0) + { + linesinline++; + //FOR DEBUG + //Console.WriteLine("remainder = {0}, division = {1}, tempwidth = {2}, linesinline = {3}", remainder, division, tempwidth, linesinline); + //Console.ReadLine(); + } + if (linesinline < (PAGELENGTH - pageCounter)) + { // room to print the whole wrapped line + leftinstring = workstring.Length; + while (linesinline > 0) + { + if (leftinstring >= PAGEWIDTH) + { + tempstring = workstring.Substring(workstring.Length - leftinstring, PAGEWIDTH); + } + else + { + tempstring = workstring.Substring(workstring.Length - leftinstring, remainder); + } + + Console.WriteLine("{0,5}: {1}", (nIndex + 1), tempstring); + pageCounter++; + linesinline--; + if (leftinstring > PAGEWIDTH) + { + leftinstring = leftinstring - PAGEWIDTH; + } + } + } + else if (pageCounter <= PAGELENGTH) + { // less than PAGELENGTH, but not enough room to print the whole wrapped line + leftinstring = workstring.Length; + while (linesinline > 0) + { + if (leftinstring >= PAGEWIDTH) + { + tempstring = workstring.Substring(workstring.Length - leftinstring, PAGEWIDTH); + } + else + { + tempstring = workstring.Substring(workstring.Length - leftinstring, remainder); + } + + Console.WriteLine("{0,5}: {1}", (nIndex + 1), tempstring); + pageCounter++; + linesinline--; + if (leftinstring > PAGEWIDTH) + { + leftinstring = leftinstring - PAGEWIDTH; + } + if (pageCounter > PAGELENGTH) + { + pageCounter = 0; + Console.Write("-- -- "); + pageReply = GetConsoleInput(); + if (pageReply != "") + { + //pageReplyFirstChar = Convert.ToString(pageReply[0]); + pageReplyFirstChar = pageReply[0].ToString(); + switch (pageReplyFirstChar) + { + case "q": + case "Q": + return nIndex + 1; + default: + if (leftinstring >= PAGEWIDTH) + { + tempstring = workstring.Substring(workstring.Length - leftinstring, PAGEWIDTH); + } + else + { + tempstring = workstring.Substring(workstring.Length - leftinstring, remainder); + } + Console.WriteLine("{0,5}: {1}", (nIndex + 1), tempstring); + pageCounter++; + linesinline--; + break; + } + } + } + } + } + // rezero worker constants + remainder = 0; + division = 0; + linesinline = 0; + leftinstring = 0; + listSuccess = 1; + } + else + { + Console.WriteLine("{0,5}: {1}", (nIndex + 1), szArray[nIndex]); + + if (pageCounter < PAGELENGTH) + { + pageCounter++; + } + else + { + pageCounter = 0; + Console.Write("-- -- "); + pageReply = GetConsoleInput(); + if (pageReply != "") + { + //pageReplyFirstChar = Convert.ToString(pageReply[0]); + pageReplyFirstChar = pageReply[0].ToString(); + switch (pageReplyFirstChar) + { + case "q": + case "Q": + return nIndex + 1; + default: + break; + } + } + } + listSuccess = 1; + } + } + + if (listSuccess == 1) { + return nIndex; // paging worked + } + else { // note that you should never get here + return -1; // bad arguments, don't move line pointer + } + } // end of PageText + + // TransferText() - returns updated ArrayList with content merged in from external file, or the original ArrayList + static ArrayList TransferText(ArrayList szArray, string ParserInput) + { + Queue transferQueue = new Queue(); + Regex transferr = new Regex(@"^[tT](?<1>\d+),(?<2>.+)", RegexOptions.Compiled); + Match transferm; + + //FOR DEBUGGING + //Console.WriteLine("Current line number is {0}", nIndex); + + transferm = transferr.Match(ParserInput); + Group transferg1 = transferm.Groups[1]; + Group transferg2 = transferm.Groups[2]; + + if (transferm.Success) { // we think we have a line number and a filename of some sort + //FOR DEBUG + // Console.WriteLine("First line number {0}, filename {1}", transferm.Groups[1], transferm.Groups[2]); + + //Put file contents to be copied into transferQueue + Capture transferc1 = transferg1.Captures[0]; // insertion point + + // int lowLine = Convert.ToInt32(transferc1.Value); + int lowLine = Int32.Parse(transferc1.Value); + + Capture transferc2 = transferg2.Captures[0]; // filename + // string TransferFileName = Convert.ToString(transferc2.Value); + string TransferFileName = transferc2.Value.ToString(); + + if (File.Exists(TransferFileName)) { // file exists, so read it into a buffer + string TransferLine; + ArrayList transferContents = new ArrayList(); + FileStream fsInput = new FileStream(TransferFileName, FileMode.Open, FileAccess.Read); + StreamReader srInput = new StreamReader(fsInput); + while ((TransferLine = srInput.ReadLine()) != null) { + transferContents.Add(TransferLine); + } + srInput.Close(); + fsInput.Close(); + for (int transferIndex = 0; transferIndex < transferContents.Count; transferIndex++) { + //FOR DEBUG + // Console.WriteLine("{0}: {1}", transferIndex, transferContents[transferIndex]); + + transferQueue.Enqueue(transferContents[transferIndex]); + } + } + else { // file to be merged wasn't there + Console.WriteLine("* File to be merged doesn't exist."); + return szArray; + } + + // test for numbers out of range or out of order + if (lowLine >= 1 && lowLine <= szArray.Count) { // + szArray.InsertRange(lowLine - 1, transferQueue); + return szArray; + } + else if (lowLine > szArray.Count) { // check if number is past the end of the file and they want to append + Console.Write("* Transfer past end of file - do you want file appended? (Y/N) "); + + string appendReply = GetConsoleInput(); + // string appendReplyFirstChar = Convert.ToString(appendReply[0]); + if (appendReply != "") { + string appendReplyFirstChar = appendReply[0].ToString(); + switch (appendReplyFirstChar) { + case "y": + case "Y": + szArray.AddRange(transferQueue); + break; + default: + Console.WriteLine("* Aborting transfer."); + break; + } + } + else { + Console.WriteLine("* Aborting transfer."); + } + return szArray; + } + else { // something else is wrong with the insertion point + Console.WriteLine("* Invalid transfer destination."); + Console.WriteLine("* tnum1, filename where num1 is insertion point and filename"); + Console.WriteLine("* is what is to be inserted. File length is {0}.", szArray.Count); + return szArray; + } + } + else {// bad arguments + Console.WriteLine("* Malformed arguments to transfer."); + Console.WriteLine("* tnum1, filename where num1 is insertion point and filename"); + Console.WriteLine("* is what is to be inserted. File length is {0}.", szArray.Count); + return szArray; + } + } // end of TransferText + + static string GetConsoleInput() { // filter Console.ReadLine input for backspaces + string InputString = ""; + string InputCheck = ""; + + InputString = Console.ReadLine(); + if (InputString != "") { + //FOR DEBUG + //Console.WriteLine("* Input was {0}", InputString); + //Console.Write("* "); + // + //for (int i = 0; i < InputString.Length; i++) { + // Console.Write("{0:x}",(int)InputString[i]); + //} + //Console.Write("* "); + // END DEBUG + + // Check for backspace chars and remove them if present, but also delete the character(s) they meant to delete + int j = 0; + string TempString = ""; + for (int i = 0; i < InputString.Length; i++) { + if ((int)InputString[i] != 0x08) { + TempString = string.Concat(InputCheck,InputString[i].ToString()); + InputCheck = TempString; + j++; + } + else { + InputCheck = InputCheck.Remove(j - 1,1); + j--; + } + } + //FOR DEBUG + //Console.WriteLine("* Check was {0}", InputCheck); + //Console.Write("* "); + // + //for (int i = 0; i < InputCheck.Length; i++) { + // Console.Write("{0:x}",(int)InputCheck[i]); + //} + //END DEBUG + + } + return InputCheck; + } // end of GetConsoleInput() + + + } +} + diff --git a/base/Applications/Seditor/Seditor.csproj b/base/Applications/Seditor/Seditor.csproj new file mode 100644 index 0000000..2267108 --- /dev/null +++ b/base/Applications/Seditor/Seditor.csproj @@ -0,0 +1,36 @@ + + + + + + + Exe + SEditor + true + + + + + + + + + + + + + + + + + diff --git a/base/Applications/Seditor/readme.txt b/base/Applications/Seditor/readme.txt new file mode 100644 index 0000000..ad02f0a --- /dev/null +++ b/base/Applications/Seditor/readme.txt @@ -0,0 +1,96 @@ +SEditor - a simple Singularity Editor + +Syntax: seditor filename + +Commands: + +?; (h | H) - prints this message +[number] - start editing at line [number] +(a | A) - append lines at end of file +(c | C)[num1],[num2],[destnum] - copy lines from num1 to num2 to dest num +(d | D); (d | D)[num]; (d | D)[num1],[num2] - delete current line, + line at num, lines from num1 to num2 +(e | E) - exit, saving changes +(i | I); (i | I)[num] - insert line above current line, or above line num +(l | L); (l | L)[num]; (l | L)[num1],[num2] - list the whole file, + list the line at num, list the lines from num1 to num2 +(m | M)[num1],[num2],[destnum] - move lines from num1 to num2 to dest num +(n | N) - print current line number (location in file) +(p | P) - same as l, only displays one page at a time. +(q | Q) - quit, saving no changes since last write +(r | R)[num1],([num2] | ?),[searchstr]^[replacestr] - replace + searchstr with replacestr. If ? is used as second param, sub is prompted +(s | S)[num1],([num2] | ?),[searchstr] - search for searchstr. + If ? is used as second param, occurrence is displayed with prompt + until accepted with y, Y, or newline. +(t | T)[num],filename - insert contents of filename above line num. +(w | W) - write contents of memory to filename. Original contents will be + backed up as for exit command. + +Notes: + +This is a very simple interactive editor, roughly modelled after the MS-DOS "edlin" program. It requires that you provide it a file name (only one) to edit. If it is a new file (i.e., does not exist), seditor will so inform you and will create the file upon exit, if given an exit or write command. It will provide error messages if the name it is given is not a "file" - i.e., if it is a directory or is otherwise not able to be opened and manipulated. Note that it does not attempt to figure out whether the contents of the file, if it exists, are text or not - so if you give it a binary to edit, be prepared for what will likely be erratic (and certainly untested) behavior. + +The console height and width are being treated as fixed constants for the moment. Some obvious "to-dos" include: + + TODO: Dynamically determine height/width + TODO: Recheck display size between pages + in case size has changed. (Lower pri). + TODO: Turn it into some sort of "screen" editor (a la' emacs, + vi, or edit) + TODO: As part of the screen sizing issue - constants were chosen and the + fields are being formatted to permit up to 99,999 lines before the display + is wrong in the list and print commands. Change this so that it dynamically + sizes (though if you'd ever _want_ to edit something that large with a + line editor, one might wonder about your sanity ;-)....) + +The syntax has been been made simple to parse, though perhaps less obvious to use than that of ed or edlin. The basic form is: + +cmd[first line],[second line],[third line] + +or + +cmd[first line],[second line | interrogative (i.e. ?)],[search-pat[^replace-pat]] + +SEditor retains a line counter, so commands will frequently act on the "current" line if given no other arguments. The "current" line pointer is generally updated in commands that deal with moving around in the buffer, but that don't modify text; see below in the "Details on Commands" section for more information. + +Details on Commands, in order: + +? or h | H: prints a help message of the form above. + +[number]: edit at the line given by number. SEditor will print the line out prior to providing you a prompt of the form "> ". It will accept one line of input, which is terminated when you enter a newline. The line pointer will be set to the line you are editing. + +a | A: append lines at the end of the file. If you are editing a "new" file, this is one of the few commands that will permit you to do something meaningful. The line pointer will be set to the "new" end of the file when you execute this command, which is an exception to the general rule noted above that line pointers normally are not reset on actual edit operations. + +c | C[num1],[num2],[destination number]: copy the text starting at line num1 and proceeding through line num2 to, and insert it before the line specified by destination number. If you wish to copy text to the end of the file, give it a number that is greater than the number of lines in your buffer. You will be prompted to confirm the copy operation with a message telling you that you are copying past the current end of the file. The copy command does not update the line pointer. + +d | D; d | D[num1]; d | D[num1],[num2]: the delete command with no arguments will delete the "current" line (i.e. your current position within the buffer). With one argument, it will delete the line you have specified. With two line numbers separated by a comma (no spaces), it will delete the text starting at num1 and proceeding through the line specified by num2. The delete command will not update the line pointer, unless you have shrunken the file buffer to a point below that of the line pointer, at which point it will be set to the current last line. + +e | E: exits, saving any text changed since the last save of the file buffer. If no text has been changed, it will exit without saving text. The original file will be backed up to a file in the same directory with the same filename, but with a different extension - namely, the ".bak" extension. If the backup exists under that name, it will be silently replaced. + +i | I; i | I[num]: insert text before either the "current line" (no arguments), or before the line specified by num. If you wish to append text to the end of the file, use the "a" command, as line numbers out of range of the file will produce an error. Note that the "current" line after this command is executed is whatever you named as the point of insertion. + +l | L; l | L[num1]; l | L[num1],[num2]: with no arguments, list the entire file (with no paging). With one argument, list the line specified by num1. With two arguments, list the file's contents starting at the line specified by num1 and proceeding through num2. The line pointer will be set to the last line listed. + +m | M[num1],[num2],[destination number]: move the text starting at line num1 and proceeding through line num2 to, and insert it before the line specified by destination number. The text you are moving will be deleted from its original position. If you wish to move text to the end of the file, give it a number that is greater than the number of lines in your buffer. You will be prompted to confirm the move operation with a message telling you that you are copying past the current end of the file. The move command does not update the line pointer. + +n | N: print the current line number. + +p | P; p | P[num1]; p | P[num1],[num2]: with no arguments, list the entire file (with paging). At each page, you may choose to continue paging by hitting , or you may quit by hitting or , followed by . With one argument, list the line specified by num1. With two arguments, list the file's contents (with paging) starting at the line specified by num1 and proceeding through num2. The line pointer will be set to the last line listed. + +q | Q; quit, saving no changes since last write. If the file has been changed, you will be prompted in case you wish to abort your "quit" and save your changes. + +r | R[num1],[num2 | ?],[searchstring]^[replacestring]: search for searchstring, starting at the line specified by num1 and proceeding through num2 (if present), and replace the text described by searchstring with replacestring. If the second argument is "?" (instead of num2), you will be prompted if you want to do the replacement until all of the possible replacements have been queried. The replace command will not update the line pointer. + +s | S[num1],[num2 | ?],[searchstring]: search for searchstring, starting at the line specified by num1 and proceeding through num2 (if present. If the second argument is "?" (instead of num2), you will be prompted if this is the correct match. If a match is found, the line pointer will be updated to the line where the match was found. + +t | T[num],[filename]: insert the contents of filename above the line specified by num. If you wish to append the contents of the file being merged to the current file contents, specify a line number that is greater than the current number of lines in the file. You will be prompted, in that case, to proceed (or not) with the transfer. The line pointer will not be changed as a result of this command. + +w | W: write the contents of the file buffer to a file on disk. The original file will be backed up as for the exit command (e). + + + + + + +6/20/2006 \ No newline at end of file diff --git a/base/Applications/ServiceManager/Benchmark/ArgumentJob.sg b/base/Applications/ServiceManager/Benchmark/ArgumentJob.sg new file mode 100644 index 0000000..140a9a0 --- /dev/null +++ b/base/Applications/ServiceManager/Benchmark/ArgumentJob.sg @@ -0,0 +1,113 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Applications\ServiceManager\Benchmark\ArgumentJob.sg +// +// Note: +// +using System; +using System.Threading; +using System.Text; +using Microsoft.SingSharp; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Services; +using Microsoft.Singularity.ServiceManager; + +namespace Microsoft.Singularity.Applications.ServiceManager +{ + internal class ArgumentJob : Job + { + public const int NPatterns = 10; + public const int NSamples = 100; + private ulong[] xchangeRTT = new ulong[NPatterns]; + + internal ArgumentJob(BenchmarkServerInfo! info) + { + base(info); + } + + internal override bool Run() + { + bool success = false; + + BenchmarkContract.Imp:Ready! ep; + if (!Bind(out ep)) { + goto exit; + } + + Console.WriteLine("ArgumentJob start"); + DebugStub.WriteLine("-- ArgumentJob start"); + + for (int i = 0; i < NPatterns; i++) { + success = TestArgumentsHelper(ep, i, out xchangeRTT[i]); + if (!success) { + goto exit; + } + } + + ep.SendEndOfBenchmark(); + switch receive { + case ep.AckEnd(): + break; + case ep.ChannelClosed(): + break; + } + success = true; +exit: + delete ep; + return success; + } + + private bool TestArgumentsHelper(BenchmarkContract.Imp:Ready! ep, + int num, out ulong time) + { + bool success = false; + ulong[] time1 = new ulong[NSamples]; + ulong[] time2 = new ulong[NSamples]; + ulong time3; + + time = 0; + for (int i = 0; i < NSamples; i++) { + if (!Message.SendReceive(ep, num, out time1[i], + out time2[i])) { + success = false; + goto exit; + } + } + + time3 = time2[0] - time1[0]; + for (int i = 1; i < NSamples; i++) { + time3 = (time2[i] - time1[i] + time3) / 2; + } + time = time3; + success = true; +exit: + return success; + } + + public override String! ToString() + { + StringBuilder builder = new StringBuilder(); + + builder.Append("-- Arguments Test Result --\n"); + builder.Append("Average Roundtrip "); + builder.Append("with various number of message arguments ("); + builder.Append(NSamples); + builder.Append(" samples):\n"); + + builder.Append("Args Cycle\n"); + builder.Append("---- -------\n"); + for (int i = 0; i < NPatterns; i++) { + builder.AppendFormat("{0, -4} ", i); + builder.AppendFormat("{0, 7}\n", xchangeRTT[i]); + } + + return builder.ToString(); + } + } +} diff --git a/base/Applications/ServiceManager/Benchmark/CommunicationJob.sg b/base/Applications/ServiceManager/Benchmark/CommunicationJob.sg new file mode 100644 index 0000000..0e672e1 --- /dev/null +++ b/base/Applications/ServiceManager/Benchmark/CommunicationJob.sg @@ -0,0 +1,128 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Applications\ServiceManager\Benchmark\CommunicationJob.sg +// +// Note: +// +using System; +using System.Threading; +using System.Text; +using Microsoft.SingSharp; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Services; +using Microsoft.Singularity.ServiceManager; + +namespace Microsoft.Singularity.Applications.ServiceManager +{ + internal class CommunicationJob : Job + { + private const int MaxSamples = 100; + private ulong[,] time = new ulong[3, MaxSamples]; + private ulong outgoing; + private ulong incoming; + private ulong outTotal; + private ulong inTotal; + + internal CommunicationJob(BenchmarkServerInfo! info) + { + base(info); + } + + internal override bool Run() + { + bool success = false; + ulong time1, time2, time3; + + BenchmarkContract.Imp:Ready! ep; + if (!base.Bind(out ep)) { + success = false; + goto exit; + } + + Console.WriteLine("CommunicationJob start"); + DebugStub.WriteLine("-- CommunicationJob start"); + + time[0, 0] = Processor.GetCycleCount(); + ep.SendGetCycleCount(); + switch receive { + case ep.CycleCount(number): + time[2, 0] = Processor.GetCycleCount(); + time[1, 0] = number; + break; + case ep.ChannelClosed(): + Console.WriteLine("ChannelClosed @ comm\n"); + success = false; + goto exit; + break; + } + + for (int i = 1; i < MaxSamples; i++) { + time[0, i] = Processor.GetCycleCount(); + ep.SendGetCycleCount(); + switch receive { + case ep.CycleCount(number): + time[2, i] = Processor.GetCycleCount(); + time[1, i] = number; + break; + case ep.ChannelClosed(): + Console.WriteLine("ChannelClosed @ comm\n"); + success = false; + goto exit; + break; + } + } + + ep.SendEndOfBenchmark(); + switch receive { + case ep.AckEnd(): + break; + case ep.ChannelClosed(): + break; + } + + for (int i = 0; i < MaxSamples; i++) { + outTotal += (time[1, i] - time[0, i]); + inTotal += (time[2, i] - time[1, i]); + } + outgoing = outTotal / MaxSamples; + incoming = inTotal / MaxSamples; + + success = true; +exit: + delete ep; + return success; + } + + public override String! ToString() + { + StringBuilder builder = new StringBuilder(); + + builder.Append("-- Communication Test Result ("); + builder.Append(MaxSamples); + builder.Append(" samples) --\n"); + builder.Append("No. Cycle Count Cycle Count Cycle Count\n"); + builder.Append("--- ----------- ----------- -----------\n"); + for (int i = 0; i < 10; i++) { + builder.AppendFormat("{0, 3} {1, 11} {2, 11} {3, 11}\n", + i, time[0, i], time[1, i], time[2, i]); + } + builder.Append("\n"); + builder.Append("Direction TotalCycles Average\n"); + builder.Append("--------- ----------- -------\n"); + builder.AppendFormat("Outgoing {0, 11} {1, 7}\n", + outTotal, outgoing); + builder.AppendFormat("Incoming {0, 11} {1, 7}\n", + inTotal, incoming); + builder.AppendFormat("Round-trip {0, 11} {1, 7}\n", + outTotal + inTotal, outgoing + incoming); + + return builder.ToString(); + } + } +} diff --git a/base/Applications/ServiceManager/Benchmark/Job.sg b/base/Applications/ServiceManager/Benchmark/Job.sg new file mode 100644 index 0000000..04727f0 --- /dev/null +++ b/base/Applications/ServiceManager/Benchmark/Job.sg @@ -0,0 +1,66 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Applications\ServiceManager\Benchmark\Job.sg +// +// Note: +// +using System; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Services; + +namespace Microsoft.Singularity.Applications.ServiceManager +{ + internal abstract class Job + { + internal readonly BenchmarkServerInfo! info; + + internal Job(BenchmarkServerInfo! info) + { + this.info = info; + } + + internal abstract bool Run(); + + protected bool Bind(out BenchmarkContract.Imp:Ready! ep) + { + bool success = false; + ErrorCode error; + + BenchmarkContract.Imp! imp; + BenchmarkContract.Exp! exp; + DirectoryServiceContract.Imp ds; + + BenchmarkContract.NewChannel(out imp, out exp); + ds = DirectoryService.NewClientEndpoint(); + if (!SdsUtils.Bind(info.ServiceName, ds, exp, out error)) + { + Console.WriteLine("Binding failed: {0}\n", + SdsUtils.ErrorCodeToString(error)); + success = false; + goto exit; + } + + switch receive + { + case imp.Success(): + success = true; + break; + case imp.ChannelClosed(): + Console.WriteLine("Job: Channel closed.\n"); + success = false; + break; + } +exit: + delete ds; + ep = imp; + + return success; + } + } // class +} diff --git a/base/Applications/ServiceManager/Benchmark/JobSet.sg b/base/Applications/ServiceManager/Benchmark/JobSet.sg new file mode 100644 index 0000000..17dd1b5 --- /dev/null +++ b/base/Applications/ServiceManager/Benchmark/JobSet.sg @@ -0,0 +1,73 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Applications\ServiceManager\Benchmark\JobSet.sg +// +// Note: +// +using System; +using System.Collections; +using Microsoft.SingSharp; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.ServiceManager; +using Microsoft.Singularity.Services; + +namespace Microsoft.Singularity.Applications.ServiceManager +{ + internal class JobSet + { + internal static void Start(BenchmarkServerInfo! info, + TRef! tref) + { + IList modules = new ArrayList(); + + modules.Add(new CommunicationJob(info)); + modules.Add(new ArgumentJob(info)); + modules.Add(new MultiThreadJob(info, tref)); + + DoJob(modules); + Console.WriteLine(info.BinaryName); + Console.WriteLine("===================="); + DebugStub.WriteLine(info.BinaryName); + DebugStub.WriteLine("===================="); + PrintResult(modules); + + modules.Clear(); + } + + private static void DoJob(IList modules) + { + Job job; + + if (modules == null) { + return; + } + + foreach (Object obj in modules) { + if (obj != null) { + job = obj as Job; + if (job != null) { + job.Run(); + } + } + } + } + + private static void PrintResult(IList modules) { + if (modules == null) { + return; + } + + foreach (Object obj in modules) { + if (obj != null) { + Console.WriteLine(obj.ToString()); + DebugStub.WriteLine(obj.ToString()); + } + } + } + } +} diff --git a/base/Applications/ServiceManager/Benchmark/LogBench.csproj b/base/Applications/ServiceManager/Benchmark/LogBench.csproj new file mode 100644 index 0000000..232f435 --- /dev/null +++ b/base/Applications/ServiceManager/Benchmark/LogBench.csproj @@ -0,0 +1,35 @@ + + + + + + + Exe + LogBench + true + + + + + + + + + + + + + + + + + + diff --git a/base/Applications/ServiceManager/Benchmark/LogBenchmark.sg b/base/Applications/ServiceManager/Benchmark/LogBenchmark.sg new file mode 100644 index 0000000..c878ba6 --- /dev/null +++ b/base/Applications/ServiceManager/Benchmark/LogBenchmark.sg @@ -0,0 +1,310 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Applications\ServiceManager\Benchmark\LogBenchmark.sg +// +// Note: +// +using System; +using System.Text; +using System.Threading; +using Microsoft.SingSharp; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Configuration; +using Microsoft.Singularity.Diagnostics.Contracts; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.ServiceManager; +using Microsoft.Singularity.Services; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications.ServiceManager +{ + [ConsoleCategory(HelpMessage="Benchmark client", DefaultAction=true)] + internal class DefaultConfig + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef processRef; + + [Endpoint] + public readonly TRef memoryRef; + + [Endpoint] + public readonly TRef channelRef; + + reflective internal DefaultConfig(); + + internal int AppMain() + { + return LogBenchmark.DefaultMain(this); + } + } + + internal sealed class BenchmarkServerInfo + { + private readonly string! serviceName; + private readonly string! binaryName; + private readonly ServiceType type; + + internal BenchmarkServerInfo(string! serviceName, string! binaryName, + ServiceType type) + { + this.serviceName = serviceName; + this.binaryName= binaryName; + this.type = type; + } + + internal string! ServiceName + { + get { return serviceName; } + private set {} + } + + internal string! BinaryName + { + get { return binaryName; } + private set{} + } + + internal ServiceType Type + { + get { return type; } + private set{} + } + } + + internal sealed class LogBenchmark + { + private BenchmarkServerInfo[] serverList; + + private TRef serverControlRef; + private TRef manageRef; + private TRef processRef; + private TRef memoryRef; + private TRef channelRef; + + internal LogBenchmark(BenchmarkServerInfo[] info, + [Claims]ProcessContract.Imp:Start! pep, + [Claims]MemoryContract.Imp:Start! mep, + [Claims]ChannelContract.Imp:Start! cep) + { + serverList = info; + pep.RecvReady(); + processRef = new TRef(pep); + mep.RecvReady(); + memoryRef = new TRef(mep); + cep.RecvReady(); + channelRef = new TRef(cep); + } + + internal void Start() + { + ServiceControlContract.Imp:Ready! control; + + foreach (BenchmarkServerInfo server in serverList) { + if (server == null) { + continue; + } + + // Launch the benchmark server + if (!StartService(server)) { + return; + } + + // Wait for the server registered. + Thread.Sleep(2000); + + // Start the evaluation + JobSet.Start(server, serverControlRef); + + // shutdown server + if (!StopService()) { + return; + } + Thread.Sleep(2000); + } + } + + private bool StartService(BenchmarkServerInfo! info) + { + bool success = false; + + ServiceInfo* in ExHeap serviceInfo; + ServiceManagementContract.Imp! ep; + ServiceControlContract.Imp! client; + ServiceControlContract.Exp! server; + + Console.Write("Starting service: " + info.ServiceName + " ..."); + GetEndpoint(out ep); + ep.RecvSuccess(); + + Console.Write("."); + ServiceControlContract.NewChannel(out client, out server); + serviceInfo = new [ExHeap] ServiceInfo(0, + info.ServiceName, + info.BinaryName, + info.Type); + ep.SendBind(serviceInfo, server); + switch receive { + case ep.AckBind(): + { + break; + } + case ep.NotFound(rejected): + { + delete rejected; + Console.WriteLine("Doesn't exist."); + goto exit; + break; + } + case ep.PermissionDenied(rejected): + { + delete rejected; + Console.WriteLine("Permission denied"); + goto exit; + break; + } + } + + client.RecvSuccess(); + client.SendStartService(); + switch receive { + case client.RecvAckStartService(): + { + Console.WriteLine(" done."); + success = true; + break; + } + case client.NakStartService(error): + { + Console.WriteLine(" error: " + error); + break; + } + case client.ChannelClosed(): + { + Console.WriteLine(" Channel is closed."); + break; + } + } + +exit: + if (success) { + serverControlRef = + new TRef(client); + manageRef = + new TRef(ep); + } + else { + delete client; + delete ep; + } + return success; + } + + private bool StopService() + { + bool success = false; + ServiceControlContract.Imp! client; + + Console.Write("Stopping service ..."); + + client = serverControlRef.Acquire(); + client.SendStopService(); + switch receive { + case client.AckStopService(): + { + Console.WriteLine(" done."); + success = true; + break; + } + case client.NakStopService(error): + { + Console.WriteLine(" error: " + error); + break; + } + case unsatisfiable: + { + break; + } + } + delete client; + delete manageRef.Acquire(); + return success; + } + + private void GetEndpoint(out ServiceManagementContract.Imp! ep) + { + ErrorCode error; + DirectoryServiceContract.Imp ds; + ServiceManagementContract.Exp! scServer; + ServiceManagementContract.NewChannel(out ep, out scServer); + + ds = DirectoryService.NewClientEndpoint(); + SdsUtils.Bind(ServiceManagementContract.ModuleName, + ds, + scServer, out error); + delete ds; + } + + internal static int DefaultMain(DefaultConfig! config) + { + LogBenchmark bench; + BenchmarkServerInfo[] serverInfo = new BenchmarkServerInfo[4] { + new BenchmarkServerInfo("RBench", "RBenchWorker", + ServiceType.Default), + new BenchmarkServerInfo("RBench", "RBenchWorker", + ServiceType.Resilient), + new BenchmarkServerInfo("RBench", "RBenchHoisted", + ServiceType.Default), + new BenchmarkServerInfo("RBench", "RBenchHoisted", + ServiceType.Resilient), + }; + + StringBuilder builder = new StringBuilder(); + ulong[] time = new ulong[4]; + Object obj; + + for (int i = 0; i < 4; i++) { + time[i] = 0; + } + for (int i = 0; i < 100; i++) { + time[0] += Processor.GetCycleCount(); + obj = new Object(); + time[1] += Processor.GetCycleCount(); + obj.ToString(); + time[2] += Processor.GetCycleCount(); + obj.ToString(); + time[3] += Processor.GetCycleCount(); + } + for (int i = 0; i < 4; i++) { + time[i] /= 100; + } + builder.AppendFormat("New object: {0}\n", time[1] - time[0]); + builder.AppendFormat("ToString1: {0}\n", time[2] - time[1]); + builder.AppendFormat("ToString2: {0}\n", time[3] - time[2]); + + Console.WriteLine(builder.ToString()); + DebugStub.WriteLine(builder.ToString()); + + bench = new LogBenchmark(serverInfo, + config.processRef.Acquire(), + config.memoryRef.Acquire(), + config.channelRef.Acquire()); + bench.Start(); + + return 0; + } + } +} diff --git a/base/Applications/ServiceManager/Benchmark/Message.sg b/base/Applications/ServiceManager/Benchmark/Message.sg new file mode 100644 index 0000000..ea3184c --- /dev/null +++ b/base/Applications/ServiceManager/Benchmark/Message.sg @@ -0,0 +1,150 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Applications\ServiceManager\Benchmark\Message.sg +// +// Note: +// +using System; +using System.Threading; +using System.Text; +using Microsoft.SingSharp; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Services; + +namespace Microsoft.Singularity.Applications.ServiceManager +{ + internal class Message + { + private const int MaxArguments = 9; + private static int[] n = new int[MaxArguments]; + + static Message() + { + Random r = new Random(); + for (int i = 0; i < MaxArguments; i++) { + n[i] = r.Next(); + } + } + + internal static bool SendReceive(BenchmarkContract.Imp:Ready! ep, + int num, + out ulong time1, + out ulong time2) + { + bool success = false; + + time1 = 0; + time2 = 0; + if (n == null) { + return false; + } + + switch (num) { + case 0: + time1 = Processor.GetCycleCount(); + ep.SendNull(); + break; + case 1: + time1 = Processor.GetCycleCount(); + ep.SendOne(n[0]); + break; + case 2: + time1 = Processor.GetCycleCount(); + ep.SendTwo(n[0], n[1]); + break; + case 3: + time1 = Processor.GetCycleCount(); + ep.SendThree(n[0], n[1], n[2]); + break; + case 4: + time1 = Processor.GetCycleCount(); + ep.SendFour(n[0], n[1], n[2], n[3]); + break; + case 5: + time1 = Processor.GetCycleCount(); + ep.SendFive(n[0], n[1], n[2], n[3], n[4]); + break; + case 6: + time1 = Processor.GetCycleCount(); + ep.SendSix(n[0], n[1], n[2], n[3], n[4], n[5]); + break; + case 7: + time1 = Processor.GetCycleCount(); + ep.SendSeven(n[0], n[1], n[2], n[3], n[4], n[5], n[6]); + break; + case 8: + time1 = Processor.GetCycleCount(); + ep.SendEight(n[0], n[1], n[2], n[3], n[4], n[5], n[6], + n[7]); + break; + case 9: + time1 = Processor.GetCycleCount(); + ep.SendNine(n[0], n[1], n[2], n[3], n[4], n[5], n[6], + n[7], n[8]); + break; + default: + time1 = 0; + time2 = 0; + return false; + break; + } + + switch receive { + case ep.AckNull(): + time2 = Processor.GetCycleCount(); + success = true; + break; + case ep.AckOne(num1): + time2 = Processor.GetCycleCount(); + success = true; + break; + case ep.AckTwo(num1, num2): + time2 = Processor.GetCycleCount(); + success = true; + break; + case ep.AckThree(num1, num2, num3): + time2 = Processor.GetCycleCount(); + success = true; + break; + case ep.AckFour(num1, num2, num3, num4): + time2 = Processor.GetCycleCount(); + success = true; + break; + case ep.AckFive(num1, num2, num3, num4, num5): + time2 = Processor.GetCycleCount(); + success = true; + break; + case ep.AckSix(num1, num2, num3, num4, num5, num6): + time2 = Processor.GetCycleCount(); + success = true; + break; + case ep.AckSeven(num1, num2, num3, num4, num5, num6, num7): + time2 = Processor.GetCycleCount(); + success = true; + break; + case ep.AckEight(num1, num2, num3, num4, num5, num6, num7, + num8): + time2 = Processor.GetCycleCount(); + success = true; + break; + case ep.AckNine(num1, num2, num3, num4, num5, num6, num7, + num8, num9): + time2 = Processor.GetCycleCount(); + success = true; + break; + case ep.ChannelClosed(): + Console.WriteLine("Job: Server channel closed.\n"); + success = false; + break; + } + return success; + } + + } // class +} diff --git a/base/Applications/ServiceManager/Benchmark/MultiThreadJob.sg b/base/Applications/ServiceManager/Benchmark/MultiThreadJob.sg new file mode 100644 index 0000000..32fac44 --- /dev/null +++ b/base/Applications/ServiceManager/Benchmark/MultiThreadJob.sg @@ -0,0 +1,325 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Applications\ServiceManager\Benchmark\MultiThreadJob.sg +// +// Note: +// +using System; +using System.Collections; +using System.Text; +using System.Threading; +using Microsoft.SingSharp; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.ServiceManager; +using Microsoft.Singularity.Services; + +namespace Microsoft.Singularity.Applications.ServiceManager +{ + internal sealed class RandomJob : Job + { + private readonly int id; + private bool keepAlive; + private ulong messageCount; + private ulong firstHalf; + private Thread thread; + + [ Microsoft.Contracts.NotDelayed ] + internal RandomJob(BenchmarkServerInfo! info, int tid) + { + base(info); + this.id = tid; + thread = new Thread(new ThreadStart(this.RunThread)); + } + + internal override bool Run() + { + thread.Start(); + return true; + } + + internal void Join() + { + thread.Join(); + } + + internal void Join(int timeout) + { + thread.Join(new TimeSpan(0, 0, 0, timeout)); + } + + internal void RunThread() + { + ulong time1; + ulong time2; + + DebugStub.Print("RandomJob {0} start\n", __arglist(id)); + + BenchmarkContract.Imp:Ready! imp; + if (!Bind(out imp)) { + goto exit; + } + + messageCount = 0; + keepAlive = true; + while (keepAlive) { + imp.SendNull(); + switch receive { + case imp.AckNull(): + break; + case unsatisfiable: + goto exit; + break; + } + messageCount += 2; + } + + /* + imp.SendEndOfBenchmark(); + switch receive { + case imp.AckEnd(): + break; + case imp.ChannelClosed(): + break; + } + */ +exit: + delete imp; + DebugStub.Print("RandomJob {0} stop\n", __arglist(id)); + } + + internal void Stop() + { + keepAlive = false; + } + + internal void SwitchRecord() + { + firstHalf = messageCount; + } + + internal ulong MessageCount + { + get { return messageCount; } + private set {} + } + + internal ulong FirstHalf + { + get { return firstHalf; } + private set{} + } + + internal ulong SecondHalf + { + get {return messageCount - firstHalf; } + private set{} + } + } + + internal sealed class MultiThreadJob : Job + { + private const int Order = 4; + private const int NSamples = 10; + private ulong[,] firstHalf = new ulong[Order, NSamples]; + private ulong[,] totalMessages = new ulong[Order, NSamples]; + private ArrayList jobList; + + private TRef serverRef; + + internal MultiThreadJob(BenchmarkServerInfo! info, + TRef! tref) + { + base(info); + this.jobList = new ArrayList(); + this.serverRef = tref; + } + + internal override bool Run() + { + bool success = false; + + Console.WriteLine("MultiThreadJob start"); + DebugStub.WriteLine("-- MultiThreadJob start"); + + for (int i = 0; i < Order; i++) { + for (int j = 0; j < NSamples; j++) { + CreateJobs(1 << i); + StartJobs(); + Thread.Sleep(5000); + + Start2ndHalf(); + if (base.info.Type == ServiceType.Resilient) { + success = RestartService(); + } + else { + DummyOperation(); + success = true; + } + Thread.Sleep(5000); + DebugStub.WriteLine("Stop jobs..."); + StopJobs(); + CollectResults(i, j); + DebugStub.WriteLine("Delete jobs..."); + DeleteJobs(); + if (!success) { + break; + } + Thread.Sleep(2000); + } + } + return success; + } + + private void CreateJobs(int numberOfJobs) + { + RandomJob job; + + for (int i = 0; i < numberOfJobs; i++) { + job = new RandomJob(base.info, i); + jobList.Add(job); + } + } + + private void StartJobs() + { + RandomJob job; + + foreach (Object obj in jobList) { + if (obj != null) { + job = obj as RandomJob; + if (job != null) { + job.Run(); + } + } + } + } + + private void Start2ndHalf() + { + RandomJob job; + + foreach (Object obj in jobList) { + if (obj != null) { + job = obj as RandomJob; + if (job != null) { + job.SwitchRecord(); + } + } + } + } + + private void StopJobs() + { + RandomJob job; + + foreach (Object obj in jobList) { + if (obj != null) { + job = obj as RandomJob; + if (job != null) { + job.Stop(); + } + } + } + + foreach (Object obj in jobList) { + if (obj != null) { + job = obj as RandomJob; + if (job != null) { + job.Join(2000); + } + } + } + } + + private void DeleteJobs() + { + jobList.Clear(); + } + + private bool RestartService() + { + bool success = false; + + ServiceControlContract.Imp:Ready! ep; + + ep = serverRef.Acquire(); + ep.SendRestartService(); + switch receive { + case ep.AckRestartService(): + { + success = true; + break; + } + case ep.ChannelClosed(): + { + success = false; + break; + } + } + serverRef.Release(ep); + return success; + } + + private void DummyOperation() + { + ServiceControlContract.Imp:Ready! ep; + ep = serverRef.Acquire(); + ep.SendStopPoll(); + switch receive { + case ep.AckStopPoll(): + break; + case ep.ChannelClosed(): + break; + } + serverRef.Release(ep); + } + + private void CollectResults(int order, int sample) + { + RandomJob job; + + foreach (Object obj in jobList) { + if (obj != null) { + job = obj as RandomJob; + if (job != null) { + firstHalf[order, sample] = job.FirstHalf; + totalMessages[order, sample] = job.MessageCount; + } + } + } + } + + public override String! ToString() + { + ulong half, total; + StringBuilder builder = new StringBuilder(); + + builder.Append("-- MultiThread Test (100 samples for each)"); + builder.Append("(5 seconds for each half) --\n"); + builder.Append("Client(s) FirstHalf SecondHalf Total\n"); + builder.Append("--------- --------- ---------- -------\n"); + for (int i = 0; i < Order; i++) { + half = 0; + total = 0; + for (int j = 0; j < NSamples; j++) { + half += firstHalf[i, j]; + total += totalMessages[i, j]; + } + half /= NSamples; + total /= NSamples; + + builder.AppendFormat("{0, -9} {1, 9} {2, 10} {3, 7}\n", + 1 << i, half, total - half, total); + } + builder.Append("\n"); + return builder.ToString(); + } + } +} diff --git a/base/Applications/ServiceManager/Count/Count.csproj b/base/Applications/ServiceManager/Count/Count.csproj new file mode 100644 index 0000000..19ab1cc --- /dev/null +++ b/base/Applications/ServiceManager/Count/Count.csproj @@ -0,0 +1,27 @@ + + + + + + + Exe + Count + + + + + + + + + + + diff --git a/base/Applications/ServiceManager/Count/Count.sg b/base/Applications/ServiceManager/Count/Count.sg new file mode 100644 index 0000000..b89b678 --- /dev/null +++ b/base/Applications/ServiceManager/Count/Count.sg @@ -0,0 +1,89 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Applications\ServiceManager\CountUp\CountUp.sg +// +// Note: +// +using System; +using System.Threading; +using Microsoft.SingSharp; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Configuration; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Services; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications +{ + [ConsoleCategory(HelpMessage="Counter client", DefaultAction=true)] + internal class DefaultConfig + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [LongParameter("interval", Position=0, Default=500)] + internal long interval; + + reflective internal DefaultConfig(); + + internal int AppMain() + { + return CountUp.DefaultMain(this); + } + } + + public class CountUp + { + internal static int DefaultMain(DefaultConfig! config) + { + bool next; + ErrorCode error; + DirectoryServiceContract.Imp ds; + CounterContract.Imp! ep; + CounterContract.Exp! server; + CounterContract.NewChannel(out ep, out server); + + ds = DirectoryService.NewClientEndpoint(); + SdsUtils.Bind(CounterContract.ModuleName, ds, server, out error); + + ep.RecvSuccess(); + + Console.WriteLine("Start count"); + ep.SendBeginCount(); + do { + switch receive { + case ep.RecvCurrent(number): + Console.WriteLine("Count: " + number); + Thread.Sleep((int)config.interval); + ep.SendNext(); + next = true; + break; + case ep.RecvTerminated(): + Console.WriteLine("Terminated..."); + next = false; + break; + case ep.ChannelClosed(): + Console.WriteLine("Channel closed..."); + next = false; + break; + } + } while (next); + + delete ds; + delete ep; + + return 0; + } + } +} diff --git a/base/Applications/ServiceManager/Replace/ReplaceGame.csproj b/base/Applications/ServiceManager/Replace/ReplaceGame.csproj new file mode 100644 index 0000000..122bc57 --- /dev/null +++ b/base/Applications/ServiceManager/Replace/ReplaceGame.csproj @@ -0,0 +1,31 @@ + + + + + + + Exe + ReplaceGame + true + + + + + + + + + + + + + + diff --git a/base/Applications/ServiceManager/Replace/ReplaceGame.sg b/base/Applications/ServiceManager/Replace/ReplaceGame.sg new file mode 100644 index 0000000..6f2ad8e --- /dev/null +++ b/base/Applications/ServiceManager/Replace/ReplaceGame.sg @@ -0,0 +1,399 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Applications\ServiceManager\Replace\ReplaceGame.sg +// +// Note: +// +using System; +using System.Threading; +using Microsoft.SingSharp; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Configuration; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.ServiceManager; +using Microsoft.Singularity.Services; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications +{ + [ConsoleCategory(HelpMessage="Replace Game Client", DefaultAction=true)] + internal class DefaultConfig + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [LongParameter("interval", Default=500)] + internal long interval; + + [BoolParameter("test", Default=true)] + internal bool test; + + reflective internal DefaultConfig(); + + internal int AppMain() + { + return ReplaceGame.DefaultMain(this); + } + } + + internal sealed class ReplaceGame + { + private const int DefaultCount = 50; + private int count; + private String![]! names; + private int self; + private Random! random; + + private const int NumberOfActions = 4; + private enum Action : int { Overwrite, Protect, Score, Pose }; + + private static TRef! controlRef; + private static TRef! manageRef; + + internal ReplaceGame(String![]! competitors, int self) + { + this.count = DefaultCount; + this.names = competitors; + this.self = self; + Thread.Sleep(1); // To get a different seed + this.random = new Random(); + } + + internal void Run() + { + int action; + GamePlayerContract.Imp! ep; + + if (!Connect(out ep)) { + goto exit; + } + + switch receive { + case ep.Success(): + break; + case unsatisfiable: + goto exit; + break; + } + + Score(ep); + Console.WriteLine(names[self] + " start!!"); + try { + while (count-- > 0) { + action = random.Next(NumberOfActions); + switch ((Action)action) { + case Action.Overwrite: + Console.WriteLine(names[self] + " overwrite"); + Overwrite(ep); + break; + case Action.Protect: + Console.WriteLine(names[self] + " protect"); + Protect(ep); + break; + case Action.Score: + Console.WriteLine(names[self] + " score"); + Score(ep); + break; + case Action.Pose: + Pose(); + break; + } + } + Console.WriteLine(names[self] + " end!!"); + Score(ep); + } + catch (Exception e) { + DebugStub.Print(e.ToString()); + } +exit: + delete ep; + } + + private void Overwrite(GamePlayerContract.Imp:Ready! ep) + { + int pos = -1; + DebugStub.Print("Enter overwrite\n"); + + ep.SendSearch(Bitter.FromString2(GetSomeone())); + switch receive { + case ep.AckSearch(position): + pos = position; + break; + case ep.ChannelClosed(): + //throw new ChannelClosedException(); + break; + } + + if (pos >= 0) { + ep.SendOverwrite(Bitter.FromString2(names[self]), pos); + switch receive { + case ep.AckOverwrite(): + break; + case ep.ChannelClosed(): + //throw new ChannelClosedException(); + break; + } + } + DebugStub.Print("Exit overwrite\n"); + } + + private void Protect(GamePlayerContract.Imp:Ready! ep) + { + int pos = -1; + ep.SendSearch(Bitter.FromString2(names[self])); + switch receive { + case ep.AckSearch(position): + pos = position; + break; + case ep.ChannelClosed(): + //throw new ChannelClosedException(); + break; + } + if (pos >= 0) { + ep.SendProtect(pos); + switch receive { + case ep.AckProtect(): + break; + case ep.ChannelClosed(): + //throw new ChannelClosedException(); + break; + } + } + } + + private void Score(GamePlayerContract.Imp:Ready! ep) + { + ep.SendScore(Bitter.FromString2(names[self])); + switch receive { + case ep.AckScore(score): + Console.Write("{0, -10} : {1}\n", names[self], score); + break; + case ep.ChannelClosed(): + //throw new ChannelClosedException(); + break; + } + } + + private void Pose() + { + Thread.Sleep(100); + } + + private String! GetSomeone() + { + int index; + do { + index = random.Next(names.Length); + } while (index == self); + return names[index]; + } + + internal bool Connect(out GamePlayerContract.Imp! ep) + { + DirectoryServiceContract.Imp! ds; + GamePlayerContract.Imp! imp; + GamePlayerContract.Exp! exp; + ErrorCode error; + + ds = DirectoryService.NewClientEndpoint(); + GamePlayerContract.NewChannel(out imp, out exp); + SdsUtils.Bind(GamePlayerContract.ModuleName, ds, exp, out error); + ep = imp; + delete ds; + return (error == ErrorCode.NoError); + } + + //-------------------------------------------------------------------- + // Test Code + //-------------------------------------------------------------------- + + private static bool StartService() + { + bool success = false; + + ServiceInfo* in ExHeap serviceInfo; + ServiceManagementContract.Imp! ep; + ServiceControlContract.Imp! imp; + ServiceControlContract.Exp! exp; + + Console.Write("Starting service: " + + GamePlayerContract.ModuleName + " ..."); + GetEndpoint(out ep); + ep.RecvSuccess(); + + ServiceControlContract.NewChannel(out imp, out exp); + serviceInfo = new [ExHeap] ServiceInfo(0, + GamePlayerContract.ModuleName, + GamePlayerContract.ModuleName, + ServiceType.Resilient); + ep.SendBind(serviceInfo, exp); + switch receive { + case ep.AckBind(): + { + break; + } + case ep.NotFound(rejected): + { + delete rejected; + Console.WriteLine("Doesn't exist."); + goto exit; + break; + } + case ep.PermissionDenied(rejected): + { + delete rejected; + Console.WriteLine("Permission denied"); + goto exit; + break; + } + } + + imp.RecvSuccess(); + imp.SendStartService(); + switch receive { + case imp.RecvAckStartService(): + { + Console.WriteLine(" done."); + success = true; + break; + } + case imp.NakStartService(error): + { + Console.WriteLine(" error: " + error); + break; + } + case imp.ChannelClosed(): + { + Console.WriteLine(" Channel is closed."); + break; + } + } + +exit: + if (success) { + controlRef = + new TRef(imp); + manageRef = + new TRef(ep); + } + else { + delete imp; + delete ep; + } + return success; + } + + private static bool RestartService() + { + bool success = false; + ServiceControlContract.Imp:Ready! ep; + + ep = controlRef.Acquire(); + ep.SendRestartService(); + switch receive { + case ep.AckRestartService(): + { + success = true; + break; + } + case ep.ChannelClosed(): + { + success = false; + break; + } + } + controlRef.Release(ep); + return success; + } + + private static bool StopService() + { + bool success = false; + ServiceControlContract.Imp:Ready! ep; + + Console.Write("Stopping service ..."); + + ep = controlRef.Acquire(); + ep.SendStopService(); + switch receive { + case ep.AckStopService(): + { + Console.WriteLine(" done."); + success = true; + break; + } + case ep.NakStopService(error): + { + Console.WriteLine(" error: " + error); + break; + } + } + delete ep; + delete manageRef.Acquire(); + return success; + } + + private static void GetEndpoint(out ServiceManagementContract.Imp! ep) + { + ErrorCode error; + DirectoryServiceContract.Imp ds; + ServiceManagementContract.Exp! scServer; + ServiceManagementContract.NewChannel(out ep, out scServer); + + DebugStub.Print("GetEndpoint\n"); + ds = DirectoryService.NewClientEndpoint(); + SdsUtils.Bind(ServiceManagementContract.ModuleName, ds, scServer, + out error); + DebugStub.Print("GetEndpoint: {0}\n", __arglist((int)error)); + delete ds; + } + + + internal static int DefaultMain(DefaultConfig! config) + { + // bang! bang! bang! + String![]! names = new String![4] {"Microsoft", "Google", "Yahoo", "Apple"}; + ReplaceGame![]! game = new ReplaceGame![4]; + Thread![]! players = new Thread![4]; + + if (config.test) { + StartService(); + Thread.Sleep(2000); + } + + for (int i = 0; i < 4; i++) { + game[i] = new ReplaceGame(names, i); + players[i] = new Thread(new ThreadStart(game[i].Run)); + } + foreach (Thread! player in players) { + player.Start(); + } + + if (config.test) { + Thread.Sleep(8000); + RestartService(); + } + + foreach (Thread! player in players) { + player.Join(); + } + + if (config.test) { + StopService(); + } + + return 0; + } + } +} diff --git a/base/Applications/ServiceManager/SMSClient/SMSClient.cs b/base/Applications/ServiceManager/SMSClient/SMSClient.cs new file mode 100644 index 0000000..ae62b40 --- /dev/null +++ b/base/Applications/ServiceManager/SMSClient/SMSClient.cs @@ -0,0 +1,313 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Applications\ServiceManager\SMSClient\SMSClient.sg +// +// Note: Service Manager client program +// +using System; +using Microsoft.SingSharp; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Configuration; +using Microsoft.Singularity.Contracts; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.ServiceManager; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications.ServiceManager +{ + [ConsoleCategory(HelpMessage="Service management client", DefaultAction=true)] + internal class DefaultConfig + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal DefaultConfig(); + + internal int AppMain() + { + return SMSClient.DefaultMain(this); + } + } + + [ConsoleCategory(Action="start", HelpMessage="Start a service")] + internal class StartConfig + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [StringParameter("service", Mandatory=true, Position=0)] + internal string service; + + [StringParameter("type", Mandatory=false, Position=1)] + internal string type; + + reflective internal StartConfig(); + + internal int AppMain() + { + return SMSClient.StartService(this); + } + } + + [ConsoleCategory(Action="stop", HelpMessage="Stop a service")] + internal class StopConfig + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + //[StringParameter("service", Mandatory=true, Position=0)] + //internal string service; + + [LongParameter("id", Mandatory=true, Position=0)] + internal long id; + + reflective internal StopConfig(); + + internal int AppMain() + { + return SMSClient.StopService(this); + } + } + + [ConsoleCategory(Action="restart", HelpMessage="Restart a service")] + internal class RestartConfig + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [StringParameter("service", Mandatory=true, Position=0)] + internal string service; + + reflective internal RestartConfig(); + + internal int AppMain() + { + return SMSClient.RestartService(this); + } + } + + [ConsoleCategory(Action="list", HelpMessage="Show a list of services")] + internal class ListConfig + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal ListConfig(); + + internal int AppMain() + { + return SMSClient.ListServices(this); + } + } + + public class SMSClient + { + private static void GetEndpoint(out ServiceManagementContract.Imp! ep) + { + ErrorCode error; + DirectoryServiceContract.Imp ds; + ServiceManagementContract.Exp! scServer; + ServiceManagementContract.NewChannel(out ep, out scServer); + + ds = DirectoryService.NewClientEndpoint(); + SdsUtils.Bind(ServiceManagementContract.ModuleName, ds, + scServer, out error); + delete ds; + } + + internal static int StartService(StartConfig! config) + { + int res = 1; + ServiceType type = ServiceType.Unknown; + ServiceInfo* in ExHeap info; + ServiceManagementContract.Imp! ep; + ServiceControlContract.Imp! client; + ServiceControlContract.Exp! server; + + switch (config.type) + { + case "Resilient": + type = ServiceType.Resilient; + break; + case "Default": + type = ServiceType.Default; + break; + default: + type = ServiceType.Default; + break; + } + + Console.Write("Starting service: " + config.service + " ... "); + GetEndpoint(out ep); + ep.RecvSuccess(); + + ServiceControlContract.NewChannel(out client, out server); + info = new[ExHeap] ServiceInfo(0, config.service, config.service, + type); + ep.SendBind(info, server); + switch receive { + case ep.AckBind(): + break; + case ep.NotFound(rejected): + delete rejected; + Console.WriteLine("Doesn't exist."); + goto exit; + break; + case ep.PermissionDenied(rejected): + delete rejected; + Console.WriteLine("Permission denied"); + goto exit; + break; + } + + client.RecvSuccess(); + client.SendStartService(); + switch receive { + case client.RecvAckStartService(): + Console.WriteLine("done."); + res = 0; + break; + case client.NakStartService(error): + Console.WriteLine("Error code: " + error); + break; + case client.ChannelClosed(): + Console.WriteLine("Channel is closed."); + break; + } +exit: + delete client; + delete ep; + return res; + } + + internal static int StopService(StopConfig! config) + { + int res = 1; + ServiceManagementContract.Imp! ep; + ServiceControlContract.Imp! client; + ServiceControlContract.Exp! server; + + Console.Write("Stopping service: " + config.id + " ... "); + GetEndpoint(out ep); + ep.RecvSuccess(); + + ServiceControlContract.NewChannel(out client, out server); + ep.SendGetControl((int)config.id, server); + switch receive { + case ep.RecvAckGetControl(): + break; + case ep.NotFound(rejected): + delete rejected; + Console.WriteLine("Doesn't exist."); + goto exit; + break; + case ep.PermissionDenied(rejected): + delete rejected; + Console.WriteLine("Permission denied"); + goto exit; + break; + case ep.TryAgain(rejected): + delete rejected; + Console.WriteLine("Busy!"); + goto exit; + break; + } + + client.RecvSuccess(); + client.SendStopService(); + switch receive { + case client.AckStopService(): + Console.WriteLine("done."); + res = 0; + break; + case client.NakStopService(error): + Console.WriteLine("Error code: " + error); + break; + } +exit: + delete client; + delete ep; + return res; + } + + internal static int RestartService(RestartConfig! config) + { + Console.WriteLine("-- Sorry, not implemented yet."); + return 1; + } + + internal static int ListServices(ListConfig! config) + { + bool next = false; + int count = 0; + ServiceManagementContract.Imp! ep; + + GetEndpoint(out ep); + ep.RecvSuccess(); + ep.SendBeginEnumeration(); + + Console.WriteLine(); + Console.WriteLine("PID Task Name"); + Console.WriteLine("=== ==================="); + do { + switch receive { + case ep.RecvCurrent(info): + ++count; + Console.WriteLine("{0,3} {1,-19}", + info->Id, info->Name); + delete info; + ep.SendMoveNext(); + next = true; + break; + case ep.RecvEnumerationTerminated(): + next = false; + break; + case ep.ChannelClosed(): + next = false; + break; + } + } while (next); + Console.WriteLine(); + Console.WriteLine(count + " services are found."); + + delete ep; + return 0; + } + + internal static int DefaultMain(DefaultConfig! config) + { + Console.WriteLine("Usage: svconf [name] [type]"); + Console.WriteLine(" @start Start the service"); + Console.WriteLine(" @stop Stop the service"); + //Console.WriteLine(" @restart Restart the service"); + Console.WriteLine(" @list Show a list of running services"); + Console.WriteLine(" type: Default or Resilient"); + + return 0; + } + } +} + diff --git a/base/Applications/ServiceManager/SMSClient/SMSClient.csproj b/base/Applications/ServiceManager/SMSClient/SMSClient.csproj new file mode 100644 index 0000000..8f459c7 --- /dev/null +++ b/base/Applications/ServiceManager/SMSClient/SMSClient.csproj @@ -0,0 +1,31 @@ + + + + + + + Exe + svconf + true + + + + + + + + + + + + + + diff --git a/base/Applications/ServiceManager/ServiceManager.proj b/base/Applications/ServiceManager/ServiceManager.proj new file mode 100644 index 0000000..3185c57 --- /dev/null +++ b/base/Applications/ServiceManager/ServiceManager.proj @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/base/Applications/ServiceManager/TryEnter/Main.sg b/base/Applications/ServiceManager/TryEnter/Main.sg new file mode 100644 index 0000000..c5d18f7 --- /dev/null +++ b/base/Applications/ServiceManager/TryEnter/Main.sg @@ -0,0 +1,110 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// + +using System; +using System.Threading; +using Microsoft.SingSharp; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Configuration; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Io; + +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications.ServiceManager +{ + [ConsoleCategory(HelpMessage="TryEnter Test", DefaultAction=true)] + internal class DefaultConfig + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal DefaultConfig(); + + internal int AppMain() + { + return Main.AppMain(this); + } + } + + + internal class Worker + { + private Main! parent; + private int id; + + internal Worker(Main! parent, int id) + { + this.parent = parent; + this.id = id; + } + + internal void Run() + { + Console.WriteLine("Thread {0} start\n", id); + for (int i = 0; i < 10; i++) { + parent.Enter(id); + Thread.Sleep(100); + } + Console.WriteLine("Thread {0} end\n", id); + } + } + + internal class Main + { + private Object! mutex = new Object(); + private int count = 0; + + public void Start(int number) + requires number >= 0; + { + Thread![] thread = new Thread![number]; + Worker[] worker = new Worker[number]; + + for (int i = 0; i < number; i++) { + worker[i] = new Worker(this, i); + thread[i] = new Thread(new ThreadStart(worker[i].Run)); + } + + for (int i = 0; i < number; i++) { + thread[i].Start(); + } + + for (int i = 0; i < number; i++) { + thread[i].Join(); + } + } + + internal void Enter(int id) + { + assert mutex != null; + + Console.WriteLine("{0} try enter", id); + if (!Monitor.TryEnter(mutex)) { + // Never reached here + Console.WriteLine("{0} couldn't get monitor", id); + ++count; + return; + } + Console.WriteLine("{0} got monitor", id); + Thread.Sleep(1000); + Monitor.Exit(mutex); + Console.WriteLine("{0} exit (count: {1})", id, count); + } + + internal static int AppMain(DefaultConfig! config) + { + new Main().Start(4); + + return 0; + } + } +} diff --git a/base/Applications/ServiceManager/TryEnter/TryEnterTest.csproj b/base/Applications/ServiceManager/TryEnter/TryEnterTest.csproj new file mode 100644 index 0000000..594c18d --- /dev/null +++ b/base/Applications/ServiceManager/TryEnter/TryEnterTest.csproj @@ -0,0 +1,30 @@ + + + + + + + Exe + TryEnterTest + true + + + + + + + + + + + + + diff --git a/base/Applications/Shell/Breaker.cs b/base/Applications/Shell/Breaker.cs new file mode 100644 index 0000000..91921c7 --- /dev/null +++ b/base/Applications/Shell/Breaker.cs @@ -0,0 +1,65 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Breaker.cs +// +// Note: +// + +using System; +using System.Text; +using System.Runtime.CompilerServices; +using Microsoft.Singularity; + +namespace Microsoft.Singularity.Applications +{ + public class Breaker + { + private static Object ToObject(StringBuilder sb) + { + return (Object)sb; + } + + public static void Break(int how) + { + if (how == 2) { + Console.WriteLine("Breaking into kernel debugger with write to page zero."); + DebugStub.WriteLine("About to write to page zero."); + StringBuilder sb = new StringBuilder(128); + Object o = ToObject(sb); + unsafe { + byte *buffer = null; + *buffer = 0xff; + } + sb = new StringBuilder(256); + DebugStub.WriteLine("sb={0}, o={1}", __arglist(sb, o)); + } + else if (how == 1) { + Console.WriteLine("Breaking into kernel debugger with read from page zero."); + DebugStub.WriteLine("About to read from page zero."); + StringBuilder sb = new StringBuilder(128); + Object o = ToObject(sb); + byte b; + unsafe { + byte *buffer = null; + b = *buffer; + } + sb = new StringBuilder(256); + DebugStub.WriteLine("sb={0}, o={1}, b={2}", __arglist(sb, o, b)); + } + else if (how == 2) { + Console.WriteLine("Breaking into kernel debugger."); + DebugStub.WriteLine("About to break into kernel debugger"); + StringBuilder sb = new StringBuilder(128); + Object o = ToObject(sb); + + DebugStub.Break(); + sb = new StringBuilder(256); + DebugStub.WriteLine("sb={0}, o={1}", __arglist(sb, o)); + } + } + } +} diff --git a/base/Applications/Shell/Logo.bmp b/base/Applications/Shell/Logo.bmp new file mode 100644 index 0000000..45f448d Binary files /dev/null and b/base/Applications/Shell/Logo.bmp differ diff --git a/base/Applications/Shell/Manifest.sg b/base/Applications/Shell/Manifest.sg new file mode 100644 index 0000000..165ef5a --- /dev/null +++ b/base/Applications/Shell/Manifest.sg @@ -0,0 +1,292 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Manifest.cs +// +// Note: Creates and binds endpoints using a manifest. +// + +using System; +using System.Text; +using System.Collections; + +using Microsoft.SingSharp; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Extending; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Memory; +using Microsoft.Singularity.Xml; + +namespace Microsoft.Singularity.Applications +{ + + /// + /// This is a placeholder class for an application's manifest. + /// At present the application manifest is represented by a hashtable. + /// The hashtable has several important properties: + /// - name: the name of the application + /// - path: path to the application executable + /// + public class Manifest + { + /// + /// We treat the application manifest as a collection of + /// key, value pairs. + /// + + + private Hashtable! data = new Hashtable(); + private const string pipeContract = "Microsoft.Singularity.Io.UnicodePipeContract"; + + private string name; + private string path; + + private readonly XmlNode! applicationNode; + private readonly XmlNode! processNode; + private readonly XmlNode actionNode; + private readonly XmlNode categoriesNode; + private readonly XmlNode stringParametersNode; + private readonly XmlNode stringArrayParametersNode; + private readonly XmlNode longParametersNode; + private readonly XmlNode boolParametersNode; + private static StringBuilder sb; + + /// + /// Create a manifest object from the given xml representation + /// + + [Microsoft.Contracts.NotDelayed] + public Manifest(byte[] xml) + { + XmlReader! reader = new XmlReader(xml); + XmlNode! doc = (!)reader.Parse(); + + this(doc); + } + + [Microsoft.Contracts.NotDelayed] + private Manifest(XmlNode! doc) + { + XmlNode app = (!)doc.GetChild("application"); + name = app["name"]; + XmlNode proc = null; + foreach (XmlNode! process in app.Children) { + if (process.Name != "process") { + continue; + } + if (process.GetAttribute("main", "false") == "true") { + path = process["path"]; + proc = process; + break; + } + } + applicationNode = (!)app; + XmlNode! processNode = this.processNode = (!)proc; + base(); + + categoriesNode = processNode.GetChild("categories"); + + if (categoriesNode != null) { + return; + } + else { + DebugStub.WriteLine("::: no category"); + } + } + + public XmlNode GetCategoriesNode() + { + return categoriesNode; + } + + + public void SetProperty(object! name, object value) + { + data[name] = value; + } + + public string Name + { + get { + return name; + } + } + + public string Path + { + get { + return path; + } + } + + public string GetHelpMessage(XmlNode categoryNode) + { + return categoryNode == null? null : categoryNode.GetAttribute("HelpMessage", null); + } + + + // given an action find the corresponding category node + public XmlNode GetCategoryNode(string actionName) { + if (categoriesNode == null) { + //Console.WriteLine("GetCategoryNode: no categories!"); + return null; + } + if (actionName == null) { + // return the 1st one if there is one + //Console.WriteLine("GetCategoryNode: Selecting default!"); + XmlNode n = categoriesNode.GetChild("category"); + if (n == null) { + return null; + } + else return n; + } + else { + foreach (XmlNode! c in categoriesNode.Children) { + string a = c.GetAttribute("Action",null); + //Console.WriteLine("action= {0}.",a); + if ( a != null && a == actionName) { + //Console.WriteLine("found a match for action {0}",actionName); + return c; + } + } + return null; + } + } + + public XmlNode GetBoolParameterNode(XmlNode! category) + { + return category.GetChild("BoolParameters"); + } + + public XmlNode GetStringArrayParameterNode(XmlNode! category) + { + return category.GetChild("StringArrayParameters"); + } + + public XmlNode GetStringParameterNode(XmlNode! category) + { + return category.GetChild("StringParameters"); + } + + public XmlNode GetLongParameterNode(XmlNode! category) + { + return category.GetChild("LongParameters"); + } + + public bool HasParameters() + { + return (categoriesNode != null); + } + +#if false + public void ShowParameters() + { + if (categoryNode == null) { + Console.WriteLine("::: no category"); + return; + } + if (stringParametersNode == null) { + Console.WriteLine("::: no strings"); + } + if (longParametersNode == null) { + Console.WriteLine("::: no integers"); + } + } +#endif + public int SetEndpoints(Process process, string action, bool show) + { + // walk the XmlTree looking endpoints + // these will be used by the binder to setup and transfer to + // the starting process much like what is done for drivers + + XmlNode categoryNode = GetCategoryNode(action); + //Console.WriteLine(" Set endpoints"); + if (categoryNode == null) { + Console.WriteLine("No endpoints in console app!"); + //DebugStub.Break(); + return 0; + } + + XmlNode endpoints = categoryNode.GetChild("endpoints"); + if (endpoints == null) { + //DebugStub.Break(); + return 0; + } + int endpointCount = endpoints.GetAttribute("length", 0); + if (endpointCount == 0) { + DebugStub.Break(); + return 0; + } + + //fill in ep set + foreach (XmlNode! endpoint in endpoints.Children) { + string! contract + = (!)endpoint.GetAttribute("contractName", ""); + int index = endpoint.GetAttribute("id", -1); + + if (endpoint.Name == "endpoint") { + // FIXFIX -- if it is a pipe ignore it for now + if (show) { + Console.WriteLine(" endpoint: {0}", contract); + } + else { + if (contract != pipeContract) { + // get a pre-bound generic endpoint to a service from the + // resource tracker + if (process == null) { + throw new Exception("Process arg was null."); + } + if (!Binder.BindServiceUser(process, index, contract, endpoint)) { + return -1; + } + } + else { + DebugStub.WriteLine("shell.manifest.SetEndpoints: skipping pipe at {0}", __arglist(index)); + } + } + } + } + return endpointCount; + } + +#if false + public override string! ToString() + { + StringBuilder sb = new StringBuilder(); + + sb.AppendFormat("", Name); + + // the main executable + sb.AppendFormat("", Path); + + foreach(DataItem item in data.Values) { + if (item.Directory == null) { + sb.AppendFormat("", + item.Name, item.Value); + } + else { + sb.AppendFormat("", + item.Directory, item.Name, item.Value); + } + } + + sb.Append(""); + sb.Append(""); + sb.Append(""); + sb.Append(""); + + return sb.ToString(); + } + + public byte[] Serialize() + { + return (new UTF8Encoding()).GetBytes(ToString()); + } +#endif + } +} diff --git a/base/Applications/Shell/Parser.cs b/base/Applications/Shell/Parser.cs new file mode 100644 index 0000000..83311d2 --- /dev/null +++ b/base/Applications/Shell/Parser.cs @@ -0,0 +1,233 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +/////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Collections; +using System.Text.RegularExpressions; +using Microsoft.Contracts; + +namespace Microsoft.Singularity.Applications +{ + /** + * This is a general lr parser driver. + * Parses the programming by first lexing it into a number + * of tokens for a token stack. Then parser then pops tokens off + * this stack, consults the parse tables and push the corresponding + * nonterminals and states on the operand stack. This is the same + * algorithm from the dragon book with some tweaks to support optional + * tokens (i.e. newlines). + **/ + abstract class Parser + { + private const int END_INPUT_MARKER_ID = 2; + + protected abstract Action[,]! ActionTable { get; } + protected abstract State[,]! GotoTable { get; } + protected abstract Production[]! ProductionTable { get; } + protected abstract TokenType[]! TokenList { get; } + + + public class ParseException : Exception + { + public ParseException(Token! token, string! error) + : base("Parse error on line " + token.lineNumber + ", char " + token.charIndex + ": " + error) { } + } + + public Object Parse(string! input) + { + Stack leftStack = new Stack(); + leftStack.Push(new State(0)); + + ArrayList list = Lex(ref input); + list.Reverse(); //could return a stack out of lex instead + Stack rightStack = new Stack(list); + while (rightStack.Count != 0) { + State st = (State!)leftStack.Pop(); + Token tok = (Token!)rightStack.Pop(); + Action action = ActionTable[st.id, tok.id]; + while (tok.optional && action == null && rightStack.Count != 0) { + tok = (Token!)rightStack.Pop(); + action = ActionTable[st.id, tok.id]; + } + + if (action == null) { + if (tok.id == END_INPUT_MARKER_ID) { + throw new ParseException(tok, " unexpected EOF"); + } + throw new ParseException(tok, "'" + tok.value + "' unexpected input"); + } + + if (action.type == ActionType.SHIFT) { + leftStack.Push(st); + leftStack.Push(tok); + leftStack.Push(new State(action.stateOrProduction)); + } else if (action.type == ActionType.REDUCE) { + Production production = (!)ProductionTable[action.stateOrProduction]; + Object value = production.Reduction(leftStack); + StackElement topLeft = (StackElement)leftStack.Pop(); + State previousState; + if (topLeft is State) { + previousState = (State)topLeft; + } else { + leftStack.Push(topLeft); + previousState = st; /* took an epsilon transition */ + } + State nextState = GotoTable[previousState.id, production.NonterminalType]; + if (nextState == null) throw new Exception("missing state"); + leftStack.Push(previousState); + leftStack.Push(new Nonterminal(production.NonterminalType, value)); + leftStack.Push(nextState); + rightStack.Push(tok); + } else if (action.type == ActionType.ACCEPT) { + break; + } + } + Nonterminal result = (Nonterminal!)leftStack.Pop(); + return result.value; + } + + private static int CountOccurrences(string! input, char c, out int last) + { + int count = 0; + last = -1; + for (int i = 0; i < input.Length; ++i) { + if (c == input[i]) { + ++count; + last = i; + } + } + return count; + } + + private static bool IsNewLine(char t) { return t == '\n'; } + public ArrayList! Lex(ref string! input) + { + ArrayList tokens = new ArrayList(); + int lineNumber = 1; + int charIndex = 1; + outer: + while (input.Length != 0) { + foreach (TokenType! spec in TokenList) { + Match! match = (!)spec.Regex.Match(input); + if (match == null || !match.Success) continue; + input = input.Remove(0, ((!)match.Value).Length); + if (spec.Lexer != null) { + Token token = new Token(spec.Type, match.Value, lineNumber, charIndex); + spec.Lexer(token); + if (token.value != null) + tokens.Add(token); + } else { + tokens.Add(new Token(spec.Type, match.Value, lineNumber, charIndex)); + } + int lastIndex; + int occurrences = CountOccurrences(match.Value, '\n', out lastIndex); + if (occurrences > 0) { + lineNumber += occurrences; + charIndex = match.Value.Length - (lastIndex + 1); + } else { + charIndex += match.Value.Length; + } + goto outer; + } + throw new Exception("unknown input: " + input); + } + tokens.Add(new Token(END_INPUT_MARKER_ID, null, lineNumber, charIndex)); + return tokens; + } + + public delegate Object Reducer(Stack! stack); + public delegate void Lexer(Token! tok); + + public class Production + { + public readonly int NonterminalType; + public readonly Reducer Reduction; + public Production(int nonterminalType, [Delayed] Reducer reduction) + { + this.NonterminalType = nonterminalType; + this.Reduction = reduction; + } + } + + public class StackElement + { + public readonly int id; + public Object value; + public StackElement(int id) { this.id = id; } + public override string! ToString() + { + return id.ToString(); + } + } + public class State : StackElement + { + public State(int number) : base(number) { } + + } + public class Token : StackElement + { + public readonly int lineNumber; + public readonly int charIndex; + public bool optional = false; + public Token(int type, Object value, int lineNumber, int charIndex) + : base(type) + { + this.value = value; + this.lineNumber = lineNumber; + this.charIndex = charIndex; + this.optional = optional; + } + + public override string! ToString() + { + return value + ":" + id; + } + } + private class Nonterminal : StackElement + { + public Nonterminal(int type, Object value) : base(type) { this.value = value; } + } + + public enum ActionType { SHIFT, REDUCE, ACCEPT } + public class Action + { + public ActionType type; + public int stateOrProduction; + public Action(ActionType type, int stateOrProduction) + { + this.type = type; this.stateOrProduction = stateOrProduction; + } + public override int GetHashCode() + { + return type.GetHashCode() ^ stateOrProduction.GetHashCode(); + } + public override bool Equals(object obj) + { + Action that = obj as Action; + if (that == null) return false; + return this.type == that.type && this.stateOrProduction == that.stateOrProduction; + } + + public override string! ToString() + { + return type + " " + stateOrProduction; + } + } + + protected class TokenType + { + public readonly int Type; + public readonly Regex! Regex; + public readonly Lexer Lexer; + public TokenType(int type, Regex regex, [Delayed] Lexer lexer) + { + this.Type = type; this.Regex = (!)regex; this.Lexer = lexer; + } + } + } +} diff --git a/base/Applications/Shell/README.txt b/base/Applications/Shell/README.txt new file mode 100644 index 0000000..b05f2d2 --- /dev/null +++ b/base/Applications/Shell/README.txt @@ -0,0 +1,198 @@ +Scripting Documentation +----------------------- +This document provides a brief introduction to the script facilities of the shell. + + +Command line arguments +---------------------- +Variables can be passed to a script from the command line and accessed with +$num where num is the number of the shell script variable. The number of +command line variables is given by the $# variable. + + +Comments +-------- +Text following a # on a line is deemed a comment. + + +Data types +---------- +At the moment, the shell only supports primitive types such as integers, booleans, and strings. + + +Variables +--------- +Variables can be assigned to with a simple assignment construct. +For instance, a = 'bc' assigns the string 'bc' to the variable a. +Variables can be referenced by preceding the name with $ (e.q. echo $a) +or with ${name} to separate the reference from surround text such as +b = "surrounding${var}text". References to variables that have not been +previously assigned are considered an error. An error message is printed +and script execution is halted. + + +Operators +--------- + +integer: *, / , %, +, - +string: . (concatenation) +boolean: ||, &&, ! +comparison: <, <=, ==, >=, >. + +The integer operations coerce the +operand types to ints. Therefore, "5" + "9" will call +Int32.ParseInt() on both of these arguments. If one of the operands +to an integer operator is boolean than true is converted to 1 +and false is converted to 0. + +String operators will call ToString on the value for an operand. + +Boolean operators: coerce operand types to booleans. In the case +of integers, an integer equal to 0 is false while all other values +are equivalent to true. For strings, a value is only coercible +if it is either one of Boolean.TrueString (true) or Boolean.FalseString (false) +(case-insensitive). + + +Comparison: +Currently, comparison operators coerce both operands to the type of the left operand +using the methods described thus far. +Stricter and more sensible typing may be implemented in the future. + + +Expressions +----------- +Expressions can be constructed from variables, any of the basic primitive +types and the set of operators. + + +Control Flow +------------ +Language currently supports if, if-else, and while. The conditions to these constructs +are arbitrary expressions that successfully evaluate to a boolean value. Bracing of the statements +for these constructs is required to eliminate ambiguity. + + +Commands +-------- +Unfortunately, commands currently consist of a sequence of alpha-numeric words, a string +literal, interpolation, or integer ending in a new line. Therefore and non-alpha-numeric characters (i.e. %) +must be either placed in a string or interpolation. Hopefully, this will eventually change. + + +Exit and Exit codes +----------- +The exit status of the last command is given by the $? variable. +The built-in exit command takes optionally one integer argument indicating +the exit code of the script execution. If no argument is specified, the status +of the last executed command is returned. If no argument is given and no +commands have been executed, then 0 is returned. This exit builtin differs from +that of the shell prompt. That version performs a shutdown while this +exits the script. + + + +Grammar +------- +SCRIPT => STMT_LIST + +STMT_LIST => STMT + | STMT STMT_LIST + +STMT => while( E ) { STMT_LIST } + | if( E ) { STMT_LIST } + | if( E ) { STMT_LIST } else { STMT_LIST } + | var = E newline + + +E => integer_literal | string_literal | bool_literal | variable_reference | interpolation + | E + E | E - E | E * E | E % E | + | E < E | E <= E | E == E | E >= E | E > E + | E . E + | E && E | E || E | !E + + +COMMAND_LINE=> COMMAND_LIST newline + +COMMAND_LIST => COM + | COM COMMAND_LIST + +COM => word + | variable_reference + | integer_literal + | string_literal + | interpolation + +Example (test script from Shell.sg ) +------------------------------------ +echo $2 #echo second argument +decho $2 +echo number of arguments '=' $# +decho number of arguments '=' $# + +echo last command exit code '=' $? +decho last command exit code '=' $? +if (true) { + variable = false + if ($variable) { + var2 = true + echo broken conditional + decho broken conditional + } + else { + var2 = true + output1 = "bet${variable}ween" + echo $output1 + decho $output1 + } + #some comments # + # + decho var2 is $var2 + add = -2 + 4 + echo '-2 + 4 =' $add + decho '-2 + 4 =' $add + + mod = 6 % 5 + echo '6 % 5 =' $mod + decho '6 % 5 =' $mod + + div = 10 / 5 + echo '10 / 5 =' $div + decho '10 / 5 =' $div + + mult = 2 * 5 + echo '2 * 5=' $mult + decho '2 * 5=' $mult + + var1 = 5 + var2 = 6 + + if($var1 < $var2){ + decho $var1 is less than $var2 + two = 1 + power = 10 + echo starting loop + decho starting loop + while($power > 0){ + two = $(two) * 2 + power = $power - 1 + } + output2 = "2^10 = $two" + echo $output2 + decho $output2 + } + if ($var1 > $var2) { + echo $var2 is less than $var1 + decho $var2 is less than $var1 + } + else { + output3 = 'var1' . " is " . $var1 + echo $output3 + decho $output3 + } + var = "test" + if ("test" == $var) { + echo string compare success + decho string compare success + } +} \ No newline at end of file diff --git a/base/Applications/Shell/ScriptEngine.cs b/base/Applications/Shell/ScriptEngine.cs new file mode 100644 index 0000000..cf7005f --- /dev/null +++ b/base/Applications/Shell/ScriptEngine.cs @@ -0,0 +1,726 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +/////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Collections; +using System.IO; +using System.Text.RegularExpressions; +using System.Text; +using Microsoft.Singularity; +using Microsoft.Singularity.Io; +using Microsoft.Contracts; + +namespace Microsoft.Singularity.Applications +{ + /** + * Provides a reasonable script engine implementation. + * This engine is composed of two distinct parts: the parser + * and the interpreter. Parser.cs and ScriptParser.cs provide + * the parsing functionality. Parser.cs is the general handwritten slr + * driver while ScriptParser contains the automatically generated + * parse tables and semantic action functions for productions + * and lex operations of this specific scripting language. This file + * provides the interpretation mechanism that runs over an ast produced + * by the parser. + **/ + class ScriptEngine + { + private String script; + private Block parsedScript; + public const String LAST_COMMAND_EXIT_SYMBOL = "?"; + public const String NUM_ARGUMENTS_SYM = "#"; + public delegate int CommandLineRunner(ShellControl! shellControl, + String[] commandLine, + bool isBackground); + + private CommandLineRunner runner; + + + public static int Run(String script, ShellControl! shellControl, CommandLineRunner runner) + { + return Run(script, shellControl, runner, null); + } + + public static int Run(String script, ShellControl! shellControl, + CommandLineRunner runner, String[] arguments) + { + ScriptEngine engine = new ScriptEngine(script, runner); + try { + engine.Parse(); + } catch (Parser.ParseException e) { + Console.WriteLine(e.Message); + return -1; + } catch (Exception e) { + Console.WriteLine(e.Message); + return -1; + } + + try { + return engine.Run(shellControl, arguments); + } catch (Interpretation.InterpretationException e) { + Console.WriteLine(e.Message); + } catch (ScriptException e) { + Console.WriteLine(e.Message); + } catch (Exception e) { + Console.WriteLine(e.Message); + } + return -1; + } + + + private ScriptEngine(String script, CommandLineRunner runner) + { + this.script = script; + this.runner = runner; + } + + private void Parse() + { + ScriptParser parser = new ScriptParser(); + parsedScript = (Block)parser.Parse(script); + + } + + private int Run(ShellControl! shellControl, String[] arguments) + { + Interpretation interp = new Interpretation(runner, arguments); + parsedScript.Interpret(shellControl, interp); + return interp.ExitCode; + } + + public class ScriptException : Exception + { + public ScriptException(String message) : base(message) { } + } + + public class Interpretation + { + public static readonly object! undefinedObj = new Object(); + private Hashtable! symbolTable; + private bool exit = false; + + [NotDelayed] + public Interpretation(CommandLineRunner runner, String[] arguments) + { + this.runner = runner; + symbolTable = new Hashtable(); + base(); + int i = 0; + if (arguments != null) { + for (; i < arguments.Length; ++i) { + SetSymbol(i.ToString(), arguments[i]); + } + } + SetSymbol(NUM_ARGUMENTS_SYM, i); + } + + public int ExitCode + { + get { + Object exitCode = LookupSymbol(LAST_COMMAND_EXIT_SYMBOL); + if (exitCode == null) { return 0; } + return (Int32) exitCode; + } + set { SetSymbol(LAST_COMMAND_EXIT_SYMBOL, value); } + } + + public bool Exit + { + get { return exit; } + set { exit = value; } + } + + public CommandLineRunner runner; + + public object! LookupSymbol(string! symbol) + { + Object value = symbolTable[symbol]; + if (value == null) { + return undefinedObj; + } + return value; + } + public void SetSymbol(string! key, Object value) + { + symbolTable[key] = value; + } + + public class InterpretationException : Exception + { + public InterpretationException(String message) : base(message) { } + } + + public class UndefinedVariableException : InterpretationException + { + public UndefinedVariableException(String variable) + : base("Use of undefined variable: " + variable) { } + } + + public class TypeConversionException : InterpretationException + { + public TypeConversionException(String value, String type) + : base("Could not convert " + value + " to type: " + type) { } + } + + public class UnknownTypeException : InterpretationException + { + public UnknownTypeException(String type) + : base("Unknown type" + type) { } + } + + public class DivideByZeroException : InterpretationException + { + public DivideByZeroException() : base("Division by zero undefined.") { } + } + + + } + public abstract class Element { } + + public abstract class Expression : Element + { + public abstract object! GetValue(Interpretation! interp); + public abstract string! StringValue(Interpretation! interp); + public abstract int IntValue(Interpretation! interp); + public abstract bool BoolValue(Interpretation! interp); + public bool IsIntLike() { return true; } + public bool IsBoolLike() { return true; } + public bool IsStringLike() { return true; } + } + + public class VariableReference : Expression + { + String variable; + public VariableReference(String variable) + { + this.variable = variable; + } + public override object! GetValue(Interpretation! interp) + { + object value = interp.LookupSymbol(variable); + if (value == Interpretation.undefinedObj) + throw new Interpretation.UndefinedVariableException(variable); + return value; + } + + public override string! StringValue(Interpretation! interp) + { + object value = GetValue(interp); + return value.ToString(); + } + + public override int IntValue(Interpretation! interp) + { + Object value = GetValue(interp); + if (value is String) { + return Int32.Parse((String)value); + } else if (value is Int32) { + return (int)value; + } else if (value is bool) { + return ((bool)value) ? 1 : 0; + } + throw new Interpretation.UnknownTypeException(value.GetType().ToString()); + } + + public override bool BoolValue(Interpretation! interp) + { + Object value = GetValue(interp); + if (value is String) { + try { + return Boolean.Parse((String)value); + } catch (FormatException) { + throw new Interpretation.TypeConversionException((String)value, "bool"); + } + + } else if (value is Int32) { + + return ((int)value) == 0 ? true : false; + } else if (value is Boolean) { + return (bool)value; + } + throw new Interpretation.UnknownTypeException(value.GetType().ToString()); + } + } + + public abstract class IntegerExpression : Expression + { + public override object! GetValue(Interpretation! interp) { return IntValue(interp); } + public override string! StringValue(Interpretation! interp) + { + int value = IntValue(interp); + return value.ToString(); + } + public override bool BoolValue(Interpretation! interp) + { + int value = IntValue(interp); + return value == 0 ? true : false; + } + } + + public class IntegerLiteral : IntegerExpression + { + private int value; + public IntegerLiteral(int value) + { + this.value = value; + } + public override int IntValue(Interpretation! interp) { return value; } + } + public abstract class IntegerBinaryExpression : IntegerExpression + { + public Expression left; + public Expression right; + protected IntegerBinaryExpression(Expression left, Expression right) + { + this.left = left; this.right = right; + } + } + public class Add : IntegerBinaryExpression + { + public Add(Expression left, Expression right) : base(left, right) { } + public override int IntValue(Interpretation! interp) + { + return left.IntValue(interp) + right.IntValue(interp); + } + } + public class Subtract : IntegerBinaryExpression + { + public Subtract(Expression left, Expression right) : base(left, right) { } + public override int IntValue(Interpretation! interp) + { + return left.IntValue(interp) - right.IntValue(interp); + } + } + + public class Multiply : IntegerBinaryExpression + { + public Multiply(Expression left, Expression right) : base(left, right) { } + public override int IntValue(Interpretation! interp) + { + return left.IntValue(interp) * right.IntValue(interp); + } + } + + public class Divide : IntegerBinaryExpression + { + public Divide(Expression left, Expression right) : base(left, right) { } + public override int IntValue(Interpretation! interp) + { + int leftVal = left.IntValue(interp); + int rightVal = right.IntValue(interp); + if (rightVal == 0) { + throw new DivideByZeroException(); + } + return leftVal / rightVal; + + } + } + + public class Mod : IntegerBinaryExpression + { + public Mod(Expression left, Expression right) : base(left, right) { } + public override int IntValue(Interpretation! interp) + { + return left.IntValue(interp) % right.IntValue(interp); + } + } + public abstract class BooleanExpression : Expression + { + public override object! GetValue(Interpretation! interp) { return BoolValue(interp); } + public override int IntValue(Interpretation! interp) + { + bool value = BoolValue(interp); + return value ? 1 : 0; + } + public override string! StringValue(Interpretation! interp) + { + bool value = BoolValue(interp); + return value.ToString(); + } + } + + public class BooleanLiteral : BooleanExpression + { + bool value; + public BooleanLiteral(bool value) + { + this.value = value; + } + public override bool BoolValue(Interpretation! interp) { return value; } + + } + public abstract class BooleanBinaryExpression : BooleanExpression + { + protected Expression left; + protected Expression right; + public BooleanBinaryExpression(Expression left, Expression right) + { + this.left = left; this.right = right; + } + protected int CompareOperands(Interpretation! interp) + { + return CompareTo(left.GetValue(interp), right, interp); + } + private static int CompareTo(Object left, Expression e, Interpretation! interp) + { + if (left == null) { + if (e == null) { return 0; } + return -1; + } + if (e == null) { return 1; } + if (left is String) { + return ((String)left).CompareTo(e.StringValue(interp)); + } else if (left is int) { + return ((int)left).CompareTo(e.IntValue(interp)); + } else if (left is Boolean) { + return ((Boolean)left).CompareTo(e.BoolValue(interp)); + } + throw new Interpretation.UnknownTypeException("unsupported type"); + } + } + public class And : BooleanBinaryExpression + { + public And(Expression left, Expression right) : base(left, right) { } + + public override bool BoolValue(Interpretation! interp) + { + return left.BoolValue(interp) && right.BoolValue(interp); + } + } + + public class Or : BooleanBinaryExpression + { + public Or(Expression left, Expression right) : base(left, right) { } + public override bool BoolValue(Interpretation! interp) + { + return left.BoolValue(interp) || right.BoolValue(interp); + } + } + + public class Less : BooleanBinaryExpression + { + public Less(Expression left, Expression right) : base(left, right) { } + public override bool BoolValue(Interpretation! interp) + { + int compare = CompareOperands(interp); + return compare < 0; + } + } + + public class LessEqual : BooleanBinaryExpression + { + public LessEqual(Expression left, Expression right) : base(left, right) { } + public override bool BoolValue(Interpretation! interp) + { + int compare = CompareOperands(interp); + return compare < 0 || compare == 0; + } + } + + public class Equal : BooleanBinaryExpression + { + public Equal(Expression left, Expression right) : base(left, right) { } + public override bool BoolValue(Interpretation! interp) + { + int compare = CompareOperands(interp); + return compare == 0; + } + } + + public class Greater : BooleanBinaryExpression + { + public Greater(Expression left, Expression right) : base(left, right) { } + public override bool BoolValue(Interpretation! interp) + { + int compare = CompareOperands(interp); + return compare > 0; + } + } + + public class GreaterEqual : BooleanBinaryExpression + { + public GreaterEqual(Expression left, Expression right) : base(left, right) { } + public override bool BoolValue(Interpretation! interp) + { + int compare = CompareOperands(interp); + return compare == 0 || compare > 0; + } + } + + + public class Negate : BooleanExpression + { + Expression expr; + public Negate(Expression expr) + { + this.expr = expr; + } + public override bool BoolValue(Interpretation! interp) + { + return !expr.BoolValue(interp); + } + } + + public abstract class StringExpression : Expression + { + public override object! GetValue(Interpretation! interp) + { + return StringValue(interp); + } + public override int IntValue(Interpretation! interp) + { + String value = StringValue(interp); + try { + return Int32.Parse(value); + } catch (FormatException) { + throw new Interpretation.TypeConversionException(value, "String"); + } + } + + public override bool BoolValue(Interpretation! interp) + { + String value = StringValue(interp); + try { + return Boolean.Parse(value); + } catch (FormatException) { + throw new Interpretation.TypeConversionException(value, "String"); + } + } + } + private static Regex whitespace = new Regex(@"\s+"); + + public class StringInterpolation : StringExpression + { + private ArrayList interpolationElems; + private static Regex escaped_dollar = new Regex(@"\\\$"); + + private static String[]! Split(string! interpolation) + { + ArrayList chunks = new ArrayList(); + char last = (char) -1; + int lastIndex = 0; + for (int i = 0; i < interpolation.Length; last = interpolation[i], ++i) { + if (interpolation[i] == '$' && last != '\\') { + chunks.Add(interpolation.Substring(lastIndex, i - lastIndex)); + lastIndex = i + 1; + } + } + chunks.Add((lastIndex < interpolation.Length - 1 ? interpolation.Substring(lastIndex) : "")); + String[] strings = new string[chunks.Count]; + chunks.CopyTo(strings); + return strings; + } + + [NotDelayed] + public StringInterpolation(string! interpolation) + { + interpolationElems = new ArrayList(); + String[] split = Split(interpolation); + if (split[0] != "") { + //replace escaped $ and add + interpolationElems.Add(new StringLiteral(escaped_dollar.Replace(split[0], "$"))); + } + for (int i = 1; i < split.Length; ++i) { + string var, rest; + string! split_i = (!)split[i]; + if (split_i[0] == '{') { + int index = split_i.IndexOf('}'); + if (index == -1) { + throw new ScriptException("Unmatched left brace in " + interpolation); + } + var = split_i.Substring(1, index - 1); + rest = index + 1 < split_i.Length ? split_i.Substring(index + 1) : ""; + } else { + Match m = whitespace.Match(split_i); + assert m != null; + int index = m.Success ? m.Index : split_i.Length; + var = split_i.Substring(0, index); + rest = index + 1 < split_i.Length ? split_i.Substring(index + 1) : ""; + } + //didn't replace escaped dollar signs in variable, bad syntax anyway. + interpolationElems.Add(new VariableReference(var)); + if (rest != "") { + interpolationElems.Add(new StringLiteral(escaped_dollar.Replace(rest, "$"))); + + } + } + } + + public override string! StringValue(Interpretation! interp) + { + StringBuilder sb = new StringBuilder(); + foreach (Expression! elem in interpolationElems) { + sb.Append(elem.StringValue(interp)); + } + return sb.ToString(); + } + } + public class StringLiteral : StringExpression + { + private string literal; + public StringLiteral(String literal) + { + this.literal = literal; + } + public override string! StringValue(Interpretation! interp) + { + return literal; + + } + } + + public class Concat : StringExpression + { + private Expression left; + private Expression right; + public Concat(Expression left, Expression right) + { + this.left = left; this.right = right; + } + + public override string! StringValue(Interpretation! interp) + { + return left.StringValue(interp) + right.StringValue(interp); + } + } + + public abstract class Statement : Element + { + public abstract void Interpret(ShellControl! shellControl, Interpretation! interp); + } + + public class Assign : Statement + { + String variable; + Expression expression; + public Assign(String variable, Expression expression) + { + this.variable = variable; this.expression = expression; + } + public override void Interpret(ShellControl! shellControl, Interpretation! interp) + { + Object value = expression.GetValue(interp); + if (interp != null) + interp.SetSymbol(variable, value); + } + } + public class If : Statement + { + Expression condition; + Block block; + public If(Expression condition, Block block) + { + this.condition = condition; this.block = block; + } + public override void Interpret(ShellControl! shellControl, Interpretation! interp) + { + if (condition.BoolValue(interp)) { + block.Interpret(shellControl, interp); + } + } + } + public class IfThenElse : Statement + { + Expression condition; + Block trueBlock; + Block falseBlock; + public IfThenElse(Expression condition, Block trueBlock, Block falseBlock) + { + this.condition = condition; this.trueBlock = trueBlock; this.falseBlock = falseBlock; + } + public override void Interpret(ShellControl! shellControl, Interpretation! interp) + { + if (condition.BoolValue(interp)) { + trueBlock.Interpret(shellControl, interp); + } else { + falseBlock.Interpret(shellControl, interp); + } + } + } + + public class While : Statement + { + Expression condition; + Block block; + public While(Expression condition, Block block) + { + this.condition = condition; this.block = block; + } + public override void Interpret(ShellControl! shellControl, Interpretation! interp) + { + while (condition.BoolValue(interp)) { + block.Interpret(shellControl, interp); + if (interp.Exit) break; + } + } + } + public class Block : Statement + { + ArrayList statements; + public Block(ArrayList statements) + { + this.statements = statements; + } + public override void Interpret(ShellControl! shellControl, Interpretation! interp) + { + foreach (Statement statement in statements) { + if (statement != null) + statement.Interpret(shellControl, interp); + if (interp.Exit) break; + } + } + public override string! ToString() + { + throw new ScriptException("The method or operation is not implemented."); + } + } + + public class Command : Statement + { + public ArrayList commandLine; + bool async; + + public Command(ArrayList commandLine) : this(commandLine, false) { } + public Command(ArrayList commandLine, bool async) + { + this.commandLine = commandLine; + this.async = async; + } + public override void Interpret(ShellControl! shellControl, Interpretation! interp) + { + String[] arguments = new String[commandLine.Count]; + int i = 0; + //Console.WriteLine("Interpret Command"); + foreach (Expression! e in commandLine) { + string arg = e.StringValue(interp); + //Console.WriteLine(" CMD[{0}]: {1}", i, arg); + arguments[i++] = arg; + } + if (i != 0 && ((!)arguments[0]).Trim() == "exit") { + if (arguments.Length >= 2) { + try { + int exitCode = Int32.Parse(arguments[1]); + interp.ExitCode = exitCode; + } catch (FormatException) { + throw new Interpretation.TypeConversionException((String)arguments[1], "integer"); + } + } + interp.Exit = true; + } else { + try { + int exitCode = interp.runner(shellControl, arguments, async); + interp.ExitCode = exitCode; + } + catch (FileNotFoundException) { + interp.Exit = true; + } + } + } + } + } +} diff --git a/base/Applications/Shell/Shell.csproj b/base/Applications/Shell/Shell.csproj new file mode 100644 index 0000000..f3c3159 --- /dev/null +++ b/base/Applications/Shell/Shell.csproj @@ -0,0 +1,46 @@ + + + + + + + + Shell + Exe + true + true + true + + + + + + + + + + + + + + + + + + + + Microsoft.Singularity.Applications + ScriptParser + + + + + diff --git a/base/Applications/Shell/Shell.sg b/base/Applications/Shell/Shell.sg new file mode 100644 index 0000000..89b909b --- /dev/null +++ b/base/Applications/Shell/Shell.sg @@ -0,0 +1,2098 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Shell.cs +// +// Note: +// + +using DirectoryService.Utils; +using FileSystem.Utils; +using System; +using System.Text; +using System.GC; +using System.Runtime.Remoting; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Collections; +using System.Diagnostics; + +using Microsoft.Singularity; +using Microsoft.SingSharp; +using Microsoft.Singularity.Directory; +using DirectoryServices.Utils; +using Microsoft.Singularity.V1.Services; +using Microsoft.Singularity.V1.Processes; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.FileSystem; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Security; +using Keyboard = Microsoft.Singularity.Io.Keyboard; +using Tty = Microsoft.Singularity.Io.Tty2006; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; + +using System.IO; + +[assembly: Transform(typeof(ApplicationResourceTransform))] +[assembly: ApplicationPublisherAttribute("singularity.microsoft.com")] + +namespace Microsoft.Singularity.Applications +{ + [ConsoleCategory(HelpMessage="Shell", DefaultAction=true)] + internal class Parameters + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [StringArrayParameter( "filename", HelpMessage="the bucket")] + internal string[] args; + + reflective internal Parameters(); + + internal int AppMain() { + return Shell.AppMain(this); + } + } + + // See WaitForChildThread below + internal contract WaitForChildContract { + out message Finish(); + state Start: one {Finish! -> Done;} + state Done: one {} + } + + public enum ShellEvent : ushort + { + RunCommand = 1 + } + + internal class Dir + { + private static TRef m_epNS = null; + + public static DirectoryServiceContract.Imp:Ready! GetDirectoryServiceContract() + { + if (m_epNS == null) { + m_epNS = new TRef(DirectoryService.NewClientEndpoint()); + } + + return m_epNS.Acquire(); + } + + public static void ReleaseDirectoryServiceContract([Claims] DirectoryServiceContract.Imp:Ready! imp) + { + m_epNS.Release(imp); + } + } + + public class InvalidPathException : Exception + { + public InvalidPathException(string! message) + : base(message) + {} + } + + public class Ls + { + internal static void SplitPath(string! filePath, + out string! dirPath, + out string! fileName) + { + string[] parts = filePath.Split('/'); + if ((parts == null) || (parts.Length == 0)) { + // Not even a leading slash? Bah! + throw new InvalidPathException(String.Format("The path '{0}' is invalid.", filePath)); + } + + // The previous implementation allowed "dir hardware" to be interpreted as "dir /hardware". + if (parts.Length == 1) { + dirPath = "/"; + fileName = (!)parts[0]; + return; + } + + fileName = (!)parts[parts.Length-1]; + + // The directory path is the full path minus + // the trailing leaf part + // need to special case Directory Service root. Need to return "/" as dirPath + int len = (filePath.Length - fileName.Length - 1) > 0? filePath.Length - fileName.Length - 1 : 1; + dirPath = filePath.Substring(0, len); + } + + private static int Find(string! path, string! pattern, DirectoryServiceContract.Imp:Start! ds) + { + try { + ErrorCode errorOut; + EnumerationRecords[] in ExHeap responses = + SdsUtils.EnumerateDirectory(ds, out errorOut); + if (null == responses) { + Console.WriteLine("Find ({0}) failed. reason:{1}", + "/", SdsUtils.ErrorCodeToString(errorOut)); + return -1; + } + else { + for (int i = 0; i < responses.Length; i++) { + string displayName; + expose (responses[i]) { + string name = Bitter.ToString2(responses[i].Path); + if (!SdsUtils.IsMatch(name, pattern)) { + continue; + } + + displayName = name; + string type; + switch (responses[i].Type) { + case NodeType.Directory : + type = " "; + break; + case NodeType.File : + type = ""; + break; + case NodeType.IoMemory : + type = " "; + break; + case NodeType.ServiceProvider : + type = ""; + break; + case NodeType.SymLink : + type = ""; + break; + case NodeType.BadNode : + type = " "; + break; + default: + type = ""; + break; + } + if (responses[i].Type == NodeType.Directory) { + displayName = displayName + "/"; + } + else if (responses[i].Type == NodeType.SymLink) { + // If it's a symbolic link, show the destination. + displayName = displayName + "@"; + ErrorCode linkErrorCode; + string linkValue; + if (SdsUtils.GetLinkValue(name, ds, out linkValue, out linkErrorCode)) { + displayName = displayName.PadRight(16) + " " + linkValue; + } else { + Console.WriteLine("Failed to query link '{0}': {1}", name, SdsUtils.ErrorCodeToString(linkErrorCode)); + } + } + Console.WriteLine(" {0} {1}", type, displayName); + } + } + delete responses; + return 0; + } + } + finally { + } + } + + public static int ListAndSort(string! path) + { + string !file; + string !dir; + string pattern; + + SplitPath(path, out dir, out file); + + if ( file.IndexOf("*") != -1) { + pattern = file; + } + else { + dir = path; + pattern = "*"; + } + DirectoryServiceContract.Imp epNS = Dir.GetDirectoryServiceContract(); + + DirectoryServiceContract.Imp! dirClient; + DirectoryServiceContract.Exp! dirServer; + DirectoryServiceContract.NewChannel(out dirClient, out dirServer); + ErrorCode errorOut; + + bool ok = SdsUtils.Bind((!)dir, epNS, dirServer, out errorOut); + if (!ok) { + Console.WriteLine("Bind to '{0}' failed. reason: {1}", + dir, SdsUtils.ErrorCodeToString(errorOut)); + delete dirClient; + Dir.ReleaseDirectoryServiceContract(epNS); + return -1; + } + dirClient.RecvSuccess(); + + Find(dir, pattern, dirClient); + delete dirClient; + Dir.ReleaseDirectoryServiceContract(epNS); + return 0; + } + } + + public abstract class Job { + private string! commandLine; + protected TRef! stdinCell; + public readonly int Id; + + private static int IdGenerator = 0; + + public string Name { + get { return commandLine; } + } + + protected Job(string! command, [Claims] UnicodePipeContract.Imp:READY! stdin) { + this.commandLine = command; + this.stdinCell = new TRef(stdin); + this.Id = IdGenerator++; + } + + public UnicodePipeContract.Imp:READY! AcquireStdin() { + return this.stdinCell.Acquire(); + } + + public void ReleaseStdin([Claims] UnicodePipeContract.Imp:READY! stdin) { + this.stdinCell.Release(stdin); + } + + + public string StatusName { + get { + switch (this.Status) { + case ProcessState.Stopped: + return "Stopped"; + case ProcessState.Suspended: + return "Suspended"; + case ProcessState.Active: + return "Active"; + default: + return "Unknown"; + } + } + } + + public ProcessState Status { + get { + Process p = this.Process; + if (p == null) { + return ProcessState.Stopped; + } + return p.State; + } + } + + public int ExitCode { + get { + Process p = this.Process; + if (p == null) { + return 0; + } + return p.ExitCode; + } + } + + public virtual void Dispose() { + } + + public abstract Process Process { get; } + + public void Stop() { + Process p = this.Process; + if (p != null) { + p.Stop(); + } + } + + public void Suspend() { + Process p = this.Process; + if (p != null) { + p.Suspend(false); + } + } + + public void Resume() { + Process p = this.Process; + if (p != null) { + p.Resume(false); + } + } + } + + public class SingleProcessJob : Job { + + Process process; + + private static string! CommandLineString(string[]! command) + { + StringBuilder sb = new StringBuilder(); + foreach(string s in command) { + sb.Append(s); + sb.Append(' '); + } + return sb.ToString(); + } + + public SingleProcessJob(string[]! command, Process p, + [Claims] UnicodePipeContract.Imp:READY! stdin) + : base(CommandLineString(command), stdin) + { + this.process = p; + } + + public override Process Process { + get { return this.process; } + } + + public override void Dispose() { + Process p = this.process; + if (p != null) { + p.Dispose(true); + } + base.Dispose(); + } + } + + public class PipeJob : Job { + Process[]! processes ; + + public PipeJob(string! command, + [Claims] UnicodePipeContract.Imp:READY! stdin, + Process[]! processes) + : base(command, stdin) + { + this.processes = processes; + } + + public override Process Process { + get { + int c = processes.Length; + if (c <= 0) return null; + + return (Process)this.processes[c-1]; + } + } + + public override void Dispose() { + foreach (Process! p in this.processes) { + p.Dispose(true); + } + base.Dispose(); + } + } + + public class ShellControl : ITracked { + + PipeMultiplexer! outputControl; + Hashtable! jobs; // maps ints to jobs + + public ShellControl([Claims] PipeMultiplexer! outputControl) { + this.outputControl = outputControl; + this.jobs = new Hashtable(); + } + + public UnicodePipeContract.Imp:READY FreshStdout() { + expose(this) { + return this.outputControl.FreshClient(); + } + } + + private void RemoveStoppedJobs() { + ArrayList toRemove = new ArrayList(); + foreach (int i in jobs.Keys) { + Job job = (Job)this.jobs[i]; + assert job != null; + if (job.Status == ProcessState.Stopped) { + job.Dispose(); + toRemove.Add(i); + } + } + foreach (int i in toRemove) { + Console.WriteLine("[{0}] Done.", i); + this.jobs.Remove(i); + } + } + /// + /// Provides enumeration of non-exited jobs + /// + public IEnumerator GetEnumerator() { + RemoveStoppedJobs(); + return this.jobs.Keys.GetEnumerator(); + } + + public Job this[int i] { + get { + return (Job)this.jobs[i]; + } + } + + public void Add(Job! job) { + jobs[job.Id] = job; + } + + public void Dispose() + { + this.outputControl.Dispose(); + } + + void ITracked.Acquire() {} + void ITracked.Release() {} + void ITracked.Expose() {} + void ITracked.UnExpose() {} + } + + public class Shell + { + // Exit Codes: + internal const int EXIT_AND_RESTART = 0x1fff; + internal const int EXIT_AND_SHUTDOWN = 0x1ffe; + internal const int EXIT_AND_WARMBOOT = 0x1ffd; + internal const int EXIT_AND_HALT = 0x1ffc; + + private static Terminal terminal; + private static ParameterProcessor parameters; + private static ArrayList localPackages = null; + private static bool done = false; + private static bool insertMode = true; + private static int curpos = 0; + private static int totalChars = 0; + private static StringBuilder buildString; + + private class ShellCommand + { + public string Name; + public string Description; + public CommandStart Run; + + public ShellCommand(string name, string description, CommandStart run) + { + Name = name; + Description = description; + Run = run; + } + + override public string! ToString() + { + return "[ShellCommand(" + Name + ", " + Description + "]"; + } + } + + ////////////////////////////////////////////////////// Shell Commands. + // + private delegate int CommandStart(ShellControl! shellControl, string[]! args); + + private static ShellCommand[] commands = + { + // Please insert new commands in alphabetical order! + // + new ShellCommand("bg", "Background a stopped job", + new CommandStart(DoBg)), + new ShellCommand("break", "Break into the kernel debugger", + new CommandStart(DoBreak)), + new ShellCommand("bvt", "Basic verification test", + new CommandStart(DoBvt)), + new ShellCommand("clear", "Clear screen", + new CommandStart(DoClear)), + new ShellCommand("date", "Display date and time", + new CommandStart(DoDate)), + new ShellCommand("decho", "Echo inputs to debugger", + new CommandStart(DoDecho)), + new ShellCommand("dir", "Display contents of name space", + new CommandStart(DoDir)), + new ShellCommand("echo", "Echo inputs to console", + new CommandStart(DoEcho)), + new ShellCommand("exit", "Exit shell", + new CommandStart(DoShutdown)), + new ShellCommand("fg", "Foreground a stopped or background job", + new CommandStart(DoFg)), + new ShellCommand("_gcstress", "Stress garbage collector", + new CommandStart(DoGcStress)), + new ShellCommand("help", "Display help message", + new CommandStart(DoHelp)), + new ShellCommand("jobs", "List jobs", + new CommandStart(DoJobs)), + new ShellCommand("reboot", "Reboot computer", + new CommandStart(DoReboot)), + new ShellCommand("script", "Run script file", + new CommandStart(DoScript)), + new ShellCommand("shutdown", "Shut down computer", + new CommandStart(DoShutdown)), + new ShellCommand("start", "Start process with independent I/O", + new CommandStart(DoStart)), + new ShellCommand("testscript","Test scripting engine", + new CommandStart(DoTestScript)), + new ShellCommand("warmboot", "Warm reboot computer", + new CommandStart(DoWarmBoot)), + // + // Please insert new commands in alphabetical order! + }; + + public static int DoBreak(ShellControl! shellControl, string[]! args) + { + Console.WriteLine("Breaking into kernel debugger."); + if (args.Length == 2 && args[1] == "-w") { + Breaker.Break(2); + } + else if (args.Length == 2 && args[1] == "-r") { + Breaker.Break(1); + } + else if (args.Length == 2 && args[1] == "-b") { + Breaker.Break(01); + } + else { + DebugStub.WriteLine("About to break into kernel debugger"); + DebugStub.Break(); + } + + bool iflag = Processor.DisableInterrupts(); + Processor.RestoreInterrupts(iflag); + Console.WriteLine("First line after break."); + Console.WriteLine("Second line after break."); + Console.WriteLine("Third line after break."); + + return 0; + } + + public static int DoClear(ShellControl! shellControl, string[]! args) + { + terminal.GenerateAndSendEscapeSequence(Tty.EscapeCodes.CLEAR_SCREEN); + return 0; + } + + private static void ConsoleWriteDateTime(string preamble, DateTime dt) + { + Console.WriteLine("{0}{1:d4}/{2:d2}/{3:d2} {4:d2}:{5:d2}:{6:d2}.{7:d3}", + preamble, dt.Year, dt.Month, dt.Day, + dt.Hour, dt.Minute, dt.Second, dt.Millisecond); + } + + private static void ConsoleWriteDateTime(string preamble, TimeSpan sp) + { + Console.WriteLine("{0}{1}", preamble, sp.ToString()); + + } + + public static int DoDate(ShellControl! shellControl, string[]! args) + { + ConsoleWriteDateTime("Kernel: ", ProcessService.GetUpTime()); + ConsoleWriteDateTime("UTC: ", DateTime.UtcNow); + return 0; + } + + private static String Concat(String[]! args, int startIndex) + { + StringBuilder sb = new StringBuilder(); + for (int i = startIndex; i < args.Length; ++i) { + sb.Append(args[i] + (i == (args.Length - 1) ? "" : " ")); + } + return sb.ToString(); + } + + public static int DoDecho(ShellControl! shellControl, string[]! args) + { + DebugStub.WriteLine("{0}", __arglist(Concat(args, 1))); + return 0; + } + + public static int DoDir(ShellControl! shellControl, string[]! args) + { + int ret = 0; + + if (args.Length == 1) { + ret = Ls.ListAndSort("/"); + } + else { + for (int arg = 1; arg < args.Length; arg++) { + ret = Ls.ListAndSort((!)args[arg]); + if (ret != 0) { + Console.WriteLine("Returned: {0}", ret); + break; + } + } + } + return ret; + } + + public static int DoEcho(ShellControl! shellControl, string[]! args) + { + Console.WriteLine(Concat(args, 1)); + return 0; + } + + public static int DoScript(ShellControl! shellControl, string[]! args) + { + int exitCode = 0; + long size; + NodeType nodeType; + FileContract.Imp file; + ErrorCode errorOut; + + if (args.Length < 2) { + Console.WriteLine("usage: script "); + return -1; + } + + DirectoryServiceContract.Imp! rootNS = Dir.GetDirectoryServiceContract(); + bool ok = FileUtils.GetAttributes((!)args[1], rootNS, + out size, out nodeType, out errorOut); + if (!ok) { + Console.WriteLine("File not found."); + Dir.ReleaseDirectoryServiceContract(rootNS); + return 1; + } + file = FileUtils.OpenFile((!)args[1], rootNS); + Dir.ReleaseDirectoryServiceContract(rootNS); + if (file == null) { + return -1; + } + + byte* opt(ExHeap[]) buf = new [ExHeap] byte[size]; + file.SendRead(buf, 0, 0, size); + + switch receive{ + case file.AckRead(_buf, bytesRead, error): + buf = _buf; + break; + case file.ChannelClosed(): + Console.WriteLine("Could not read file."); + delete file; + return 1; + } + delete file; + + String script = Bitter.ToString2(buf); +#if DUMP_SCRIPT_CONTENTS_TO_SCREEN + Console.WriteLine("Script==============================="); + Console.WriteLine(script); + Console.WriteLine("============================EndScript"); +#endif + exitCode = ScriptEngine.Run(script, shellControl, + new ScriptEngine.CommandLineRunner(RunCommand)); + delete buf; + return exitCode; + } + + public static int DoStart(ShellControl! shellControl, string[]! args) + { + String[] commandLine = new String[args.Length - 1]; + Array.Copy(args, 1, commandLine, 0, commandLine.Length); + return RunCommand(shellControl, commandLine, false); + } + + public static int DoTestScript(ShellControl! shellControl, string[]! args){ + String script = + @" + echo $2 #echo second argument + decho $2 + echo number of arguments '=' $# + decho number of arguments '=' $# + + echo last command exit code '=' $? + decho last command exit code '=' $? + + type & + echo appear before type output + + if (true) { + variable = false + if ($variable) { + var2 = true + echo broken conditional + decho broken conditional + } + else { + var2 = true + output1 = ""bet${variable}ween"" + echo $output1 + decho $output1 + } + #some comments # + # + decho var2 is $var2 + add = -2 + 4 + echo '-2 + 4 =' $add + decho '-2 + 4 =' $add + + mod = 6 % 5 + echo '6 % 5 =' $mod + decho '6 % 5 =' $mod + + div = 10 / 5 + echo '10 / 5 =' $div + decho '10 / 5 =' $div + + mult = 2 * 5 + echo '2 * 5=' $mult + decho '2 * 5=' $mult + + var1 = 5 + var2 = 6 + + if($var1 < $var2){ + echo $var1 is less than $var2 + decho $var1 is less than $var2 + two = 1 + power = 10 + echo starting loop + decho starting loop + while($power > 0){ + two = $(two) * 2 + power = $power - 1 + } + output2 = ""2^10 = $two"" + echo $output2 + decho $output2 + } + if ($var1 > $var2) { + echo $var2 is less than $var1 + decho $var2 is less than $var1 + } + else { + output3 = 'var1' . "" is "" . $var1 + echo $output3 + decho $output3 + } + var = ""test"" + if (""test"" == $var) { + echo string compare success + decho string compare success + } + exit + } + echo should not display + decho should not display + exit -1 + "; + + return ScriptEngine.Run( + script, + shellControl, + new ScriptEngine.CommandLineRunner(RunCommand), + new String[] {"script", "testscript", "arg"} + ); + + } + + private static void GcStressVariableSizeObjects() + { + const uint maxItemBytes = 65535; + const uint maxAllocatedBytes = 1000000; + byte dummy = 0; + + Console.Write("Running variable size object test."); + + DateTime start = DateTime.Now; + TimeSpan duration = TimeSpan.FromSeconds(10); + TimeSpan oneSecond = TimeSpan.FromSeconds(1); + + Queue q = new Queue(); + while (DateTime.Now - start < duration) + { + DateTime roundStart = DateTime.Now; + uint iterations = 0; + while (DateTime.Now - roundStart < oneSecond) + { + uint allocatedBytes = 0; + uint i = 17u * iterations; + while (allocatedBytes < maxAllocatedBytes) + { + uint itemBytes = 1u + (uint)((433777u * i) % maxItemBytes); + allocatedBytes += itemBytes; + i++; + byte [] data = new byte[itemBytes]; + data[0] = 0xff; + q.Enqueue(data); + } + + while (q.Count != 0) + { + byte [] data = (byte []!) q.Dequeue(); + dummy ^= data[0]; + } + iterations ++; + } + Console.Write(" {0}", iterations, dummy); + } + Console.Write("\n"); + } + + private static void GcStressFixedSizeObjects() + { + const int itemCount = 1024; + const int itemBytes = 1024; + + Console.Write("Running fixed size object test."); + + byte dummy = 0; + + DateTime start = DateTime.Now; + TimeSpan duration = TimeSpan.FromSeconds(10); + TimeSpan oneSecond = TimeSpan.FromSeconds(1); + Queue q = new Queue(); + while (DateTime.Now - start < duration) + { + DateTime roundStart = DateTime.Now; + int iterations = 0; + while (DateTime.Now - roundStart < oneSecond) + { + for (int i = 0; i < itemCount; i++) + { + byte [] data = new byte[itemBytes]; + // Debug.Assert(data[0] == 0); + data[0] = 0xff; + q.Enqueue(data); + } + + for (int i = 0; i < itemCount; i++) + { + byte [] data = (byte []!) q.Dequeue(); + // Debug.Assert(data[0] == 0xff); + dummy ^= data[0]; + } + iterations ++; + } + Console.Write(" {0}", iterations, dummy); + } + Console.Write("\n"); + } + + public static int DoGcStress(ShellControl! shellControl, string[]! args) + { + GcStressFixedSizeObjects(); + GcStressVariableSizeObjects(); + return 0; + } + + public static int DoHelp(ShellControl! shellControl, string[]! args) + { + Console.WriteLine("Singularity shell commands:"); + + int max = 0; + foreach (ShellCommand! command in commands) { + int length = command.Name.Length; + if (length > max) { + max = length; + } + } + + foreach (ShellCommand! command in commands) { + Console.Write(" {0}", command.Name); + for (int i = command.Name.Length; i < max; i++) { + Console.Write(" "); + } + Console.WriteLine(" - {0}", command.Description); + } + return 0; + } + + public static int DoJobs(ShellControl! shellControl, string[]! args) + { + foreach (int i in shellControl) { + Job job = shellControl[i]; + assert job != null; + string status = job.StatusName; + Console.WriteLine("[{0}] {1,10} {2,40}", i, status, job.Name); + } + return 0; + } + + public static int DoFg(ShellControl! shellControl, string[]! args) + { + if (args == null || args.Length != 2) { + Console.WriteLine("Usage: fg "); + return 1; + } + int jobnum = Int32.Parse(args[1]); + + Job job = shellControl[jobnum]; + + if (job == null) { + Console.WriteLine("Nonexistent job {0}", jobnum); + return 1; + } + if (job.Status == ProcessState.Suspended) { + job.Resume(); + } + return WaitForJob(job); + } + + public static int DoBg(ShellControl! shellControl, string[]! args) + { + if (args == null || args.Length != 2) { + Console.WriteLine("Usage: bg "); + return 1; + } + int jobnum = Int32.Parse(args[1]); + + Job job = shellControl[jobnum]; + + if (job == null) { + Console.WriteLine("Nonexistent job {0}", jobnum); + return 1; + } + job.Resume(); + return 0; + } + + public static int DoReboot(ShellControl! shellControl, string[]! args) + { + DebugStub.WriteLine("Shell rebooting."); + done = true; + return EXIT_AND_RESTART; + } + + public static int DoShutdown(ShellControl! shellControl, string[]! args) + { + DebugStub.WriteLine("Shell shutting down."); + done = true; + return EXIT_AND_SHUTDOWN; + } + + public static int DoWarmBoot(ShellControl! shellControl, string[]! args) + { + DebugStub.WriteLine("Shell restarting for warm boot."); + done = true; + return EXIT_AND_WARMBOOT; + } + + // Runs each step of the BVT. + public static int Bvt(ShellControl! shellControl, int count) + { + Console.WriteLine("BVT BootCount={0}", count); + DebugStub.WriteLine("BVT BootCount={0}", __arglist(count)); + String script; + + if (count == 0) { + script = @" + msg = '[BVT 0.0] Running page table test.' + echo $msg + decho $msg + + msg = '[BVT 0.1] Running Pnp test.' + echo $msg + decho $msg + if (false) { + pnp + pnp + pnp + } + + msg = '[BVT 0.2] Running channel test.' + echo $msg + decho $msg + channeldemo + channeldemo + channeldemo + + msg = '[BVT 0.3] Running ram disk contents test.' + echo $msg + decho $msg + if (false) { + disk + disk + disk + } + + msg = '[BVT 0.4] Running sound driver test.' + echo $msg + decho $msg + play + play + play + + msg = '[BVT 0.5] Running select test.' + echo $msg + decho $msg + select + select + select + + msg = '[BVT 0.6] Running thread test.' + echo $msg + decho $msg + threadtest + threadtest + threadtest + + msg = '[BVT 0.7] Running mptxofy test.' + echo $msg + decho $msg + if (false) { + mptxofy + } + + msg = '[BVT 0.8] Running tasklist.' + echo $msg + decho $msg + tasklist + + msg = '[BVT 0.9] Running dir test.' + echo $msg + decho $msg + dir + dir '/init' + + msg = '[BVT 0.10] Running exception test.' + echo $msg + decho $msg + throw + throwwithlinkstack + + msg = '[BVT 0.11 Running suspend/stop test.' + echo $msg + decho $msg + arg1 = '(& p2 (* 9999999 print 2 delay 2 ) wall )' + arg2 = ' (* 5 print 1 delay 2 ) suspend p2' + arg3 = ' (* 5 print 1 delay 2 ) resume p2' + arg4 = ' (* 5 print 1 delay 2 ) stop p2' + arg5 = ' (* 5 print 1 delay 2 )' + arg = $arg1 . $arg2 . $arg3 . $arg4 . $arg5 + kptest $arg + + msg = '[BVT 0.12] Running singbench test.' + echo $msg + decho $msg + singbench + + msg = '[BVT 0.13] Running monitor test.' + echo $msg + decho $msg + monitortest + + msg = '[BVT 0.14] Running warmboot test.' + echo $msg + decho $msg + warmboot + "; + } + else if (count == 1) { + script = @" + msg = '[BVT 1.0] Running page table test.' + echo $msg + decho $msg + + msg = '[BVT 1.1] Running ram disk contents test.' + echo $msg + decho $msg + if (false) { + disk + } + + msg = '[BVT 1.2] Running sound driver test.' + echo $msg + decho $msg + play + + msg = '[BVT 1.3] Running tasklist.' + echo $msg + decho $msg + tasklist + + msg = '[BVT 1.4] Running dir test.' + echo $msg + decho $msg + dir + dir '/init' + + msg = '[BVT 1.5] Running warmboot test.' + echo $msg + decho $msg + warmboot + "; + } + else { + script = @" + msg = '[BVT 2.0] Running page table test.' + echo $msg + decho $msg + + msg = '[BVT 2.1] Running shutdown test.' + echo $msg + decho $msg + shutdown + "; + } + return ScriptEngine.Run(script, shellControl, new ScriptEngine.CommandLineRunner(RunCommand)); + } + + public static int DoBvt(ShellControl! shellControl, string[]! args) + { +#if false + // A sleezy way of avoiding confusion for new users, + // added very late in the day for the first RDK + // release. + + if (!File.Exists("/init/tasklist")) { + Console.WriteLine("A BVT capable distro is not installed."); + Console.WriteLine("The system should be built with a Distro that is a superset of Distro\\BVT.proj"); + return -1; + } +#endif // false + return Bvt(shellControl, (int)ProcessService.GetKernelBootCount()); + } + + ////////////////////////////////////////////////////////////////////// + // + public static void ReplaceOldCommandString(string! newCommand, int oldCommandLength) + { + // erase the old string + while (oldCommandLength-- > 0) + { + Console.Write("\b"); + } + terminal.GenerateAndSendEscapeSequence(Tty.EscapeCodes.ERASE_FROM_CURSOR); + + // and draw the new one + Console.Write(newCommand); + curpos = newCommand.Length; + totalChars = newCommand.Length; + } + + + private static ArrayList! StringToCharArrayList(string! s) + { + ArrayList al = new ArrayList(); + + for(int i=0; i < s.Length; i++) { + al.Add(s[i]); + } + return al; + } + + private static String! CharArrayToString(ArrayList arr) + { + if (arr == null) return ""; + return CharArrayToString(arr, 0, arr.Count); + } + + private static String! CharArrayToString(ArrayList arr, int start, int len) + { + if (arr == null) return ""; + + assert start >= 0; + assert start+len <= arr.Count; + + if (buildString == null) { + buildString = new StringBuilder(1024); + } + + buildString.Length = 0; + for (int i=start; i < start+len; i++){ + buildString.Append((char)(!)arr[i]); + } + return buildString.ToString(); + } + + private static bool IncrementCurpos() + { + if (++curpos > totalChars) { + curpos = totalChars; + return false; + } + return true; + } + + private static bool DecrementCurpos() + { + if (--curpos < 0) { + curpos = 0; + return false; + } + return true; + } + + + private static void DecrementTotalChars() + { + if (--totalChars < 0) { + totalChars = 0; + } + } + + private static void ShowHistory(ArrayList! a) { + DebugStub.WriteLine("showHistory: count={0}", __arglist(a.Count)); + if (a.Count == 0) return; + + for (int i=0; i < a.Count; i++){ + DebugStub.WriteLine(CharArrayToString((ArrayList)a[i])); + } + } + + public static String! GetCommand(String prompt, ArrayList! history) + { + int key = 0; + bool inEscapeSequence = false; + ArrayList historyWorkingCopy = new ArrayList(); + ArrayList command = new ArrayList(); + Tty.EscapeCodes code; + int repeat; + + // need to make a deep copy of the history now that the elements are + // array lists + for (int i=0; i< history.Count; i++){ + historyWorkingCopy.Add(new ArrayList((ArrayList!) history[i])); + } + + historyWorkingCopy.Add(command); + int historyCurrentSpot = historyWorkingCopy.Count - 1; + curpos = 0; + totalChars = 0; + + Console.WriteLine(); + Console.Write(prompt); + + for (;;) { + key = Console.Read(); + if (key == -1) { + Console.WriteLine("tty EOF reached!"); + return ""; + } + + char c = (char)key; + //DebugStub.WriteLine("key={0:x}, char={1}",__arglist(key, c)); + if ( c == (char) 0x1b) { + inEscapeSequence = true; + terminal.Reset(); + continue; + } + if (inEscapeSequence) { + inEscapeSequence = terminal.ProcessEscape(c, out code, out repeat); + if (inEscapeSequence) continue; + + if (code == Tty.EscapeCodes.UP) { + if (history.Count == 0) { + continue; + } + if (historyCurrentSpot == 0) { + continue; + } + + // now we can move up one row in the history + ArrayList al = (ArrayList!)historyWorkingCopy[historyCurrentSpot]; + int count = al.Count; + historyCurrentSpot--; + ArrayList alNew = (ArrayList)historyWorkingCopy[historyCurrentSpot]; + string s = CharArrayToString(alNew); + ReplaceOldCommandString(s, count); + } + else if (code == Tty.EscapeCodes.DOWN) + { + // if we're at the bottom of the history, don't move, but + // otherwise, move down one + if (history.Count == 0) { + continue; + } + if (historyCurrentSpot == historyWorkingCopy.Count - 1) { + continue; + } + + // now we can move down one row in the history + int count = ((ArrayList!)historyWorkingCopy[historyCurrentSpot]).Count; + historyCurrentSpot++; + ReplaceOldCommandString(CharArrayToString((ArrayList)historyWorkingCopy[historyCurrentSpot]), count); + } + else if (code == Tty.EscapeCodes.LEFT) { + // adjust the cursor + if ( DecrementCurpos()) { + terminal.GenerateAndSendEscapeSequence(Tty.EscapeCodes.LEFT); + } + } + else if (code == Tty.EscapeCodes.RIGHT) { + if ( IncrementCurpos() ) { + terminal.GenerateAndSendEscapeSequence(Tty.EscapeCodes.RIGHT); + } + } + else if (code == Tty.EscapeCodes.INSERT) { + //toggle insert mode + if(insertMode == true) { + insertMode = false; + terminal.SetCursorSize('2'); + } + else { + insertMode = true; + terminal.SetCursorSize('1'); + } + DebugStub.WriteLine("Insert mode: {0}",__arglist(insertMode)); + } + } // escape sequence + + else if (c == '\b') { + int len = ((ArrayList!)historyWorkingCopy[historyCurrentSpot]).Count; + if (len > 0 && curpos > 0 ){ + len = len -1; + DecrementCurpos(); + DecrementTotalChars(); + ((ArrayList!)historyWorkingCopy[historyCurrentSpot]).RemoveAt(curpos); + Console.Write(c); + // re-write any chars after the deleted one + int num = len - curpos; + if (num > 0) { + string rest = + CharArrayToString((ArrayList)historyWorkingCopy[historyCurrentSpot], + curpos, num); + Console.Write(rest); + terminal.GenerateAndSendEscapeSequence(Tty.EscapeCodes.ERASE_FROM_CURSOR); + buildString.Length = 0; + for (int i=0; i < num; i++) { + buildString.Append('\b'); + } + Console.Write(buildString.ToString()); + } + else { + terminal.GenerateAndSendEscapeSequence(Tty.EscapeCodes.ERASE_FROM_CURSOR); + } + } + } + else if (c == '\n') { + Console.WriteLine(); + + if ( ((ArrayList!)historyWorkingCopy[historyCurrentSpot]).Count != 0) + { + return CharArrayToString((ArrayList!)historyWorkingCopy[historyCurrentSpot]); + } + Console.Write(prompt); + } + else { + // Only use the character if it's in the printable ASCII range + if ((c >= 32) && (c <= 126)) // SPACE to "~" + { + + if (insertMode) { + ArrayList a = (ArrayList!)historyWorkingCopy[historyCurrentSpot]; + string s = CharArrayToString(a, curpos, a.Count - curpos); + a.Insert(curpos, c); + Console.Write(c); + Console.Write(s); + string x = ""; + for (int i=0; i < s.Length; i++){ + x = x + '\b'; + } + Console.Write(x); + totalChars++; + curpos++; + //curpos++; + } + else { + if (curpos < totalChars) { + ((ArrayList!)historyWorkingCopy[historyCurrentSpot])[curpos++] = c; + } + else { + ((ArrayList!)historyWorkingCopy[historyCurrentSpot]).Insert(curpos++, c); + totalChars++; + } + Console.Write(c); + } + + } + // else ignore it + } + } + } + + private static ShellCommand FindCommand(string input) + { + foreach (ShellCommand! command in commands) { + if (command.Name == input) { + return command; + } + } + return null; + } + + private static bool IsScript(string name, out string scriptName) + { + ErrorCode errorOut; + NodeType nodeType; + long length; + + if (name == null) { + scriptName = null; + return false; + } + DirectoryServiceContract.Imp! ds = Dir.GetDirectoryServiceContract(); + scriptName = "/init/"+name+".script"; + bool ok = SdsUtils.GetAttributes(scriptName, ds, out length, out nodeType, out errorOut); + Dir.ReleaseDirectoryServiceContract(ds); + return ok; + } + + public static int RunCommand(ShellControl! shellControl, + String[] commandLine, + bool isBackground + ) + { + DirectoryServiceContract.Imp ds; + int exitCode = 0; + string path; + if (commandLine == null || commandLine.Length == 0) { + return exitCode; + } + ShellCommand command = FindCommand(commandLine[0]); + if (command != null) { + try { + exitCode = command.Run(shellControl, commandLine); + } catch (Exception ex) { + Console.WriteLine("Exception: " + ex.Message); + exitCode = -1; + } + } + else if (IsScript(commandLine[0], out path) ) { + String[]! scriptArgs = new String[commandLine.Length + 1]; + Array.Copy(commandLine, 0, scriptArgs, 1, commandLine.Length); + scriptArgs[0] = "script"; + scriptArgs[1] = path; + exitCode = DoScript(shellControl, scriptArgs); + } + else { + try { + UnicodePipeContract.Imp:READY childStdout = shellControl.FreshStdout(); + if (childStdout == null) { + // output multiplexer dead (which means that we shouldn't use Console.WriteLine + DebugStub.WriteLine("-- Can't get new output pipe"); + return -1; + } + + Process process; + string action = null; + + ds = Dir.GetDirectoryServiceContract(); + Manifest manifest = Binder.LoadManifest(ds, commandLine[0]); + Dir.ReleaseDirectoryServiceContract(ds); + + if (manifest != null) { + if (manifest.HasParameters()) { + //Console.WriteLine("Has parameters"); + bool ok = parameters.ProcessParameters(commandLine, + manifest, out process, out action); + if (!ok) { + delete childStdout; + return -1; + } + else { + assert process != null; + int result = manifest.SetEndpoints(process, action, false); + if (result < 0) { + Console.WriteLine("Unable to set all endpoints for this process."); + delete childStdout; + return -1; + } + } + } + else { + //DebugStub.WriteLine("manifest has no parameters"); + //Console.WriteLine("manifest has no parameters"); + process = new Process(commandLine, null, 2); + } + } + else { + Console.WriteLine("'{0}' is not a command or has no manifest", + commandLine[0]); + delete childStdout; + + throw new System.IO.FileNotFoundException(commandLine[0]); + } + + UnicodePipeContract.Imp! stdinImp; + UnicodePipeContract.Exp! stdinExp; + UnicodePipeContract.NewChannel(out stdinImp, out stdinExp); + + SingleProcessJob job = new SingleProcessJob(commandLine, process, stdinImp); + + if (manifest != null && manifest.HasParameters() ) { + int stdinIndex = manifest.GetInputPipeIndex(action, "data"); + if ( stdinIndex == -1) { + Console.WriteLine(" no stdin data pipe specified in manifest"); + delete stdinExp; + } + else process.SetStartupEndpoint(stdinIndex, (Endpoint * in ExHeap) stdinExp); + + int stdoutIndex = manifest.GetOutputPipeIndex(action, "data"); + if ( stdoutIndex == -1) { + Console.WriteLine(" no stdout data pipe specified in manifest"); + delete childStdout; + } + else process.SetStartupEndpoint(stdoutIndex, (Endpoint * in ExHeap) childStdout); + } + else { + process.SetStartupEndpoint(0, (Endpoint * in ExHeap) stdinExp); + process.SetStartupEndpoint(1, (Endpoint * in ExHeap) childStdout); + } + shellControl.Add(job); + + process.Start(); + if (!isBackground){ + exitCode = WaitForJob(job); + if (exitCode != 0) { + Console.WriteLine("-- Exit code: {0}", + exitCode); + } + } + } + catch (ProcessCreateException) { + Console.Write("Unsupported command: {0}", commandLine[0]); + } + catch (FileNotFoundException fe) { + throw fe; + } + catch (Exception e) { + Console.Write("Can't start {0}: Exception '{1}' caught.", + commandLine[0], e.Message); + } + } + return exitCode; + } + + /// + /// Copy and echo characters from shell stdin to job stdin. + /// Wait for either the job to exit gracefully, or for the user + /// to press control-c or control-z. + /// + /// Known limitation: if the child process opens + /// its own keyboard channel, the shell may never see the control-c + /// message. + /// + private static int WaitForJob(Job! job) + { + WaitForChildContract.Imp! imp; + WaitForChildContract.Exp! exp; + WaitForChildContract.NewChannel(out imp, out exp); + + PipeLookAhead cinput = ConsoleInput.AcquireInput(); + UnicodePipeContract.Imp! childStdIn = job.AcquireStdin(); + + ESet childStdInAck = + new ESet(); + ESet childStdInReady = + new ESet(); + + char[] in ExHeap exChar = new [ExHeap] char[1]; + try { + WaitForChildThread.StartWaiting(job.Process, + new TRef(exp)); + + childStdInReady.Add(childStdIn); + + while (true) { + // invariant exChar != null && childStdInReady.Head(ep) || + // exChar == null && childStdInReady.Empty + switch receive { + + case cinput.ControlC(): + job.Stop(); + job.Dispose(); + return 0; + + case cinput.ControlZ() && childStdInReady.Head(ep): + job.Suspend(); + job.ReleaseStdin(ep); + return 0; + + case cinput.Char(ch) && childStdInReady.Head(ep): + // we have a char and childStdin is ready + assert exChar != null; + // echo character + Console.Write(ch); + exChar[0] = (char) ch; + ep.SendWrite(exChar,0,1); + exChar = null; + childStdInAck.Add(ep); + continue; + + case ep.AckWrite(buffer) in childStdInAck: + assert exChar == null; + exChar = buffer; + childStdInReady.Add(ep); + continue; + + case imp.Finish(): + //Console.WriteLine("finish"); + int exitCode = job.ExitCode; + job.Dispose(); + return exitCode; + + case ep.ChannelClosed() in childStdInAck: + delete ep; + continue; + } + } + } + finally { + childStdInReady.Dispose(); + childStdInAck.Dispose(); + ConsoleInput.ReleaseInput(cinput); + delete imp; + delete exChar; + } + } + + // [Hawblitzel] TODO: better ways to wait on a child process + private class WaitForChildThread + { + private Process! process; + private TRef! expRef; + + private WaitForChildThread(Process! process, + TRef! expRef) + { + this.process = process; + this.expRef = expRef; + base(); + } + + public static void StartWaiting(Process process, + TRef! expRef) + { + if (process == null) { + WaitForChildContract.Exp exp = expRef.Acquire(); + exp.SendFinish(); + delete exp; + return; + } + + WaitForChildThread wft = new WaitForChildThread(process, expRef); + Thread t = new Thread(new ThreadStart(wft.Wait)); + t.Start(); + } + + private void Wait() + { + process.Join(); + WaitForChildContract.Exp exp = expRef.Acquire(); + exp.SendFinish(); + delete exp; + } + } + + + // kinda dumb... + private static bool CommandLineSyntaxCheck(string! commandLine) + { + int quoteCount = 0; + for (int i = 0; i < commandLine.Length; i++) { + if (commandLine[i] == '\'') { + quoteCount++; + } + } + + return (quoteCount % 2 == 0); + } + + private static bool InSeparators(char c, char []! separators) + { + for (int i = 0; i < separators.Length; i++) + { + if (separators[i] == c) + return true; + } + return false; + } + + private static ArrayList! Tokenize(string! input, int last, + char []! separators) + { + ArrayList tokens = new ArrayList(); + + for (int i = 0; i <= last;) + { + // Skip separators + while (i <= last && InSeparators(input[i], separators)) + { + i++; + } + + if (i > last) + break; + + // Try to slurp word + int start = i; + while (i <= last && + !InSeparators(input[i], separators) && + input[i] != '\'') + { + i++; + } + if (i != start) + { + tokens.Add(input.Substring(start, i - start)); + } + + // Skip separators + while (i <= last && InSeparators(input[i], separators)) + { + i++; + } + + if (i > last) + break; + + // Try to quoted slurp word + if (input[i] == '\'') + { + start = i; + i++; + while (i <= last && input[i] != '\'') + { + i++; + } + + if (i <= last && input[i] == '\'') + { + tokens.Add(input.Substring(start + 1, i - start - 1)); + i++; + } + else + { + tokens.Add(input.Substring(start, i - start)); + i++; + } + } + } // end for + + return tokens; + } + + private static void BreakCommandLine(string! input, + char []! separators, + out string command, + out string[]! commandArguments, + out bool isBackground) + { + isBackground = false; + + if (!CommandLineSyntaxCheck(input)) { + command = ""; + commandArguments = new string[0]; + return; + } + + // Scan for trailing ampersand first + int last = input.Length - 1; + while (last > 0 && InSeparators(input[last], separators)) + { + last--; + } + + if (input[last] == '&') + { + isBackground = true; + last--; + } + + ArrayList tokens = Tokenize(input, last, separators); + + if (tokens.Count == 0) + { + command = ""; + commandArguments = new string[0]; + isBackground = false; + return; + } + + command = (string) tokens[0]; + commandArguments = new string [tokens.Count]; + for (int i = 0; i < tokens.Count; i++) + { + commandArguments[i] = (string) tokens[i]; + } + } + + public static int RunPipe(ShellControl! shellControl, string! input) + { + DirectoryServiceContract.Imp ds; + int last = input.Length - 1; + ArrayList tokens = Tokenize(input, last, new char[] {'|'}); + string [] commands = new string [tokens.Count]; + for (int i = 0; i < tokens.Count; i++) + { + commands[i] = (string) tokens[i]; + DebugStub.WriteLine("Command : {0}",__arglist(commands[i])); + } + + UnicodePipeContract.Imp! pipeStdin; + UnicodePipeContract.Exp! nonNullNextStdin; + + UnicodePipeContract.NewChannel(out pipeStdin, out nonNullNextStdin); + + UnicodePipeContract.Exp nextStdin = nonNullNextStdin; + + Process[] processes = new Process[tokens.Count]; + // Start up each link process. + + string commandName; + string[]! commandArguments; + bool isBackground = false; + Process process = null; + Process child = null; + string action = null;; + + for (int i = 0; i < tokens.Count; i++) { + if (commands[i] != null) { + + UnicodePipeContract.Imp childStdout; + UnicodePipeContract.Exp childStdoutExp; + + if (i == tokens.Count - 1) { + // last process, hook up to output multiplexer + childStdout = shellControl.FreshStdout(); + childStdoutExp = null; + } + else { + UnicodePipeContract.Imp! nonNullChildImp; + UnicodePipeContract.Exp! nonNullChildExp; + UnicodePipeContract.NewChannel(out nonNullChildImp, out nonNullChildExp); + childStdout = nonNullChildImp; + childStdoutExp = nonNullChildExp; + } + + BreakCommandLine((!)commands[i], new char[] {' '}, + out commandName, out commandArguments, + out isBackground); + + try { + //------------------- + ds = Dir.GetDirectoryServiceContract(); + Manifest manifest = Binder.LoadManifest(ds, commandName); + Dir.ReleaseDirectoryServiceContract(ds); + if (manifest != null) { + if (manifest.HasParameters()) { + bool ok = parameters.ProcessParameters(commandArguments, + manifest, out child, out action); + + if (!ok) { + delete childStdout; + delete childStdoutExp; + delete pipeStdin; + delete nextStdin; + return -1; + } + assert child != null; + manifest.SetEndpoints(child, action, false); + } + else { + DebugStub.WriteLine("manifest has no parameters"); + child = new Process(commandArguments, null, 2); + } + } + else { + Console.WriteLine("'{0}' is not a command or has no manifest",commandArguments[0]); + //process = new Process(commandLine, null, 2); + delete childStdout; + delete childStdoutExp; + delete pipeStdin; + delete nextStdin; + return -1; + } + //-------------------- + + //Process child = new Process(commandArguments, null, 2); + process = child; + processes[i] = process; + // Console.WriteLine("Starting the Process {0}, arg count={1}.", + // commandArguments[0],commandArguments.Length ); + + int stdinIndex = manifest.GetInputPipeIndex(action, "data"); + if ( stdinIndex == -1) { + Console.WriteLine(" no stdin data pipe specified in manifest"); + delete nextStdin; + } + else child.SetStartupEndpoint(stdinIndex, (Endpoint * in ExHeap) nextStdin); + + int stdoutIndex = manifest.GetOutputPipeIndex(action, "data"); + if ( stdoutIndex == -1) { + Console.WriteLine(" no stdout data pipe specified in manifest"); + delete childStdout; + } + else child.SetStartupEndpoint(stdoutIndex, (Endpoint * in ExHeap) childStdout); + + child.Start(); + } + catch (ProcessCreateException) { + Console.Write("Unsupported command: {0}", commandArguments); + delete nextStdin; + delete childStdout; + delete childStdoutExp; + delete pipeStdin; + return -1; + } + catch (Exception e) { + Console.Write("Can't start {0}: Exception '{1}' caught.", commandArguments, + e.Message); + delete nextStdin; + delete childStdout; + delete childStdoutExp; + delete pipeStdin; + return -1; + } + + nextStdin = childStdoutExp; + } + } + assert nextStdin == null; + + PipeJob job = new PipeJob(input, pipeStdin, processes); + shellControl.Add(job); + + int exitCode; + if (job.Process != null && !isBackground) + { + exitCode = WaitForJob(job); + // DebugStub.WriteLine("pipe: wait ended"); + + if (exitCode != 0) { + Console.WriteLine("-- Exit code: {0}", + exitCode); + } + return exitCode; + } + else { + return 0; + } + } + + + private static bool HasPipes(string! input) + { + if (input.IndexOf('|',0) == -1 ) return false; + else { + return true; + } + } + + private static ShellControl! StartOutputPipeThread() { + UnicodePipeContract.Exp! newOutputExp; + UnicodePipeContract.Imp! newOutputImp; + UnicodePipeContract.NewChannel(out newOutputImp, out newOutputExp); + + UnicodePipeContract.Imp stdOut = ConsoleOutput.Swap(newOutputImp); + if (stdOut == null) { + DebugStub.WriteLine("Shell not connected to a pipe output!"); + throw new ApplicationException("Can't go on"); + } + PipeMultiplexer pm = PipeMultiplexer.Start(stdOut, newOutputExp); + return new ShellControl(pm); + } + private static bool Compare(ArrayList! al, string! s) + { + if (al.Count != s.Length) return false; + for (int i=0; i < s.Length; i++) { + if ( (char)(!)al[i] != s[i] ) return false; + } + return true; + } + + internal static int AppMain(Parameters! config) + { + int exitCode = 0; + + terminal = new Terminal(); + Binder.Initialize(); + parameters = new ParameterProcessor(); + + Console.WriteLine("Singularity Shell (PID={0})", + ProcessService.GetCurrentProcessId()); + + + ShellControl! shellControl = + StartOutputPipeThread(); + + string prompt = "Singularity>"; + string loginName = Principal.Self().GetName(); + int i = loginName.IndexOf('+'); + int j = loginName.IndexOf('@'); + if (i > 0 && j > 0 && i > j) { + prompt = String.Format("Singularity ({0})>", loginName.Substring(j+1, i-(j+1))); + } + + try { + Console.WriteLine(); + Console.WriteLine("Type `help' to get a list of valid commands."); + ArrayList history = new ArrayList(); + + if (config.args != null ) { + //String[]! scriptArgs = new String[config.args.Length - 1]; + //Array.Copy(config.args, 1, scriptArgs, 0, scriptArgs.Length); + + try { + exitCode = RunCommand(shellControl, config.args, false); + } + catch (FileNotFoundException) { + } + + if (done) { + // we pretend we didn't connect to the keyboard. + } + } + + // At startup, run the script 'startup.script'. + DoScript(shellControl, new string[] { "script", "/init/startup.script" }); + + while (!done) { + DebugStub.WriteLine("--- Singularity Shell Prompt ---"); + Tracing.Log(Tracing.Warning, "--- Singularity Shell Prompt ---"); + String inputs = GetCommand(prompt, history); + if (inputs.Length == 0) { + continue; + } + + Monitoring.Log(Monitoring.Provider.Shell, + (ushort)ShellEvent.RunCommand, + inputs); + + if (history.Count != 0 ) { + bool same = Compare ((ArrayList!)history[history.Count - 1], inputs); + if (!same) { + history.Add(StringToCharArrayList(inputs)); + } + } + else { + history.Add(StringToCharArrayList(inputs)); + } + string commandName; + string[]! commandArguments; + bool isBackground; + + //Ask for the pipe + if (HasPipes(inputs)) { + RunPipe(shellControl, inputs); + } + else { + BreakCommandLine(inputs, new char[] {' '}, + out commandName, out commandArguments, + out isBackground); + try { + exitCode = RunCommand(shellControl, commandArguments, isBackground); + } + catch (FileNotFoundException) { + // No action needed, expected if user mistypes + // command. + } + } + + } + } + catch (Exception e) { + Console.WriteLine("Caught {0}", e.Message); + return 1; + } + finally { + shellControl.Dispose(); + } + + Console.WriteLine("Shell (PID={0}) Terminating w/ 0x{1:x4}.", + ProcessService.GetCurrentProcessId(), + exitCode); + DebugStub.WriteLine("Shell exiting w/ {0}.", __arglist(exitCode)); + return exitCode; + } + } +} diff --git a/base/Applications/Shell/Terminal.sg b/base/Applications/Shell/Terminal.sg new file mode 100644 index 0000000..fc4f8dc --- /dev/null +++ b/base/Applications/Shell/Terminal.sg @@ -0,0 +1,283 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Shell.cs +// +// Note: +// + +using System; +//using Microsoft.Singularity; +//using Microsoft.SingSharp; +using Pipe = Microsoft.Singularity.Io.Tty2006; + +namespace Microsoft.Singularity.Applications +{ + + class Terminal + { + private bool openBracketSeen; + private string numberString; + private bool haveNumber; + private bool inNumber; + private int repeat; + private string history; //debug remove + + public Terminal() + { + openBracketSeen = false; + inNumber = false; + haveNumber = false; + numberString = ""; + history = ""; + } + + public void Reset() + { + openBracketSeen = false; + inNumber = false; + haveNumber = false; + history = ""; + numberString = ""; + } + + public bool ProcessEscape(char c, out Pipe.EscapeCodes code, out int repeat) + { + code = Pipe.EscapeCodes.NOCODE; + repeat = 1; + bool notProcessed = false; + + history = history + c; + //DebugStub.WriteLine("esc: processing({0}. history={1})",__arglist(c, history)); + + if (Char.IsWhiteSpace(c)) { + code = Pipe.EscapeCodes.NOCODE; + return true; + } + + if ( c == '[') { + Reset(); + openBracketSeen = true; + code = Pipe.EscapeCodes.NOCODE; + return true; + } + + if (Char.IsNumber(c) ) { + if (!inNumber){ + inNumber = true; + } + numberString = numberString +c; + return true; + } + + if (Char.IsLetter(c)) { + if (inNumber) { + inNumber = false; + haveNumber = true; + repeat = int.Parse(numberString); + } + switch (c) { + case 'A': + code = Pipe.EscapeCodes.UP; + break; + case 'B': + code = Pipe.EscapeCodes.DOWN; + break; + case 'C': + code = Pipe.EscapeCodes.RIGHT; + break; + case 'D': + code = Pipe.EscapeCodes.LEFT; + break; + case 'K': + code = Pipe.EscapeCodes.ERASE_FROM_CURSOR; + break; + case 'S': + code = Pipe.EscapeCodes.SET_CURSOR_SIZE; + break; + case 'J': + if (haveNumber) { + if (repeat == 2) { + code = Pipe.EscapeCodes.CLEAR_SCREEN; + } + } + break; + default: + //DebugStub.Break(); + notProcessed = true; + break; + } + if (notProcessed) { + return true; + } + else { + Reset(); + return false; + } + + } + else if ( c == '~' ) { + DebugStub.WriteLine("term: ~ seen. inNumber={0}", __arglist(inNumber)); + if (inNumber) { + inNumber = false; + haveNumber = true; + int num = int.Parse(numberString); + DebugStub.WriteLine("term: Number={0}", __arglist(num)); + switch (num) { + case 1: + code = Pipe.EscapeCodes.HOME; + break; + case 2: + code = Pipe.EscapeCodes.INSERT; + break; + case 3: + code = Pipe.EscapeCodes.DELETE; + break; + case 4: + code = Pipe.EscapeCodes.END; + break; + case 5: + code = Pipe.EscapeCodes.PAGE_UP; + break; + case 6: + code = Pipe.EscapeCodes.PAGE_DOWN; + break; + default: + notProcessed = true; + break; + } + if (notProcessed) { + return true; + } + else { + Reset(); + return false; + } + } + // hit ~ but not processing a number? + DebugStub.Break(); + } + return false; + } + + private Pipe.EscapeCodes GetCodeFromSequence(char[]! sequence) + { + int pos, num, qual; + string numString= ""; + string qualString= ""; + bool qualifierEncountered = false; + num = 0; + + assert sequence[0] == '['; + for (pos=1; pos < sequence.Length; pos++) { + if (sequence[pos] == ';') { + // handle qualifier + qualifierEncountered = true; + continue; + } + if (sequence[pos] =='~') { + //end of sequence + break; + } + if (qualifierEncountered) { + qualString = qualString + sequence[pos]; + } + else { + numString = numString + sequence[pos]; + } + } + try { + num = int.Parse(numString); + if (qualifierEncountered) { +#if false + qual = int.Parse(qualString); + DebugStub.WriteLine("shell: key qualifier encountered {0} in sequence ", + __arglist(qual)); +#endif + } + } + catch (Exception e) { + Console.WriteLine("Exception encountered: {0}", e.ToString()); + } + return (Pipe.EscapeCodes) num; + + } + + public void SetCursorSize(char size) + { + char[] buffer = new char[10]; + int pos; + + if (buffer != null) { + buffer[0] = (char) 0x1b; + buffer[1] = '['; + pos = 2; + buffer[pos++] = size; + buffer[pos++] = 'S'; + Console.Write(buffer,0,pos); + } + } + + public void GenerateAndSendEscapeSequence(Pipe.EscapeCodes code) + { + char[] buffer = new char[10]; + int pos; + + if (buffer != null) { + buffer[0] = (char) 0x1b; + buffer[1] = '['; + pos = 2; + switch (code) { + case Pipe.EscapeCodes.PAGE_UP: + buffer[pos++] = '5'; + buffer[pos++] = '~'; + break; + case Pipe.EscapeCodes.PAGE_DOWN: + buffer[pos++] = '6'; + buffer[pos++] = '~'; + break; + case Pipe.EscapeCodes.UP: + buffer[pos++] = 'A'; + break; + case Pipe.EscapeCodes.DOWN: + buffer[pos++] = 'B'; + break; + case Pipe.EscapeCodes.LEFT: + buffer[pos++] = 'D'; + break; + case Pipe.EscapeCodes.RIGHT: + buffer[pos++] = 'C'; + break; + case Pipe.EscapeCodes.ERASE_FROM_CURSOR: + buffer[pos++] = 'K'; + break; + case Pipe.EscapeCodes.CLEAR_SCREEN: + buffer[pos++] = '2'; + buffer[pos++] = 'J'; + break; + case Pipe.EscapeCodes.HOME: + buffer[pos++] = '1'; + buffer[pos++] = '~'; + break; + case Pipe.EscapeCodes.END: + buffer[pos++] = '4'; + buffer[pos++] = '~'; + break; + case Pipe.EscapeCodes.INSERT: + buffer[pos++] = '2'; + buffer[pos++] = '~'; + break; + case Pipe.EscapeCodes.DELETE: + buffer[pos++] = '~'; + buffer[pos++] = '3'; + break; + } + + Console.Write(buffer,0,pos); + } + } + } +} diff --git a/base/Applications/Shell/clock0.bmp b/base/Applications/Shell/clock0.bmp new file mode 100644 index 0000000..1f7bd82 Binary files /dev/null and b/base/Applications/Shell/clock0.bmp differ diff --git a/base/Applications/Shell/clock2.bmp b/base/Applications/Shell/clock2.bmp new file mode 100644 index 0000000..3c2c0b0 Binary files /dev/null and b/base/Applications/Shell/clock2.bmp differ diff --git a/base/Applications/Shell/clock4.bmp b/base/Applications/Shell/clock4.bmp new file mode 100644 index 0000000..6f6d794 Binary files /dev/null and b/base/Applications/Shell/clock4.bmp differ diff --git a/base/Applications/Shell/clock6.bmp b/base/Applications/Shell/clock6.bmp new file mode 100644 index 0000000..34c006f Binary files /dev/null and b/base/Applications/Shell/clock6.bmp differ diff --git a/base/Applications/Shell/script.lang b/base/Applications/Shell/script.lang new file mode 100644 index 0000000..6ecde28 --- /dev/null +++ b/base/Applications/Shell/script.lang @@ -0,0 +1,309 @@ + +[fields] +{ + bool TRACE = false; +} + +[init] +{ + + +} + +[tokens] +{ + if := "^if" + else := "^else" + while := "^while" + bool := "^(true|false)" + equals_compare := "^==" + + lt := "^<" + le := "^<=" + gt := "^>" + ge := "^>=" + semicolon := "^;" + integer := "^-?\d+" + interp := "^""(([^\\""\r\n])|(\\.))*""" + { tok.value = ((String) tok.value).Replace("\"",""); } + + + string := "^'([^'])*'" + { tok.value = ((String) tok.value).Replace("'",""); } + + comment := "^#.*" + { tok.value = null; } + + word := "^\w+" + div := "^/" + equals := "^=" + plus := "^\+" + mult := "^\*" + mod := "^%" + concat := "^\." + and := "^&&" + ampersand := "^&" + or := "^\|\|" + not := "^\!" + lparen := "^\(" + rparen := "^\)" + lbrace := "^{" + rbrace := "^}" + minus := "^-" + + reference := "^((\$\w+)|(\$\(\w+\))|(\$\?)|(\$\(\?\))|(\$#)|(\$\(#\)))" + { + tok.value = ((String) tok.value).Replace("$",""); + tok.value =((String) tok.value).Replace("(",""); + tok.value = ((String) tok.value).Replace(")",""); + } + + newline := "^\n" + { tok.optional = true; } + + whitespace := "^[ \f\r\t\v]+" + { tok.value = null; } + + lparen rparen > not + lparen rparen not > mult div mod + not lparen rparen mult div mod > plus minus concat and or +} + + +[grammar] +{ + S => STMT_LIST:list + { + if(TRACE) Console.WriteLine("Reducing statement list to programm"); + value = new ScriptEngine.Block((ArrayList) list); + } + + STMT_LIST => epsilon + { + if(TRACE) Console.WriteLine("Rsmt epsilon"); + value = new ArrayList(); + } + + STMT_LIST => STMT:stmt STMT_LIST:list + { + if(TRACE) Console.WriteLine("Reduction: adding statement to statement list"); + ((ArrayList) list).Insert(0,stmt); + value = list; + } + + STMT => if lparen E:cond rparen lbrace STMT_LIST:stmts rbrace + { + if(TRACE) Console.WriteLine("Reducing if"); + value = new ScriptEngine.If((ScriptEngine.Expression) cond, new ScriptEngine.Block((ArrayList) stmts)); + } + STMT => if lparen E:cond rparen lbrace STMT_LIST:trueBranch rbrace else lbrace STMT_LIST:falseBranch rbrace + { + if(TRACE) Console.WriteLine("Reducing if then else"); + value = new ScriptEngine.IfThenElse((ScriptEngine.Expression) cond, new ScriptEngine.Block((ArrayList) trueBranch), new ScriptEngine.Block((ArrayList) falseBranch)); + } + + STMT => while lparen E:cond rparen lbrace STMT_LIST:block rbrace + { + if(TRACE) Console.WriteLine("Reducing while loop"); + value = new ScriptEngine.While((ScriptEngine.Expression) cond, new ScriptEngine.Block((ArrayList) block)); + } + + STMT => word:var equals E:expr newline + { + if(TRACE) Console.WriteLine("Reducing assignment: " + var + "= " + expr); + value = new ScriptEngine.Assign((String) var, (ScriptEngine.Expression) expr); + } + + STMT => COMMAND:comm + { + if(TRACE) Console.WriteLine("Reducing command list to statement: " + comm); + value = new ScriptEngine.Command((ArrayList) comm); + } + + STMT => ASYNC_COMMAND:comm + { + if(TRACE) Console.WriteLine("Reducing command list to statement: " + comm); + value = new ScriptEngine.Command((ArrayList) comm, true); + } + + + COMMAND => COMM:elem COMM_LIST:list newline + { + if(TRACE) Console.WriteLine("reducing command list to command"); + ((ArrayList) list).Insert(0,elem); + value = list; + } + + + ASYNC_COMMAND => COMM:elem COMM_LIST:list ampersand newline + { + if(TRACE) Console.WriteLine("reducing command list to command"); + ((ArrayList) list).Insert(0,elem); + value = list; + } + + + + COMM_LIST => COMM:elem COMM_LIST:list + { + ArrayList rest = (ArrayList)list; + if(TRACE) { + Console.WriteLine("reducing commlist: '{0}'", elem); + int i=0; + foreach (object o in rest) { + Console.WriteLine(" [{0}] = {1}", i++, o); + } + } + rest.Insert(0,elem); + value = list; + } + + COMM_LIST => epsilon + { + value = new ArrayList(); + } + + COMM => reference:varRef + { + if(TRACE) Console.WriteLine("Reducing variable in command reference: '{0}'", varRef); + value = new ScriptEngine.VariableReference((String) varRef); + } + + COMM => interp:str + { + if(TRACE) Console.WriteLine("Reducing interp: '{0}'", str); + value = new ScriptEngine.StringInterpolation((String) str); + } + + COMM => string:str + { + if(TRACE) Console.WriteLine("Reducing string: '{0}'", str); + value = new ScriptEngine.StringLiteral((String) str); + } + + COMM => word:w + { + if(TRACE) Console.WriteLine("Reducing command word: '{0}'", w); + value = new ScriptEngine.StringLiteral((String) w); + } + + COMM => integer:integer + { value = new ScriptEngine.IntegerLiteral(Int32.Parse((String) integer)); } + + + + E => lparen E:e rparen + { value = e; } + + E => integer:intString + { + if(TRACE) Console.WriteLine("Reducing integer literal expression: " + intString); + value = new ScriptEngine.IntegerLiteral(Int32.Parse((String) intString)); + } + + E => interp:interp + { value = new ScriptEngine.StringInterpolation((String) interp); } + E => string:strVal + { + if(TRACE) Console.WriteLine("Reducing string literal expression: " + strVal); + value = new ScriptEngine.StringLiteral((String) strVal); + } + + E => bool:boolVal + { + if(TRACE) Console.WriteLine("reducing bool literal expression"); + value = new ScriptEngine.BooleanLiteral(Boolean.Parse((String) boolVal)); + } + + E => reference:varRef + { + value = new ScriptEngine.VariableReference((String) varRef); + } + + E => E:e1 and E:e2 + { + if(TRACE) Console.WriteLine("reducing to boolean and"); + value = new ScriptEngine.And((ScriptEngine.Expression) e1, (ScriptEngine.Expression) e2); + } + + E => E:e1 or E:e2 + { + if(TRACE) Console.WriteLine("reducing to boolean or"); + value = new ScriptEngine.Or((ScriptEngine.Expression) e1, (ScriptEngine.Expression) e2); + } + + E => E:e1 lt E:e2 + { + if(TRACE) Console.WriteLine("reducing to boolean less"); + value = new ScriptEngine.Less((ScriptEngine.Expression) e1, (ScriptEngine.Expression) e2); + } + + E => E:e1 le E:e2 + { + if(TRACE) Console.WriteLine("reducing to boolean less than or equal"); + value = new ScriptEngine.LessEqual((ScriptEngine.Expression) e1, (ScriptEngine.Expression) e2); + } + + E => E:e1 equals_compare E:e2 + { + if(TRACE) Console.WriteLine("reducing to boolean =="); + value = new ScriptEngine.Equal((ScriptEngine.Expression) e1, (ScriptEngine.Expression) e2); + } + + E => E:e1 gt E:e2 + { + if(TRACE) Console.WriteLine("reducing to boolean greater"); + value = new ScriptEngine.Greater((ScriptEngine.Expression) e1, (ScriptEngine.Expression) e2); + } + E => E:e1 ge E:e2 + { + if(TRACE) Console.WriteLine("reducing to boolean greater than or equal"); + value = new ScriptEngine.GreaterEqual((ScriptEngine.Expression) e1, (ScriptEngine.Expression) e2); + } + + E => not E:e1 + { + if(TRACE) Console.WriteLine("reducing to boolean and"); + value = new ScriptEngine.Negate((ScriptEngine.Expression) e1); + } + + E => reference:varRef + { + if(TRACE) Console.WriteLine("Reducing expression variable reference"); + value = new ScriptEngine.VariableReference((String) varRef); + } + + E => E:e1 plus E:e2 + { + if(TRACE) Console.WriteLine("Reducing plus"); + value = new ScriptEngine.Add((ScriptEngine.Expression) e1, (ScriptEngine.Expression) e2); + } + + E => E:e1 minus E:e2 + { + if(TRACE) Console.WriteLine("Reducing minus"); + value = new ScriptEngine.Subtract((ScriptEngine.Expression) e1, (ScriptEngine.Expression) e2); + } + + E => E:e1 mult E:e2 + { + if(TRACE) Console.WriteLine("Reducing multiply"); + value = new ScriptEngine.Multiply((ScriptEngine.Expression) e1, (ScriptEngine.Expression) e2); + } + E => E:e1 mod E:e2 + { + if(TRACE) Console.WriteLine("Reducing modulus"); + value = new ScriptEngine.Mod((ScriptEngine.Expression) e1, (ScriptEngine.Expression) e2); + } + + E => E:e1 div E:e2 + { + if(TRACE) Console.WriteLine("Reducing divide"); + value = new ScriptEngine.Divide((ScriptEngine.Expression) e1, (ScriptEngine.Expression) e2); + } + E => E:e1 concat E:e2 + { + value = new ScriptEngine.Concat((ScriptEngine.Expression) e1, (ScriptEngine.Expression) e2); + } + +} \ No newline at end of file diff --git a/base/Applications/Sleep/Sleep.cs b/base/Applications/Sleep/Sleep.cs new file mode 100644 index 0000000..8b5014a --- /dev/null +++ b/base/Applications/Sleep/Sleep.cs @@ -0,0 +1,93 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Sleep.cs +// +// Note: Shell utility to pause execution. +// + +using System; +using System.Threading; +// using Microsoft.Singularity.V1.Services; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications +{ + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [LongParameter( "seconds", Mandatory=true, Position=0, HelpMessage="seconds")] + internal long seconds; + + [BoolParameter( "m", Default=false , HelpMessage="treat time as milliseconds")] + internal bool doMilli; + + [BoolParameter( "v", Default=false , HelpMessage="verbose output")] + internal bool doVerbose; + + reflective internal Parameters(); + + internal int AppMain() { + return Sleep.AppMain(this); + } + } + + public class Sleep + { + private static void ConsoleWriteDateTime(string preamble, DateTime dt) + { + Console.WriteLine("{0}{1:d4}/{2:d2}/{3:d2} {4:d2}:{5:d2}:{6:d2}.{7:d3}", + preamble, dt.Year, dt.Month, dt.Day, + dt.Hour, dt.Minute, dt.Second, dt.Millisecond); + } + + private static void ConsoleWriteDateTime(string preamble, TimeSpan sp) + { + Console.WriteLine("{0}{1}", preamble, sp.ToString()); + + } + + + private static void DoDate(string pre) + { + Console.WriteLine(pre + "cycles: {0}", Processor.CycleCount ); + ConsoleWriteDateTime(pre , DateTime.UtcNow); + } + + internal static int AppMain(Parameters! config) + { + try { + uint seconds = (uint) config.seconds; + + if(config.doVerbose) DoDate(" pre "); + if (config.doMilli) { + Thread.Sleep(TimeSpan.FromMilliseconds(seconds)); + } + else { + Thread.Sleep(TimeSpan.FromSeconds(seconds)); + } + if(config.doVerbose) DoDate(" post "); + return 0; + } + catch (ArgumentOutOfRangeException) { // From Thread.Sleep + Console.WriteLine("Value too large :- \"{0}\"", config.seconds); + } + return 1; + } + } +} diff --git a/base/Applications/Sleep/Sleep.csproj b/base/Applications/Sleep/Sleep.csproj new file mode 100644 index 0000000..0059bf9 --- /dev/null +++ b/base/Applications/Sleep/Sleep.csproj @@ -0,0 +1,27 @@ + + + + + + + Exe + Sleep + + + + + + + + + diff --git a/base/Applications/Slides/DemoDeck.ppt b/base/Applications/Slides/DemoDeck.ppt new file mode 100644 index 0000000..016306a Binary files /dev/null and b/base/Applications/Slides/DemoDeck.ppt differ diff --git a/base/Applications/Slides/EndOfShow.bmp b/base/Applications/Slides/EndOfShow.bmp new file mode 100644 index 0000000..42f8b89 Binary files /dev/null and b/base/Applications/Slides/EndOfShow.bmp differ diff --git a/base/Applications/Slides/Resources.cpp b/base/Applications/Slides/Resources.cpp new file mode 100644 index 0000000..65e4917 --- /dev/null +++ b/base/Applications/Slides/Resources.cpp @@ -0,0 +1,13 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// + +////////////////////////////////////////////////////////////////////////////// +// +// Stub +// +// +#include "hal.h" + +#include "Content.cpp" diff --git a/base/Applications/Slides/Slide.bmp b/base/Applications/Slides/Slide.bmp new file mode 100644 index 0000000..42f8b89 Binary files /dev/null and b/base/Applications/Slides/Slide.bmp differ diff --git a/base/Applications/Slides/Slide1.BMP b/base/Applications/Slides/Slide1.BMP new file mode 100644 index 0000000..9a60239 Binary files /dev/null and b/base/Applications/Slides/Slide1.BMP differ diff --git a/base/Applications/Slides/Slide2.BMP b/base/Applications/Slides/Slide2.BMP new file mode 100644 index 0000000..5054ee5 Binary files /dev/null and b/base/Applications/Slides/Slide2.BMP differ diff --git a/base/Applications/Slides/Slide3.BMP b/base/Applications/Slides/Slide3.BMP new file mode 100644 index 0000000..c3aef2d Binary files /dev/null and b/base/Applications/Slides/Slide3.BMP differ diff --git a/base/Applications/Slides/Slide4.BMP b/base/Applications/Slides/Slide4.BMP new file mode 100644 index 0000000..97207bd Binary files /dev/null and b/base/Applications/Slides/Slide4.BMP differ diff --git a/base/Applications/Slides/Slide5.BMP b/base/Applications/Slides/Slide5.BMP new file mode 100644 index 0000000..7532878 Binary files /dev/null and b/base/Applications/Slides/Slide5.BMP differ diff --git a/base/Applications/Slides/Slides.csproj b/base/Applications/Slides/Slides.csproj new file mode 100644 index 0000000..d5bf87c --- /dev/null +++ b/base/Applications/Slides/Slides.csproj @@ -0,0 +1,36 @@ + + + + + + + Exe + Slides + true + + + + + + Slides + Microsoft.Singularity.Applications + Content + true + + + + + + + + + + diff --git a/base/Applications/Slides/Slides.sg b/base/Applications/Slides/Slides.sg new file mode 100644 index 0000000..d9766c4 --- /dev/null +++ b/base/Applications/Slides/Slides.sg @@ -0,0 +1,502 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: slides.cs +// +// Note: +// + +using System; +using System.Text; +using System.GC; +using System.Runtime.Remoting; +using System.Runtime.InteropServices; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Collections; +using System.Diagnostics; + +using Microsoft.Singularity; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.V1.Services; +using Microsoft.Singularity.Io; + +using Microsoft.Singularity.Channels; +using Keyboard = Microsoft.Singularity.Io.Keyboard; + +namespace Microsoft.Singularity.Applications +{ + public class SlideShow + { + public static KeyboardDeviceContract.Imp:Ready OpenKeyboard(string! devName) + { + KeyboardDeviceContract.Exp! exp; + KeyboardDeviceContract.Imp! imp; + KeyboardDeviceContract.NewChannel(out imp, out exp); + + DirectoryServiceContract.Imp ns = DirectoryService.NewClientEndpoint(); + + ErrorCode errorOut; + if (SdsUtils.Bind(devName, ns, exp, out errorOut)) { + switch receive { + case imp.Success(): + break; + case imp.ContractNotSupported(): + throw new Exception("Contract not supported"); + case imp.ChannelClosed(): + throw new Exception("Didn't imp.RecvActConnect"); + } + delete ns; + return imp; + } + + if (errorOut == ErrorCode.ChannelClosed) + { + // Why is this a special case? + throw new Exception("Encountered a ChannelClosed while opening Keyboard"); + } + DebugStub.WriteLine( + "OpenKeyboard lookup of {0} failed ({1})\n", + __arglist(devName, SdsUtils.ErrorCodeToString(errorOut)) + ); + + delete imp; + delete ns; + return null; + } + + public static VideoDeviceContract.Imp:Ready OpenVideo(string! devName) + { + VideoDeviceContract.Exp! exp; + VideoDeviceContract.Imp! imp; + VideoDeviceContract.NewChannel(out imp, out exp); + + DirectoryServiceContract.Imp ns = DirectoryService.NewClientEndpoint(); + + ErrorCode errorCode; + if (SdsUtils.Bind(devName, ns, exp, out errorCode)) { + switch receive { + case imp.Success(): + break; + case imp.ContractNotSupported(): + throw new Exception("Contract not supported"); + case imp.ChannelClosed(): + throw new Exception("Didn't imp.RecvActConnect"); + } + delete ns; + return imp; + } + + DebugStub.WriteLine( + "OpenVideo lookup of {0} failed : {1}\n", + __arglist(devName, SdsUtils.ErrorCodeToString(errorCode)) + ); + delete imp; + delete ns; + return null; + } + + public static int Main(string[] args) + { + Console.WriteLine("{0,13:f6}", (double)1.0); + Console.WriteLine("{0,13:f6}", (double)10.0); + Console.WriteLine("{0,13:f6}", (double)100.0); + Console.WriteLine("{0,13:f6}", (double)1000.0); + Console.WriteLine("{0,13:f6}", (double)10000.0); + Console.WriteLine("{0,13:f6}", (double)100000.0); + Console.WriteLine("{0,13:f6}", (double)0.1); + Console.WriteLine("{0,13:f6}", (double)0.01); + Console.WriteLine("{0,13:f6}", (double)0.001); + Console.WriteLine("{0,13:f6}", (double)0.0001); + Console.WriteLine("{0,13:f6}", (double)0.00001); + Console.WriteLine("{0,13:f6}", (double)0.000001); + + VideoDeviceContract.Imp video = OpenVideo("/dev/video"); + + Console.WriteLine("Singularity Slide Show Viewer (PID={0})", + ProcessService.GetCurrentProcessId()); + DebugStub.WriteLine("Singularity Slide Show Viewer (PID={0})", + __arglist(ProcessService.GetCurrentProcessId())); + + if (video == null) { + Console.WriteLine("Can only display slides on a graphic display."); + return 1; + } + if (Slides.Content == null || Slides.Content.Length == 0) { + Console.WriteLine("No slides to display."); + delete video; + return 1; + } + + KeyboardDeviceContract.Imp keyboard = OpenKeyboard("/dev/keyboard"); + if (keyboard == null) { + // TODO: show keyboardless slides with timer? + delete video; + return 1; + } + int slide = 0; + + byte[] currentSlide = (!)Slides.Content[slide]; + byte[]! in ExHeap current = new[ExHeap] byte [currentSlide.Length]; + Bitter.FromByteArray(current, 0, currentSlide.Length, + currentSlide, 0); + video.SendFill(0, 0, 1023, 767, 0); + video.RecvAckFill(); + video.SendBitBltBmp(32, 16, current); + video.RecvAckBitBltBmp(out current); + + try { + for (;;) { + int x; + int y; + bool go_back = false; + bool go_fore = false; + bool go_home = false; + bool go_end = false; + + uint key = 0; + keyboard.SendGetKey(); + switch receive { + case keyboard.AckKey(ikey): + key = ikey; + break; + case keyboard.NakKey(): + break; + case keyboard.ChannelClosed(): + throw new Exception("Didn't get reply from Keyboard"); + } + + if (key == 0) { + Console.WriteLine("GetKey failed, try typing `start slides'."); + DebugStub.WriteLine("GetKey failed."); + Tracing.Log(Tracing.Warning, "GetKey failed."); + break; + } + if ((key & (uint)Keyboard.Qualifiers.KEY_DOWN) == 0) { + continue; + } + if ((key & (uint)Keyboard.Qualifiers.KEY_MOUSE) == 0) { + char c = (char)(key & (uint)Keyboard.Qualifiers.KEY_BASE_CODE); + + switch (c) { + case (char)Keyboard.Keys.ESCAPE: + delete video; + delete keyboard; + delete current; + return 0; + case (char)Keyboard.Keys.HOME: + go_home = true; + break; + case (char)Keyboard.Keys.UP_ARROW: + case (char)Keyboard.Keys.LEFT_ARROW: + case (char)Keyboard.Keys.PAGE_UP: + case '\b': + go_back = true; + break; + case (char)Keyboard.Keys.DOWN_ARROW: + case (char)Keyboard.Keys.RIGHT_ARROW: + case (char)Keyboard.Keys.PAGE_DOWN: + case '\n': + case ' ': + go_fore = true; + break; + case (char)Keyboard.Keys.END: + go_end = true; + break; + default: + continue; + } + } + else { + if ((key & (uint)Keyboard.Qualifiers.MOUSE_BUTTON_1) != 0) { + go_fore = true; + } + else if ((key & (uint)Keyboard.Qualifiers.MOUSE_BUTTON_0) != 0) { + go_back = true; + } + else { + continue; + } + } + + if (go_home) { + slide = 0; + currentSlide = (!)Slides.Content[slide]; + } + else if (go_fore) { + ++slide; + if (slide >= Slides.Content.Length) { + slide = Slides.Content.Length; + currentSlide = (!)EndOfShow.Content[0]; + } + else { + currentSlide = (!)Slides.Content[slide]; + } + } + else if (go_back) { + if (--slide < 0) { + slide = 0; + } + currentSlide = (!)Slides.Content[slide]; + } + else if (go_end) { + slide = Slides.Content.Length; + currentSlide = (!)EndOfShow.Content[0]; + } + + if (current.Length < currentSlide.Length) { + delete current; + current = new[ExHeap] byte [currentSlide.Length]; + } + Bitter.FromByteArray(current, 0, currentSlide.Length, + currentSlide, 0); + video.SendFill(0, 0, 1023, 767, 0); + video.RecvAckFill(); + video.SendBitBltBmp(32, 16, current); + video.RecvAckBitBltBmp(out current); + } + } + catch (Exception e) { + DebugStub.WriteLine("Caught exception: {0}", __arglist(e)); + } + + delete keyboard; + delete video; + delete current; + + return 0; + } + } + + public class EndOfShow { + public static readonly byte[][]! Content = { + new byte[] { + 0x42,0x4d,0x0e,0x10,0x00,0x00,0x00,0x00, + 0x00,0x00,0x36,0x00,0x00,0x00,0x28,0x00, + 0x00,0x00,0x67,0x00,0x00,0x00,0x0d,0x00, + 0x00,0x00,0x01,0x00,0x18,0x00,0x00,0x00, + 0x00,0xff,0xd8,0x0f,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x98,0xff, + 0x00,0x00,0x00,0x98,0xff,0x00,0x00,0x00, + 0xfe,0xff,0x00,0x00,0x00,0xfa,0xff,0xff, + 0xff,0xff,0xfe,0xff,0x00,0x00,0x00,0x03, + 0x00,0xff,0xff,0xff,0xfd,0xff,0x00,0x00, + 0x00,0x03,0x00,0xff,0xff,0xff,0xfd,0xff, + 0x00,0x00,0x00,0xfc,0xff,0xff,0xff,0xff, + 0xfa,0xff,0x00,0x00,0x00,0xfd,0xff,0xff, + 0xff,0xff,0xfd,0xff,0x00,0x00,0x00,0x03, + 0x00,0xff,0xff,0xff,0xfa,0xff,0x00,0x00, + 0x00,0xfd,0xff,0xff,0xff,0xff,0xfd,0xff, + 0x00,0x00,0x00,0x03,0x00,0xff,0xff,0xff, + 0xfe,0xff,0x00,0x00,0x00,0x03,0x00,0xff, + 0xff,0xff,0xfd,0xff,0x00,0x00,0x00,0xfc, + 0xff,0xff,0xff,0xff,0xfd,0xff,0x00,0x00, + 0x00,0xfd,0xff,0xff,0xff,0xff,0xf9,0xff, + 0x00,0x00,0x00,0xfd,0xff,0xff,0xff,0xff, + 0xfd,0xff,0x00,0x00,0x00,0x03,0x00,0xff, + 0xff,0xff,0xfd,0xff,0x00,0x00,0x00,0x03, + 0x00,0xff,0xff,0xff,0xfd,0xff,0x00,0x00, + 0x00,0xfd,0xff,0xff,0xff,0xff,0xfc,0xff, + 0x00,0x00,0x00,0x03,0x00,0xff,0xff,0xff, + 0xfd,0xff,0x00,0x00,0x00,0x03,0x00,0xff, + 0xff,0xff,0xfd,0xff,0x00,0x00,0x00,0x03, + 0x00,0xff,0xff,0xff,0xfd,0xff,0x00,0x00, + 0x00,0xfe,0xff,0x00,0x00,0x00,0x03,0x00, + 0xff,0xff,0xff,0xf9,0xff,0x00,0x00,0x00, + 0x03,0x00,0xff,0xff,0xff,0xfd,0xff,0x00, + 0x00,0x00,0x03,0x00,0xff,0xff,0xff,0xfe, + 0xff,0x00,0x00,0x00,0x03,0x00,0xff,0xff, + 0xff,0xfd,0xff,0x00,0x00,0x00,0x03,0x00, + 0xff,0xff,0xff,0xfb,0xff,0x00,0x00,0x00, + 0x03,0x00,0xff,0xff,0xff,0xfd,0xff,0x00, + 0x00,0x00,0x03,0x00,0xff,0xff,0xff,0xfe, + 0xff,0x00,0x00,0x00,0x03,0x00,0xff,0xff, + 0xff,0xfb,0xff,0x00,0x00,0x00,0x03,0x00, + 0xff,0xff,0xff,0xfd,0xff,0x00,0x00,0x00, + 0x03,0x00,0xff,0xff,0xff,0xfe,0xff,0x00, + 0x00,0x00,0x03,0x00,0xff,0xff,0xff,0xfe, + 0xff,0x00,0x00,0x00,0x03,0x00,0xff,0xff, + 0xff,0xfe,0xff,0x00,0x00,0x00,0x03,0x00, + 0xff,0xff,0xff,0xfd,0xff,0x00,0x00,0x00, + 0x03,0x00,0xff,0xff,0xff,0xfe,0xff,0x00, + 0x00,0x00,0x03,0x00,0xff,0xff,0xff,0xfd, + 0xff,0x00,0x00,0x00,0x03,0x00,0xff,0xff, + 0xff,0xfb,0xff,0x00,0x00,0x00,0x03,0x00, + 0xff,0xff,0xff,0xfd,0xff,0x00,0x00,0x00, + 0x03,0x00,0xff,0xff,0xff,0xfe,0xff,0x00, + 0x00,0x00,0x03,0x00,0xff,0xff,0xff,0xfd, + 0xff,0x00,0x00,0x00,0x03,0x00,0xff,0xff, + 0xff,0xfe,0xff,0x00,0x00,0x00,0x03,0x00, + 0xff,0xff,0xff,0xfd,0xff,0x00,0x00,0x00, + 0x03,0x00,0xff,0xff,0xff,0xfd,0xff,0x00, + 0x00,0x00,0x03,0x00,0xff,0xff,0xff,0xfd, + 0xff,0x00,0x00,0x00,0x03,0x00,0xff,0xff, + 0xff,0xf9,0xff,0x00,0x00,0x00,0xfe,0xff, + 0x00,0x00,0x00,0x03,0x00,0xff,0xff,0xff, + 0xf9,0xff,0x00,0x00,0x00,0x03,0x00,0xff, + 0xff,0xff,0xfd,0xff,0x00,0x00,0x00,0x03, + 0x00,0xff,0xff,0xff,0xfe,0xff,0x00,0x00, + 0x00,0x03,0x00,0xff,0xff,0xff,0xfd,0xff, + 0x00,0x00,0x00,0x03,0x00,0xff,0xff,0xff, + 0xfb,0xff,0x00,0x00,0x00,0x03,0x00,0xff, + 0xff,0xff,0xfd,0xff,0x00,0x00,0x00,0x03, + 0x00,0xff,0xff,0xff,0xfe,0xff,0x00,0x00, + 0x00,0x03,0x00,0xff,0xff,0xff,0xf7,0xff, + 0x00,0x00,0x00,0x03,0x00,0xff,0xff,0xff, + 0xfe,0xff,0x00,0x00,0x00,0x03,0x00,0xff, + 0xff,0xff,0xfe,0xff,0x00,0x00,0x00,0x03, + 0x00,0xff,0xff,0xff,0xfe,0xff,0x00,0x00, + 0x00,0x03,0x00,0xff,0xff,0xff,0xfd,0xff, + 0x00,0x00,0x00,0x03,0x00,0xff,0xff,0xff, + 0xfe,0xff,0x00,0x00,0x00,0x03,0x00,0xff, + 0xff,0xff,0xf3,0xff,0x00,0x00,0x00,0x03, + 0x00,0xff,0xff,0xff,0xfe,0xff,0x00,0x00, + 0x00,0x03,0x00,0xff,0xff,0xff,0xfd,0xff, + 0x00,0x00,0x00,0x03,0x00,0xff,0xff,0xff, + 0xfe,0xff,0x00,0x00,0x00,0x03,0x00,0xff, + 0xff,0xff,0xfd,0xff,0x00,0x00,0x00,0x03, + 0x00,0xff,0xff,0xff,0xfe,0xff,0x00,0x00, + 0x00,0x15,0x00,0xff,0xff,0xff,0x00,0x00, + 0x00,0xff,0xff,0xff,0x00,0x00,0x00,0xff, + 0xff,0xff,0x00,0x00,0x00,0xff,0xff,0xff, + 0xfa,0xff,0x00,0x00,0x00,0xfe,0xff,0x00, + 0x00,0x00,0x03,0x00,0xff,0xff,0xff,0xf9, + 0xff,0x00,0x00,0x00,0x03,0x00,0xff,0xff, + 0xff,0xfd,0xff,0x00,0x00,0x00,0x03,0x00, + 0xff,0xff,0xff,0xfe,0xff,0x00,0x00,0x00, + 0x03,0x00,0xff,0xff,0xff,0xfd,0xff,0x00, + 0x00,0x00,0x03,0x00,0xff,0xff,0xff,0xfb, + 0xff,0x00,0x00,0x00,0x03,0x00,0xff,0xff, + 0xff,0xfd,0xff,0x00,0x00,0x00,0x03,0x00, + 0xff,0xff,0xff,0xfe,0xff,0x00,0x00,0x00, + 0x03,0x00,0xff,0xff,0xff,0xfa,0xff,0x00, + 0x00,0x00,0xfd,0xff,0xff,0xff,0xff,0xfd, + 0xff,0x00,0x00,0x00,0x03,0x00,0xff,0xff, + 0xff,0xfe,0xff,0x00,0x00,0x00,0x03,0x00, + 0xff,0xff,0xff,0xfe,0xff,0x00,0x00,0x00, + 0x03,0x00,0xff,0xff,0xff,0xfd,0xff,0x00, + 0x00,0x00,0x03,0x00,0xff,0xff,0xff,0xfe, + 0xff,0x00,0x00,0x00,0xfb,0xff,0xff,0xff, + 0xff,0xfa,0xff,0x00,0x00,0x00,0xfd,0xff, + 0xff,0xff,0xff,0xfd,0xff,0x00,0x00,0x00, + 0x03,0x00,0xff,0xff,0xff,0xfd,0xff,0x00, + 0x00,0x00,0x03,0x00,0xff,0xff,0xff,0xfe, + 0xff,0x00,0x00,0x00,0x03,0x00,0xff,0xff, + 0xff,0xfd,0xff,0x00,0x00,0x00,0x03,0x00, + 0xff,0xff,0xff,0xfe,0xff,0x00,0x00,0x00, + 0x15,0x00,0xff,0xff,0xff,0x00,0x00,0x00, + 0xff,0xff,0xff,0x00,0x00,0x00,0xff,0xff, + 0xff,0x00,0x00,0x00,0xff,0xff,0xff,0xfa, + 0xff,0x00,0x00,0x00,0xfe,0xff,0x00,0x00, + 0x00,0xfa,0xff,0xff,0xff,0xff,0xfe,0xff, + 0x00,0x00,0x00,0x03,0x00,0xff,0xff,0xff, + 0xfd,0xff,0x00,0x00,0x00,0x03,0x00,0xff, + 0xff,0xff,0xfe,0xff,0x00,0x00,0x00,0x03, + 0x00,0xff,0xff,0xff,0xfd,0xff,0x00,0x00, + 0x00,0x03,0x00,0xff,0xff,0xff,0xfb,0xff, + 0x00,0x00,0x00,0x03,0x00,0xff,0xff,0xff, + 0xfd,0xff,0x00,0x00,0x00,0x03,0x00,0xff, + 0xff,0xff,0xfe,0xff,0x00,0x00,0x00,0x03, + 0x00,0xff,0xff,0xff,0xfb,0xff,0x00,0x00, + 0x00,0x03,0x00,0xff,0xff,0xff,0xfa,0xff, + 0x00,0x00,0x00,0x03,0x00,0xff,0xff,0xff, + 0xfe,0xff,0x00,0x00,0x00,0x03,0x00,0xff, + 0xff,0xff,0xfe,0xff,0x00,0x00,0x00,0x03, + 0x00,0xff,0xff,0xff,0xfd,0xff,0x00,0x00, + 0x00,0x03,0x00,0xff,0xff,0xff,0xfe,0xff, + 0x00,0x00,0x00,0x03,0x00,0xff,0xff,0xff, + 0xfd,0xff,0x00,0x00,0x00,0x03,0x00,0xff, + 0xff,0xff,0xfb,0xff,0x00,0x00,0x00,0x03, + 0x00,0xff,0xff,0xff,0xfa,0xff,0x00,0x00, + 0x00,0x03,0x00,0xff,0xff,0xff,0xfd,0xff, + 0x00,0x00,0x00,0x03,0x00,0xff,0xff,0xff, + 0xfe,0xff,0x00,0x00,0x00,0x03,0x00,0xff, + 0xff,0xff,0xfd,0xff,0x00,0x00,0x00,0x03, + 0x00,0xff,0xff,0xff,0xfe,0xff,0x00,0x00, + 0x00,0x15,0x00,0xff,0xff,0xff,0x00,0x00, + 0x00,0xff,0xff,0xff,0x00,0x00,0x00,0xff, + 0xff,0xff,0x00,0x00,0x00,0xff,0xff,0xff, + 0xfa,0xff,0x00,0x00,0x00,0xfe,0xff,0x00, + 0x00,0x00,0x03,0x00,0xff,0xff,0xff,0xf9, + 0xff,0x00,0x00,0x00,0xfe,0xff,0xff,0xff, + 0xff,0xfe,0xff,0x00,0x00,0x00,0x03,0x00, + 0xff,0xff,0xff,0xfe,0xff,0x00,0x00,0x00, + 0x03,0x00,0xff,0xff,0xff,0xfe,0xff,0x00, + 0x00,0x00,0xfe,0xff,0xff,0xff,0xff,0xfb, + 0xff,0x00,0x00,0x00,0x03,0x00,0xff,0xff, + 0xff,0xfd,0xff,0x00,0x00,0x00,0x03,0x00, + 0xff,0xff,0xff,0xfe,0xff,0x00,0x00,0x00, + 0x03,0x00,0xff,0xff,0xff,0xfb,0xff,0x00, + 0x00,0x00,0x03,0x00,0xff,0xff,0xff,0xfd, + 0xff,0x00,0x00,0x00,0x03,0x00,0xff,0xff, + 0xff,0xfe,0xff,0x00,0x00,0x00,0x03,0x00, + 0xff,0xff,0xff,0xfe,0xff,0x00,0x00,0x00, + 0x03,0x00,0xff,0xff,0xff,0xfe,0xff,0x00, + 0x00,0x00,0x03,0x00,0xff,0xff,0xff,0xfe, + 0xff,0x00,0x00,0x00,0xfe,0xff,0xff,0xff, + 0xff,0xfe,0xff,0x00,0x00,0x00,0x03,0x00, + 0xff,0xff,0xff,0xfd,0xff,0x00,0x00,0x00, + 0x03,0x00,0xff,0xff,0xff,0xfb,0xff,0x00, + 0x00,0x00,0x03,0x00,0xff,0xff,0xff,0xfd, + 0xff,0x00,0x00,0x00,0x03,0x00,0xff,0xff, + 0xff,0xfe,0xff,0x00,0x00,0x00,0xfe,0xff, + 0xff,0xff,0xff,0xfe,0xff,0x00,0x00,0x00, + 0x03,0x00,0xff,0xff,0xff,0xfe,0xff,0x00, + 0x00,0x00,0x03,0x00,0xff,0xff,0xff,0xfd, + 0xff,0x00,0x00,0x00,0x09,0x00,0xff,0xff, + 0xff,0x00,0x00,0x00,0xff,0xff,0xff,0xfd, + 0xff,0x00,0x00,0x00,0x03,0x00,0xff,0xff, + 0xff,0xfd,0xff,0x00,0x00,0x00,0x03,0x00, + 0xff,0xff,0xff,0xfb,0xff,0x00,0x00,0x00, + 0xfe,0xff,0x00,0x00,0x00,0x03,0x00,0xff, + 0xff,0xff,0xf9,0xff,0x00,0x00,0x00,0x06, + 0x00,0xff,0xff,0xff,0x00,0x00,0x00,0xfe, + 0xff,0xff,0xff,0xff,0xfc,0xff,0x00,0x00, + 0x00,0xfe,0xff,0xff,0xff,0xff,0x06,0x00, + 0x00,0x00,0x00,0xff,0xff,0xff,0xfa,0xff, + 0x00,0x00,0x00,0xfd,0xff,0xff,0xff,0xff, + 0xfe,0xff,0x00,0x00,0x00,0xfd,0xff,0xff, + 0xff,0xff,0xfb,0xff,0x00,0x00,0x00,0xfd, + 0xff,0xff,0xff,0xff,0xfd,0xff,0x00,0x00, + 0x00,0x03,0x00,0xff,0xff,0xff,0xfe,0xff, + 0x00,0x00,0x00,0x03,0x00,0xff,0xff,0xff, + 0xfd,0xff,0x00,0x00,0x00,0xfe,0xff,0xff, + 0xff,0xff,0x06,0x00,0x00,0x00,0x00,0xff, + 0xff,0xff,0xfd,0xff,0x00,0x00,0x00,0xfd, + 0xff,0xff,0xff,0xff,0xf9,0xff,0x00,0x00, + 0x00,0xfd,0xff,0xff,0xff,0xff,0xfd,0xff, + 0x00,0x00,0x00,0x06,0x00,0xff,0xff,0xff, + 0x00,0x00,0x00,0xfe,0xff,0xff,0xff,0xff, + 0xfc,0xff,0x00,0x00,0x00,0xfd,0xff,0xff, + 0xff,0xff,0xfe,0xff,0x00,0x00,0x00,0x03, + 0x00,0xff,0xff,0xff,0xfd,0xff,0x00,0x00, + 0x00,0x03,0x00,0xff,0xff,0xff,0xfd,0xff, + 0x00,0x00,0x00,0x03,0x00,0xff,0xff,0xff, + 0xfb,0xff,0x00,0x00,0x00,0xfe,0xff,0x00, + 0x00,0x00,0x03,0x00,0xff,0xff,0xff,0xee, + 0xff,0x00,0x00,0x00,0x03,0x00,0xff,0xff, + 0xff,0xf4,0xff,0x00,0x00,0x00,0x03,0x00, + 0xff,0xff,0xff,0xf4,0xff,0x00,0x00,0x00, + 0x03,0x00,0xff,0xff,0xff,0xf7,0xff,0x00, + 0x00,0x00,0x03,0x00,0xff,0xff,0xff,0xed, + 0xff,0x00,0x00,0x00,0x03,0x00,0xff,0xff, + 0xff,0xe6,0xff,0x00,0x00,0x00,0xfe,0xff, + 0x00,0x00,0x00,0xfa,0xff,0xff,0xff,0xff, + 0xf3,0xff,0x00,0x00,0x00,0x03,0x00,0xff, + 0xff,0xff,0xf3,0xff,0x00,0x00,0x00,0xfe, + 0xff,0xff,0xff,0xff,0xf6,0xff,0x00,0x00, + 0x00,0x03,0x00,0xff,0xff,0xff,0xfe,0xff, + 0x00,0x00,0x00,0x03,0x00,0xff,0xff,0xff, + 0xfa,0xff,0x00,0x00,0x00,0x03,0x00,0xff, + 0xff,0xff,0xed,0xff,0x00,0x00,0x00,0x03, + 0x00,0xff,0xff,0xff,0xe6,0xff,0x00,0x00, + 0x00,0x98,0xff,0x00,0x00,0x00,0x98,0xff, + 0x00,0x00,0x00, + }, + }; + } +} diff --git a/base/Applications/TaskList/TaskList.csproj b/base/Applications/TaskList/TaskList.csproj new file mode 100644 index 0000000..ce0f69e --- /dev/null +++ b/base/Applications/TaskList/TaskList.csproj @@ -0,0 +1,31 @@ + + + + + + + Exe + TaskList + true + + + + + + + + + + + + + + diff --git a/base/Applications/TaskList/TaskList.sg b/base/Applications/TaskList/TaskList.sg new file mode 100644 index 0000000..b936a2a --- /dev/null +++ b/base/Applications/TaskList/TaskList.sg @@ -0,0 +1,431 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: TaskList.cs +// +// Note: Simple Windows XP-like TaskList program. +// +using System; +using System.Collections; +using System.Runtime.CompilerServices; +using System.Threading; + +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Diagnostics.Contracts; +using Microsoft.Singularity.Configuration; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.V1.Services; +using Microsoft.SingSharp; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications +{ + [ConsoleCategory(HelpMessage="Tasklist [options] Displays XP-like task information", + DefaultAction=true)] + internal sealed class Parameters + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef processRef; + + [Endpoint] + public readonly TRef memoryRef; + + [Endpoint] + public readonly TRef channelRef; + + [BoolParameter( "d", Default=false , HelpMessage="Dumps output and PageTable to Debugger.")] + internal bool dumpTable; + + [BoolParameter( "c", Default=false , HelpMessage="Displays channels per process.")] + internal bool displayChannels; + + [BoolParameter( "t", Default=false , HelpMessage="Displays ThreadIds per process.")] + internal bool displayThreads; + + [LongParameter( "r", Default=-1, HelpMessage="Repeat every seconds")] + internal long pauseSeconds; + + reflective internal Parameters(); + + internal int AppMain() { + return TaskList.AppMain(this); + } + } + + public class TaskList + { + public class ProcessData + { + public int id; + public string name; + public long memBytes; + public long peakMemBytes; + public long commMemBlocks; + public long commMemBytes; + public long handlePages; + public int[] tids; + + public ProcessData() { + tids = null; + } + } + + public class ChannelData + { + public int ChannelId; + public int ImpProcessId; + public int ExpProcessId; + public int MessagesDeliveredToImp; + public int MessagesDeliveredToExp; + } + + public static int []! GetProcessIDs(ProcessContract.Imp:ReadyState! imp) + { + int [] ids = null; + int[]! in ExHeap xids; + imp.SendGetProcessIDs(); + imp.RecvProcessIDs(out xids); + // REVIEW: The kernel process is being returned twice so we're + // skipping one of the entries if the process ID matches. + int startIndex = 0; + if (xids[0] == xids[1]) + startIndex++; + ids = new int[xids.Length - startIndex]; + for (int i = startIndex; i < xids.Length; i++) + { + ids[i - startIndex] = xids[i]; + } + delete xids; + return ids; + } + + public static int [] GetProcessThreadIDs(ProcessContract.Imp:ReadyState! imp, int procID) + { + imp.SendGetProcessThreadIDs(procID); + int [] retVal = null; + + switch receive + { + case imp.NotFound() : + break; + + case imp.ProcessThreadIDs(int[]! in ExHeap tids) : + retVal = new int[tids.Length]; + for (int i=0; i= 4) + { + try + { + value = UInt32.Parse(arg.Substring(3)); + return true; + } + catch (FormatException) + {} + catch (OverflowException) + {} + } + Console.WriteLine("Could not parse {0}", name); + value = 0; + return false; + } + + /// + /// Use this method to write output to both the screen and the debugger if toDebugger is true. + /// + public static void WriteLine(bool toDebugger, string format, params object[] args) { + string s = String.Format(format, args); + Console.WriteLine(s); + if (toDebugger) { + DebugStub.WriteLine(s); + } + } + + public static void WriteLine(bool toDebugger) { + Console.WriteLine(); + if (toDebugger) { + DebugStub.WriteLine(); + } + } + + internal static int AppMain(Parameters! config) + { + ProcessData [] processData; + ChannelData [] channelData; + + // Set the default options + bool displayChannels = config.displayChannels; + bool displayThreads = config.displayThreads; + bool dumpTable = config.dumpTable; + int pauseSeconds = (int) config.pauseSeconds; + + + ProcessContract.Imp imp1 = config.processRef.Acquire(); + imp1.RecvReady(); + config.processRef.Release(imp1); + + MemoryContract.Imp imp2 = config.memoryRef.Acquire(); + imp2.RecvReady(); + config.memoryRef.Release(imp2); + + ChannelContract.Imp imp3 = config.channelRef.Acquire(); + imp3.RecvReady(); + config.channelRef.Release(imp3); + + do + { + // Retrieve the process and channel data + try + { + processData = GetProcessData(config); + } + catch (Exception ex) + { + Console.WriteLine("Error retrieving process data."); + Console.WriteLine(ex.ToString()); + return 1; + } + try + { + channelData = GetChannelData(processData,config); + } + catch (Exception ex) + { + Console.WriteLine("Error retrieving channel data."); + Console.WriteLine(ex.ToString()); + return 1; + } + + // Prep for display + Hashtable processName = new Hashtable(processData.Length); + for (int i = 0; i < processData.Length; i++) + { + ProcessData pd = processData[i]; + if (pd == null) continue; + processName.Add(pd.id, pd.name); + } + + // Display the results + Console.WriteLine(); + WriteLine(dumpTable, "PID Task Name Mem Usage Peak Mem Shared Mem Chan Imp Exp HP "); + WriteLine(dumpTable, "=== =================== ========= ======== ========== ======== === ==="); + + for (int i = 0; i < processData.Length; i++) + { + ProcessData pd = processData[i]; + if (pd == null) continue; + + ArrayList importedChannels = GetImportedChannels(channelData, pd.id); + ArrayList exportedChannels = GetExportedChannels(channelData, pd.id); + + WriteLine(dumpTable, "{0,3} {1,-19} {2,7} K {3,6} K {4,8} K {5,8} {6,3} {7,3}", pd.id, + pd.name, pd.memBytes / 1024, pd.peakMemBytes / 1024, + pd.commMemBytes / 1024, importedChannels.Count, exportedChannels.Count, + pd.handlePages); + + if (displayThreads) { + if (pd.tids != null && pd.tids.Length > 0) { + for (int j = 0; j < pd.tids.Length; j++) { + WriteLine(dumpTable, " tid -> {0}",pd.tids[j]); + } + } + } + + if (displayChannels) + { + // First display the imports + for (int j = 0; j < importedChannels.Count; j++) + { + ChannelData data = (ChannelData!) importedChannels[j]; + WriteLine(dumpTable, " -> {0} (cid={1}, msgs={2})", + processName[data.ExpProcessId], data.ChannelId, data.MessagesDeliveredToImp); + } + // Then display the exports + for (int j = 0; j < exportedChannels.Count; j++) + { + ChannelData data = (ChannelData!) exportedChannels[j]; + WriteLine(dumpTable, " <- {0} (cid={1}, msgs={2})", + processName[data.ImpProcessId], data.ChannelId, data.MessagesDeliveredToExp); + } + } + } + if (dumpTable) { + AppRuntime.DumpPageTable(); + } + if (pauseSeconds > 0) { + Thread.Sleep(1000 * (int)pauseSeconds); + } + } while (pauseSeconds >= 0); + + return 0; + } + } +} diff --git a/base/Applications/TaskTimes/TaskTimes.csproj b/base/Applications/TaskTimes/TaskTimes.csproj new file mode 100644 index 0000000..4c252fc --- /dev/null +++ b/base/Applications/TaskTimes/TaskTimes.csproj @@ -0,0 +1,32 @@ + + + + + + + Exe + TaskTimes + + + + + + + + + + + + + + diff --git a/base/Applications/TaskTimes/TaskTimes.sg b/base/Applications/TaskTimes/TaskTimes.sg new file mode 100644 index 0000000..f118d54 --- /dev/null +++ b/base/Applications/TaskTimes/TaskTimes.sg @@ -0,0 +1,656 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: TaskList.cs +// +// Note: Simple Windows XP-like TaskList program. +// +using System; +using System.Collections; +using System.Runtime.CompilerServices; +using System.Threading; + +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Diagnostics.Contracts; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.V1.Services; +using Microsoft.SingSharp; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications +{ + [ConsoleCategory(HelpMessage="TaskTimes: Displays snapshot of cpu times for all processes", + DefaultAction=true)] + internal sealed class Parameters + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef processRef; + + [BoolParameter( "f", Default=false , HelpMessage="run forever")] + internal bool doForever; + + [BoolParameter( "s", Default=false , HelpMessage="Summary Mode")] + internal bool doSummary; + + [BoolParameter( "v", Default=false , HelpMessage="Verbose output")] + internal bool doVerbose; + + [BoolParameter( "q", Default=false , HelpMessage="Quiet Mode (debug output only)")] + internal bool doQuiet; + + [LongParameter( "r", Default=1, HelpMessage="Repeat every n seconds")] + internal long monitorSeconds; + + [LongParameter( "i", Default=1, HelpMessage="Perform n iterations")] + internal long iterationCount; + + [LongParameter( "w", Default=0, HelpMessage="warmup time in seconds")] + internal long warmupSeconds; + + reflective internal Parameters(); + + internal int AppMain() { + return TaskTimes.AppMain(this); + } + } + + public class TaskTimes + { + public class ProcessData + { + public int id; + public string name; + public long memBytes; + public long peakMemBytes; + public long commMemBlocks; + public long commMemBytes; + public long handlePages; + public int[] tids; + public long totalTime; + public long deadThreadTime; + public long deadThreadCount; + public int gcCount; + public long gcTotalTime; + public long gcTotalBytes; + + public ProcessData() { + tids = null; + } + } + + public class ChannelData + { + public int ChannelId; + public int ImpProcessId; + public int ExpProcessId; + public int MessagesDeliveredToImp; + public int MessagesDeliveredToExp; + } + + public static int []! GetProcessIDs(ProcessContract.Imp:ReadyState! imp) + { + int [] ids = null; + int[]! in ExHeap xids; + imp.SendGetProcessIDs(); + imp.RecvProcessIDs(out xids); + // REVIEW: The kernel process is being returned twice so we're + // skipping one of the entries if the process ID matches. + int startIndex = 0; + if (xids[0] == xids[1]) + startIndex++; + ids = new int[xids.Length - startIndex]; + for (int i = startIndex; i < xids.Length; i++) + { + ids[i - startIndex] = xids[i]; + } + delete xids; + return ids; + } + + public static int [] GetProcessThreadIDs(ProcessContract.Imp:ReadyState! imp, int procID) + { + imp.SendGetProcessThreadIDs(procID); + int [] retVal = null; + + switch receive + { + case imp.NotFound() : + break; + + case imp.ProcessThreadIDs(int[]! in ExHeap tids) : + retVal = new int[tids.Length]; + for (int i=0; i= 4) + { + try + { + value = UInt32.Parse(arg.Substring(3)); + return true; + } + catch (FormatException) + {} + catch (OverflowException) + {} + } + Console.WriteLine("Could not parse {0}", name); + value = 0; + return false; + } + + public static void PrintUsage() + { + Console.WriteLine(); + Console.WriteLine("TaskTimes [options]"); + Console.WriteLine(); + Console.WriteLine("Options:"); + Console.WriteLine(" /? Displays this help/usage."); + Console.WriteLine(" /d Output to debugger."); + Console.WriteLine(" /f iterate forever"); + Console.WriteLine(" /i: iterate times."); + Console.WriteLine(" /q Quiet mode (no console)"); + Console.WriteLine(" /r: run (monitor) for seconds."); + Console.WriteLine(" /s summary mode)"); + } + + /// + /// Use this method to write output to both the screen and the debugger if toDebugger is true. + /// + public static void WriteLine(bool toDebugger, bool toDisplay, string format, params object[] args) { + string s = String.Format(format, args); + if (toDisplay) Console.WriteLine(s); + if (toDebugger) DebugStub.WriteLine(s); + } + + public static void WriteLine(bool toDebugger, bool toDisplay) { + if (toDisplay) Console.WriteLine(); + if (toDebugger) DebugStub.WriteLine(); + } + + + public static void Write(bool toDebugger, bool toDisplay, string format, params object[] args) { + string s = String.Format(format, args); + if (toDisplay) Console.Write(s); + if (toDebugger) DebugStub.Write(s); + } + + [CLSCompliant(false)] + public struct PerfEvtSel + { + // Bits and Flags + public const uint CNT_MASK = 0xff000000; + public const uint INV = 0x00800000; + public const uint EN = 0x00400000; + public const uint INT = 0x00100000; + public const uint PC = 0x00080000; + public const uint E = 0x00040000; + public const uint OS = 0x00020000; + public const uint USR = 0x00010000; + public const uint UNIT_MASK = 0x0000ff00; + public const uint SELECTOR = 0x000000ff; + + // Common setting: Count all, but don't interrupt, + public const uint COUNT = (EN | PC | OS | USR); + // public const uint COUNT = (EN | PC | E | OS | USR); + + // Selector values. + public const uint DCacheRefillFromL2OrSys = 0x42; // Speculative + public const uint DCacheRefillFromSystem = 0x43; // Speculative + public const uint DtlbL1MissL2Hit = 0x45; // Speculative + public const uint DtlbL1MissL2Miss = 0x46; // Speculative + public const uint CyclesNotHalted = 0x76; // No E + public const uint RequestsToL2Cache = 0x7d; + public const uint L2CacheMiss = 0x7e; + public const uint ItlbL1MissL2Hit = 0x84; + public const uint ItlbL1MissL2Miss = 0x85; + public const uint RetiredInstructions = 0xc0; // No E + public const uint RetiredBranchInstructions = 0xc2; // No E + public const uint RetiredBranchesMispredicted = 0xc3; // No E + public const uint RetiredBranchesTaken = 0xc4; // No E + public const uint CyclesInterruptsMasked = 0xcd; // No E + public const uint CyclesInterruptsBlocked = 0xce; // No E + + public ulong value; // Required so Bartok doesn't die. + + public static string ToString(ulong value) + { + switch (value & 0xff) { + case PerfEvtSel.DCacheRefillFromL2OrSys: return "DCache_Refill_L2"; + case PerfEvtSel.DCacheRefillFromSystem: return "DCache_Refill_Sys"; + case PerfEvtSel.DtlbL1MissL2Hit: return "DTLB_L2_Hit"; + case PerfEvtSel.DtlbL1MissL2Miss: return "DTBL_L2_Miss"; + case PerfEvtSel.CyclesNotHalted: return "CyclesNotHalted"; + case PerfEvtSel.RequestsToL2Cache: + if ((value & 0x400) != 0) { + return "TLB_L2_Requests"; + } + return "Req_L2_Cache"; + case PerfEvtSel.L2CacheMiss: + if ((value & 0x400) != 0) { + return "TLB_L2_Miss"; + } + return "L2_Cache_Miss"; + case PerfEvtSel.ItlbL1MissL2Hit: return "ITLB_L2_Hit"; + case PerfEvtSel.ItlbL1MissL2Miss: return "ITLB_L2_Miss"; + case PerfEvtSel.RetiredInstructions: return "Retired_Inst."; + case PerfEvtSel.RetiredBranchInstructions: return "Branches"; + case PerfEvtSel.RetiredBranchesMispredicted:return "Br_Mispredicted"; + case PerfEvtSel.RetiredBranchesTaken: return "Br_Taken"; + case PerfEvtSel.CyclesInterruptsMasked: return "Ints_Masked (cyc)"; + case PerfEvtSel.CyclesInterruptsBlocked: return "Ints_Blocked (cyc)"; + default: + return String.Format("{0:x16}", value); + } + } + } + + private static void InitializeCounters () + { + Reset(0, PerfEvtSel.COUNT | PerfEvtSel.CyclesNotHalted); + Reset(1, PerfEvtSel.COUNT | PerfEvtSel.RetiredInstructions); + Reset(2, PerfEvtSel.COUNT | PerfEvtSel.CyclesInterruptsMasked); + Reset(3, PerfEvtSel.COUNT | PerfEvtSel.RequestsToL2Cache | 0x400); + DebugStub.WritePerfCounter(7, Processor.GetCycleCount()); + } + + internal static bool IsAmd() + { + uint eax; + uint ebx; + uint ecx; + uint edx; + Processor.ReadCpuid(0, out eax, out ebx, out ecx, out edx); + return (ebx == 0x68747541 && ecx == 0x444d4163 && edx == 0x69746e65); + } + + internal static void ReportCounters(bool dumpTable, bool toDisplay) + { + // Read the AMD and Singularity performance counters. + ulong b0 = 0; + ulong t0 = 0; + ulong e0 = 0; + ulong e1 = 0; + ulong e2 = 0; + ulong e3 = 0; + ulong p0 = 0; + ulong p1 = 0; + ulong p2 = 0; + //ulong p3 = 0; + ulong z0 = 0; + ulong z1 = 0; + ulong z2 = 0; + ulong z3 = 0; + ulong z4 = 0; + ulong z5 = 0; + ulong z6 = 0; + if (IsAmd()) { + b0 = DebugStub.ReadPerfCounter(7); + t0 = Processor.GetCycleCount(); + e0 = Processor.ReadMsr(0xc0010000); + e1 = Processor.ReadMsr(0xc0010001); + e2 = Processor.ReadMsr(0xc0010002); + e3 = Processor.ReadMsr(0xc0010003); + p0 = Processor.ReadPmc(0); + p1 = Processor.ReadPmc(1); + p2 = Processor.ReadPmc(2); + // p3 = Processor.ReadPmc(3); + } + else { + b0 = DebugStub.ReadPerfCounter(7); + t0 = Processor.GetCycleCount(); + } + z0 = DebugStub.ReadPerfCounter(0); + z1 = DebugStub.ReadPerfCounter(1); + z2 = DebugStub.ReadPerfCounter(2); + z3 = DebugStub.ReadPerfCounter(3); + z4 = DebugStub.ReadPerfCounter(4); + z5 = DebugStub.ReadPerfCounter(5); + z6 = DebugStub.ReadPerfCounter(6); + + t0 = t0 - b0; + WriteLine(false, false, "\nevt: {0,16} {1,16} {2,16} {3,16} {4,16}\n", + "Cycles", + PerfEvtSel.ToString(e0), + PerfEvtSel.ToString(e1), + PerfEvtSel.ToString(e2), + PerfEvtSel.ToString(e3)); + // t0= cycles + // p0= cycles not halted + // p1= cycles retired + // p2= cycles interrupt not masked + WriteLine(dumpTable,toDisplay, + " cycles={0,16}\n"+ + " notHalted={1,16}(%{2:f2})\n"+ + " retired={3,16}(%{4:f2})\n"+ + " int masked={5,16}(%{6:f2})\n"+ + "cycles halted={7,16}(%{8:f2})", + t0, + p0, + (double) (p0) / (double) (t0), + p1, + (double) (p1) / (double) (t0), + p2, + (double) (p2) / (double) (t0), + (t0-p0), + (double) (t0-p0) / (double) (t0) + ); + + WriteLine(false,false, "pfc: {0,16} {1,16} {2,16} {3,16} {4,16} {5,16} {6,16} {7,16}\n", + z0 + z1 + z2 + z3 + z4 + z5 + z6, + z0, z1, z2, z3, z4, z5, z6); + if (!IsAmd()) { + WriteLine(dumpTable,toDisplay, "Intel processor, PMC values will be zero.\n"); + } + } + + + internal static void Reset(uint pmc, ulong value) + { + if (IsAmd()) { + // Clear the event selector. + Processor.WriteMsr(0xc0010000 + pmc, 0); + // Clear the performance counter. + Processor.WriteMsr(0xc0010004 + pmc, 0); + // Enable the event selector. + Processor.WriteMsr(0xc0010000 + pmc, value); + } + } + + internal static void ResetPerfCounters() + { + DebugStub.WritePerfCounter(0, 0); + DebugStub.WritePerfCounter(1, 0); + DebugStub.WritePerfCounter(2, 0); + DebugStub.WritePerfCounter(3, 0); + DebugStub.WritePerfCounter(4, 0); + DebugStub.WritePerfCounter(5, 0); + DebugStub.WritePerfCounter(6, 0); + DebugStub.WritePerfCounter(7, 0); + + if (IsAmd()) { + for (uint pmc = 0; pmc < 4; pmc++) { + Processor.WriteMsr(0xc0010004 + pmc, 0); + } + } + DebugStub.WritePerfCounter(7, Processor.GetCycleCount()); + } + internal static int AppMain(Parameters! config) + { + ProcessData [] processData; + ProcessData [] processData2; + + // Set the default options + bool dumpTable = false; + int monitorSeconds = (int) config.monitorSeconds; + bool toDisplay = !config.doQuiet; + + bool summaryMode = config.doSummary; + bool doForever = config.doForever; + bool doVerbose = config.doVerbose; + int iterationCount = (int) config.iterationCount; + int warmupSeconds = (int) config.warmupSeconds; + string pattern = "###,##0.00"; + string pattern2 = "###,###,##0.00"; + string percentPattern = "#0.00"; + + + ProcessContract.Imp imp = ((!)config.processRef).Acquire(); + imp.RecvReady(); + + // set up performance counters to get halted/retired instructions etc. + if (doVerbose) InitializeCounters(); + + Thread.Sleep(warmupSeconds * 1000); + do + { + TimeSpan startTime = ProcessService.GetUpTime(); + long startIrqCount = ProcessService.GetKernelInterruptCount(); + long startSwitchCount = ProcessService.GetContextSwitchCount(); + + // Retrieve the process data + try + { + processData = GetProcessData(imp); + } + catch (Exception ex) + { + Console.WriteLine("Error retrieving process data."); + Console.WriteLine(ex.ToString()); + return 1; + } + + if (doVerbose) ResetPerfCounters(); + + Thread.Sleep(monitorSeconds * 1000); + + // Retrieve the process data + try + { + processData2 = GetProcessData(imp); + } + catch (Exception ex) + { + Console.WriteLine("Error retrieving process data."); + Console.WriteLine(ex.ToString()); + return 1; + } + TimeSpan endTime = ProcessService.GetUpTime(); + + double actualSpan = (double) ((endTime - startTime).TotalMilliseconds); + if (!summaryMode) { + WriteLine (dumpTable,toDisplay, "TaskTimes: now:{0}, span={1}ms int={2}, swi={3}", + endTime.Ticks, + actualSpan, + ProcessService.GetKernelInterruptCount() - startIrqCount, + ProcessService.GetContextSwitchCount() - startSwitchCount); + } + // Prep for display + Hashtable processName = new Hashtable(processData.Length); + for (int i = 0; i < processData.Length; i++) + { + ProcessData pd = processData[i]; + if (pd == null) continue; + processName.Add(pd.id, pd); + } + + // Display the results + if (!summaryMode) { + Console.WriteLine(); + WriteLine(dumpTable, toDisplay, "PID Task Name deltaTotal deltaGC %total %GC GCs GcBytes(K) total(ms) dead(ms) dead thd"); + WriteLine(dumpTable, toDisplay, "=== =================== ========== ========== ===== ===== ==== ========== ============== ============== ===="); + } + double totalPercent = 0; + //long durationMs = monitorSeconds*1000; + double durationMs = actualSpan; + double deltaGcTime; + double percentGc; + double totalTime; + double deadTime; + double deltaTotal; + double deltaDead; + int deltaGcCount; + long deltaGcBytes; + + for (int i = 0; i < processData2.Length; i++) + { + ProcessData pd2 = processData2[i]; + if (pd2 == null) continue; + + totalTime = (double)pd2.totalTime / DateTime.TicksPerMillisecond; + deadTime = (double)pd2.deadThreadTime / DateTime.TicksPerMillisecond; + + double percent = 0; + ProcessData p = (ProcessData) processName[pd2.id]; + if (p == null) { + // this process is not in the 1st snapshot + deltaGcBytes = pd2.gcTotalBytes; + deltaGcCount = pd2.gcCount; + deltaGcTime = deltaGcCount == 0 ? 0 : + (double) pd2.gcTotalTime /DateTime.TicksPerMillisecond; + percent = durationMs == 0 ? 0 : (double) (totalTime / durationMs) * 100 ; + deltaTotal = totalTime; + //deltaDead = deadTime; + } + else { + if (p.name != pd2.name) DebugStub.Break(); + deltaTotal = (double)((pd2.totalTime - p.totalTime) /DateTime.TicksPerMillisecond); + //deltaDead = (double)((pd2.deadThreadTime - p.deadThreadTime) / (TimeSpan.TicksPerSecond/1000)); + percent = durationMs == 0 ? 0 : (double) (deltaTotal / durationMs) * 100; + deltaGcCount = pd2.gcCount - p.gcCount; + deltaGcTime = deltaGcCount == 0 ? 0 : + (double)(pd2.gcTotalTime - p.gcTotalTime) /DateTime.TicksPerMillisecond; + deltaGcBytes = pd2.gcTotalBytes - p.gcTotalBytes; + + } + // percent of overall time spent in the GC in this process + //percentGc = durationMs == 0 ? 0 : (deltaGcTime / durationMs) * 100; + + //percent of time of this process spent in GC + percentGc = deltaTotal == 0 ? 0 : (deltaGcTime / deltaTotal) * 100; + if (summaryMode) { + Write(dumpTable, toDisplay, " {0}:{1}% ",pd2.name,percent.ToString(percentPattern)); + } + else { + WriteLine(dumpTable, toDisplay, "{0,3} {1,-19} {2,10} {3,10} {4,5} {5,5} {6,4} {7,10} {8,14} {9,14} {10,4}", + pd2.id, + pd2.name, + deltaTotal.ToString(pattern), + deltaGcTime.ToString(pattern), + percent.ToString(percentPattern), + percentGc.ToString(percentPattern), + deltaGcCount, + deltaGcBytes / 1024, + totalTime.ToString(pattern2), + deadTime.ToString(pattern2), + pd2.deadThreadCount + ) ; + } + totalPercent += percent; + } + + if (!summaryMode) { + WriteLine(dumpTable, toDisplay, " ======"); + WriteLine(dumpTable, toDisplay," {0,5} accounted for",totalPercent.ToString("00.00")); + } + else { + WriteLine(dumpTable,toDisplay,";"); + } + + if (doVerbose) ReportCounters(dumpTable, toDisplay); + + } while (--iterationCount > 0 || doForever); + delete imp; + return 0; + } + } +} diff --git a/base/Applications/Telnetd/Connection.sg b/base/Applications/Telnetd/Connection.sg new file mode 100644 index 0000000..8d31283 --- /dev/null +++ b/base/Applications/Telnetd/Connection.sg @@ -0,0 +1,200 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Telnetd.cs +// +// Note: Simple Singularity telnet daemon. +// + +namespace Microsoft.Singularity.Telnetd +{ + using System; + using System.Net; + using System.Net.Sockets; + using System.Text; + using System.Threading; + + using Microsoft.Singularity.Channels; + using Microsoft.Singularity.Io; + + internal sealed class Connection + { + const byte IAC = 255; // telnet "interpret as command" escape + const byte CODE_WILL = 251; // telnet commands + const byte CODE_WONT = 252; + const byte CODE_DO = 253; + const byte CODE_DONT = 254; + const byte OPTION_ECHO = 0x01; // telnet command options + const byte OPTION_SUPPRESSGA = 0x03; + + private Socket socket; + private Process process; + private TRef m_stdinImp; + + public Connection(Socket socket) + { + this.socket = socket; + } + + public void Start() + { + ThreadStart threadStart = new ThreadStart(Run); + Thread thread = new Thread(threadStart); + thread.Start(); + } + + private void Run() + { + // Send options and welcome message to the client + SendCommand(IAC, CODE_DONT, OPTION_ECHO); + SendCommand(IAC, CODE_WILL, OPTION_SUPPRESSGA); + Send("Microsoft Singularity Telnet Daemon\r\n\r\n"); + + // Start a shell process with redirected IO + string[] commands = new string[] { "shell" }; + process = new Process(commands, null, 2); + if (process == null) { + Console.WriteLine("Singularity Telnet Daemon - failed to exec shell."); + return; + } + + UnicodePipeContract.Imp! stdinImp; + UnicodePipeContract.Exp! stdinExp; + UnicodePipeContract.NewChannel(out stdinImp, out stdinExp); + + UnicodePipeContract.Imp! stdoutImp; + UnicodePipeContract.Exp! stdoutExp; + UnicodePipeContract.NewChannel(out stdoutImp, out stdoutExp); + + process.SetStartupEndpoint(0, (Endpoint * in ExHeap) stdinExp); + process.SetStartupEndpoint(1, (Endpoint * in ExHeap) stdoutImp); + process.Start(); + + // Kick off another thread that will pump the data from the socket to shell stdin + m_stdinImp = new TRef(stdinImp); + ThreadStart threadStart = new ThreadStart(WaitOnSocket); + Thread thread = new Thread(threadStart); + thread.Start(); + + // Process all output from the shell + bool abort = false; + while (!abort) + { + switch receive { + case stdoutExp.Write(buffer, offset, count): + Send(buffer, offset, count); + stdoutExp.SendAckWrite(buffer); + break; + case stdoutExp.ChannelClosed(): + Console.WriteLine("Singularity Telnet Daemon - ending connection."); + abort = true; + break; + } + } + + delete stdoutExp; + socket.Close(); + } + + private void WaitOnSocket() + { + UnicodePipeContract.Imp:READY! stdinImp = m_stdinImp.Acquire(); + byte[] localBuffer = new byte[256]; + bool abort = false; + while (!abort) + { + try { + int count = socket.Receive(localBuffer); +#if DebugTracingOn + DebugStub.Write("Receive " + count + "b:"); + for (int i = 0; i < count; i++) { + DebugStub.Write(" " + localBuffer[i]); + } + DebugStub.WriteLine(); +#endif + + if (count > 0) { + // REVIEW: If we only care about ASCII we have the same sized buffers... + char[] in ExHeap buffer = new [ExHeap] char[localBuffer.Length]; + int dataCount = 0; + for (int i = 0; i < count; i++) { + if (localBuffer[i] == IAC) { + i += 2; // TODO: Handle split 3 byte sequences and other forms + continue; + } + buffer[dataCount] = (char)localBuffer[i]; + dataCount++; + } + + // Send the data and wait for acknowledgement + stdinImp.SendWrite(buffer, 0, dataCount); + switch receive { + case stdinImp.AckWrite(returnedBuffer): + delete returnedBuffer; + break; + case stdinImp.ChannelClosed(): + abort = true; + break; + } + } + } + catch (SocketException) { + Console.WriteLine("Socket Exception on input thread"); + abort = true; + } + } + delete stdinImp; + socket.Close(); + } + + // Send - encode and sends + private void Send(char[]! in ExHeap buffer, int offset, int count) + { + // REVIEW: it's silly to copy the buffer locally because it's going to a socket + char[] localBuffer = new char[count]; + for (int i = 0; i < count; i++) { + localBuffer[i] = buffer[offset + i]; + } + byte[] encodedBuffer = Encoding.ASCII.GetBytes(localBuffer); + SendRawBytes(encodedBuffer, 0, encodedBuffer.Length); + } + + // Send - encode and sends + private void Send(string! s) + { + byte[] buffer = Encoding.ASCII.GetBytes(s); + SendRawBytes(buffer, 0, buffer.Length); + } + + // SendCommand - assembles and sends the standard three byte command + private void SendCommand(byte iac, byte code, byte option) + { + byte[] buffer = new byte[] { iac, code, option }; + SendRawBytes(buffer, 0, buffer.Length); + } + + // SendRawBytes - base function for sending already encoded data to client + private void SendRawBytes(byte[] buffer, int offset, int count) + { +#if DebugTracingOn + DebugStub.Write("Send " + count + "b:"); + for (int i = 0; i < count; i++) { + DebugStub.Write(" " + buffer[offset + i]); + } + DebugStub.WriteLine(); +#endif + if (count <= 0) { + return; + } + try { + socket.Send(buffer, offset, count, SocketFlags.None); + } + catch (SocketException) { + Console.WriteLine("Socket Exception writing string."); + } + } + } +} diff --git a/base/Applications/Telnetd/Listener.sg b/base/Applications/Telnetd/Listener.sg new file mode 100644 index 0000000..a979e02 --- /dev/null +++ b/base/Applications/Telnetd/Listener.sg @@ -0,0 +1,57 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Telnetd.cs +// +// Note: Simple Singularity telnet daemon. +// + +namespace Microsoft.Singularity.Telnetd +{ + using System; + using System.Net; + using System.Net.Sockets; + using System.Text; + using System.Threading; + + using Microsoft.Singularity.Channels; + using Microsoft.Singularity.Io; + + internal sealed class Listener + { + private int port; + private bool shutdownInProgress; + private Socket socket; + + public Listener(int port) + { + this.port = port; + } + + public void Start() + { + try { + socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + socket.Bind(new IPEndPoint(IPAddress.Any, port)); + socket.Listen((int)SocketOptionName.MaxConnections); + } + catch (SocketException) { + Console.WriteLine("SocketException during Listen"); + } + } + + public Socket Accept() + { + try { + return socket.Accept(); + } + catch (SocketException) { + Console.WriteLine("SocketException during Accept."); + return null; + } + } + } +} diff --git a/base/Applications/Telnetd/Telnetd.sg b/base/Applications/Telnetd/Telnetd.sg new file mode 100644 index 0000000..349bbca --- /dev/null +++ b/base/Applications/Telnetd/Telnetd.sg @@ -0,0 +1,71 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Telnetd.cs +// +// Note: Simple Singularity telnet daemon +// + +// TODO: +// - Graceful server shutdown? +// - non-null syntax +// - catch all appropriate exceptions +// - remove debugging traces +// - limit the number of simultaneous telnet sessions? +// - handle "exit" in shell gracefully +// - handle "client disconnect" gracefully + +using System; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Channels; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Telnetd +{ + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal Parameters(); + + internal int AppMain() { + return Telnetd.AppMain(this); + } + } + + + public sealed class Telnetd + { + internal static int AppMain(Parameters! config) + { + Console.WriteLine("Singularity Telnet Daemon - starting."); + Listener listener = new Listener(23); + listener.Start(); + while (true) + { + Socket socket = listener.Accept(); + Console.WriteLine("Singularity Telnet Daemon - accepting connection"); + Connection connection = new Connection(socket); + connection.Start(); + } + Console.WriteLine("Singularity Telnet Daemon - stopping."); + return 0; + } + } +} diff --git a/base/Applications/Telnetd/telnetd.csproj b/base/Applications/Telnetd/telnetd.csproj new file mode 100644 index 0000000..801d352 --- /dev/null +++ b/base/Applications/Telnetd/telnetd.csproj @@ -0,0 +1,42 @@ + + + + + + + Exe + Telnetd + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/base/Applications/Tests/Bartok/Bug00013/Bug00013.cs b/base/Applications/Tests/Bartok/Bug00013/Bug00013.cs new file mode 100644 index 0000000..f368011 --- /dev/null +++ b/base/Applications/Tests/Bartok/Bug00013/Bug00013.cs @@ -0,0 +1,771 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// + +// Some sort of threads/locking test. +// See usage for parameter. +// DebubPrintSpinLock was in the Marmot runtime. + +using System; +using System.Threading; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace MarmotBugs { + [ConsoleCategory(HelpMessage="Show attributes associated with a file", DefaultAction=true)] + internal class Parameters { + + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [LongParameter( "t", Default=1, HelpMessage="threads")] + internal long threads; + + reflective internal Parameters(); + + internal int AppMain() { + Bug00013.AppMain(this); + return 0; + } + } + + class DebugPrintSpin { + private static Object locker = new Object(); + public static void Lock() { + // Class_java_lang_Thread *currentThread = CurrentThread(); + // currentThread->f_isAwaitingDebugPrintSpinLock = true; + System.Threading.Monitor.Enter(locker); + // DebugPrintCriticalSectionHolder = currentThread; + // currentThread->f_isAwaitingDebugPrintSpinLock = false; + } + public static void Unlock() { + // DebugPrintCriticalSectionHolder = NULL; + System.Threading.Monitor.Exit(locker); + } + } + + class Bug00013 { //: Runnable { + + static int totalThreads = Int32.MaxValue; + + const bool wasteSpace = true; + const bool showPended = false; + + const int maxLinks = 10; + const int maxThreads = 10; + const int maxActive = 4; + const int nodeTraverse= 50; + const int linkTraverse= 500; + + const int newThreads = 2; //10; + const int newNodes = 100; + const int newLinks = 700; + const int newRejects = 1000; + + // conversion filler + public static void DebugDumpThreadAnchorTable(int i) {} + private static void DebugBreak() { + Assert(false, "DebugBreak"); + } + private static void Assert(bool b) { + Assert(b, "Assertion failed"); + } + private static void Assert(bool b, String s) { + if(!b) { + DebugPrintSpin.Lock(); + Console.WriteLine(s); + Console.WriteLine("Failed Bug00013"); + DebugPrintSpin.Unlock(); + Environment.Exit(1); + } + } + // end conversion + + void nonsyncv() { + lock (this) { + DebugPrintSpin.Lock(); + Console.WriteLine("within nonsyncv()"); + DebugDumpThreadAnchorTable(4); + DebugPrintSpin.Unlock(); + } + } + + [System.Runtime.CompilerServices.MethodImpl + (System.Runtime.CompilerServices.MethodImplOptions.Synchronized)] + void syncv() { + DebugPrintSpin.Lock(); + Console.WriteLine("within syncv()"); + DebugDumpThreadAnchorTable(4); + DebugPrintSpin.Unlock(); + } + + static void nonsyncs() { + lock (ClassBug00013) { + DebugPrintSpin.Lock(); + Console.WriteLine("within nonsyncs()"); + DebugDumpThreadAnchorTable(4); + DebugPrintSpin.Unlock(); + } + } + + [System.Runtime.CompilerServices.MethodImpl + (System.Runtime.CompilerServices.MethodImplOptions.Synchronized)] + static void syncs() { + DebugPrintSpin.Lock(); + Console.WriteLine("within syncs()"); + DebugDumpThreadAnchorTable(4); + DebugPrintSpin.Unlock(); + } + + static void usage() { + Console.WriteLine("usage: Bug00013 [total_threads]"); + Environment.Exit(1); + } + + internal static void AppMain(Parameters! config) + { + totalThreads = (int)config.threads; + + undeadThreadids = new int[2*maxThreads]; + + DebugPrintSpin.Lock(); + Console.WriteLine("Bug00013.Main()"); + DebugDumpThreadAnchorTable(4); + DebugPrintSpin.Unlock(); + + Object Lock = new Object(); + Bug00013.Lock = Lock; + DebugPrintSpin.Lock(); + Console.Write("Bug00013.Lock = "); + Console.WriteLine(Lock.GetHashCode()); + DebugPrintSpin.Unlock(); + + anchor = new Bug00013(); + DebugPrintSpin.Lock(); + Console.Write("Bug00013.Type = "); + Console.WriteLine(anchor.GetType()); + DebugPrintSpin.Unlock(); + + ClassBug00013 = anchor.GetType(); + DebugPrintSpin.Lock(); + Console.Write("Bug00013.class = "); + Console.WriteLine(ClassBug00013.GetHashCode()); + DebugPrintSpin.Unlock(); + + bug13Type = anchor.GetType(); + linksType = anchor.links.GetType(); + + //================================================================== + + DebugPrintSpin.Lock(); + Console.WriteLine(); + Console.WriteLine("//======================================" + + "======================================="); + Console.WriteLine(); + Console.WriteLine("before nonsyncv()"); + DebugPrintSpin.Unlock(); + + anchor.nonsyncv(); + + DebugPrintSpin.Lock(); + Console.WriteLine("after nonsyncv()"); + DebugPrintSpin.Unlock(); + + //================================================================== + + DebugPrintSpin.Lock(); + Console.WriteLine(); + Console.WriteLine("//======================================" + + "======================================="); + Console.WriteLine(); + Console.WriteLine("before syncv()"); + DebugPrintSpin.Unlock(); + + anchor.syncv(); + + DebugPrintSpin.Lock(); + Console.WriteLine("after syncv()"); + DebugPrintSpin.Unlock(); + + //================================================================== + + DebugPrintSpin.Lock(); + Console.WriteLine(); + Console.WriteLine("//======================================" + + "======================================="); + Console.WriteLine(); + Console.WriteLine("before nonsyncs()"); + DebugPrintSpin.Unlock(); + + nonsyncs(); + + DebugPrintSpin.Lock(); + Console.WriteLine("after nonsyncs()"); + DebugPrintSpin.Unlock(); + + //================================================================== + + DebugPrintSpin.Lock(); + Console.WriteLine(); + Console.WriteLine("//======================================" + + "======================================="); + Console.WriteLine(); + Console.WriteLine("before syncs()"); + DebugPrintSpin.Unlock(); + + syncs(); + + DebugPrintSpin.Lock(); + Console.WriteLine("after syncs()"); + DebugPrintSpin.Unlock(); + + //================================================================== + + Thread newThread = new Thread(new ThreadStart(anchor.run)); + DebugPrintSpin.Lock(); + Console.WriteLine(); + Console.WriteLine("//======================================" + + "======================================="); + Console.WriteLine(); + Console.Write("newThread = "); + Console.WriteLine(newThread.GetHashCode()); + DebugPrintSpin.Unlock(); + + /* + new WatchDog().start(); + try { + Thread.sleep(1000); + } catch(InterruptedException e) { + } + /**/ + + newThread.Start(); + + deadman = System.DateTime.Now; + for (;;) { + //try { + Thread.Sleep(25000); + //} catch(ThreadInterruptedException) { + //DebugPrintSpin.Lock(); + //Console.WriteLine("!"); + //DebugPrintSpin.Unlock(); + // } + lock (Lock) { + DebugPrintSpin.Lock(); + long deadms = (System.DateTime.Now - deadman).Milliseconds; + if (deadms > 100000) { + Console.WriteLine(); + Console.WriteLine("Bug00013.Main()" + + " deadman expired"); + DebugDumpThreadAnchorTable(4); + DebugBreak(); + } else { + Console.WriteLine(); + Console.Write(" ?<0,"); + Console.Write(numThreadsAlive); + Console.Write(","); + Console.Write(numThreadsActive); + DebugPrintUndead(); + Console.Write("> "); + } + DebugPrintSpin.Unlock(); + if (numThreadsAlive == 0) break; + } + } + Console.WriteLine("Passed Bug00013"); + } + + Bug00013() { + lock (Lock) { + nodeid = nodeidGenerator++; + } + nodename = ("Node" + nodeid); + links = new Bug00013[maxLinks]; + } + + /* + public override String ToString() { + if (nodename != null) return(nodename); + return(base.ToString()); + } + */ + + public void run() { + int myNumThreadsAlive; + int myNumThreadsActive; + lock (Lock) { + Assert(numThreadsAlive >= 0, + "run() numThreadsAlive should be >= 0"); + Assert(numThreadsActive >= 0, + "run() numThreadsActive should be >= 0"); + numThreadsAlive++; + myNumThreadsAlive = numThreadsAlive; + numThreadsActive++; + myNumThreadsActive = numThreadsActive; + threadid = ++threadidGenerator; + recordUndead(); + } + DebugPrintSpin.Lock(); + Console.WriteLine(); + Console.Write("T+<"); + Console.Write(threadid); + Console.Write(","); + Console.Write(myNumThreadsAlive); + Console.Write(","); + Console.Write(myNumThreadsActive); + Console.Write("> "); + DebugPrintSpin.Unlock(); + if ((myNumThreadsAlive <= maxThreads) + && (threadid < totalThreads)) { + bool conflict = false; + lock (this) { + if (random == null) { + random = new Random(); + } else { + conflict = true; + } + } + if (!conflict) { + traversalLimit = nodeTraverse; + Bug00013 last = this; + Bug00013 next = this; + Bug00013 node = new Bug00013(); + anchor.addLink(this, node); + + for (int i=0; i 0, + "run() numThreadsAlive should be > 0"); + Assert(numThreadsActive > 0, + "run() numThreadsActive should be > 0"); + numThreadsAlive--; + myNumThreadsAlive = numThreadsAlive; + numThreadsActive--; + myNumThreadsActive = numThreadsActive; + } + DebugPrintSpin.Lock(); + Console.WriteLine(); + Console.Write("T-<"); + Console.Write(threadid); + Console.Write(","); + Console.Write(myNumThreadsAlive); + Console.Write(","); + Console.Write(myNumThreadsActive); + Console.Write("> "); + DebugPrintSpin.Unlock(); + notifyPending(); + } + + Bug00013 traverse(Bug00013 node, int numStrides) { + lock (Lock) { + recordUndead(); + } + for (int i=0; i= 0); + if (traversalsLeft > traversalLimit) { + traversalsLeft = traversalLimit; + } + if (traversalsLeft == 0) { + bool pended = false; + int myNumThreadsAlive; + int myNumThreadsActive; + lock (Lock) { + Assert(numThreadsActive > 0); + Assert(nextPending == null); + if ((numThreadsActive > maxActive) + || (pendingQueue != null)) { + pended = showPended; + isPending = true; + if (pendingQueue != null) { + Bug00013 pend = pendingQueue; + for (;;) { + Bug00013 curr = pend; + pend = curr.nextPending; + if (pend == null) { + curr.nextPending = this; + break; + } + } + } else { + pendingQueue = this; + } + } + numThreadsActive--; + myNumThreadsAlive = numThreadsAlive; + myNumThreadsActive = numThreadsActive; + } + if (pended) { + DebugPrintSpin.Lock(); + Console.WriteLine(); + Console.Write("T_<"); + Console.Write(threadid); + Console.Write(","); + Console.Write(myNumThreadsAlive); + Console.Write(","); + Console.Write(myNumThreadsActive); + Console.Write("> "); + DebugPrintSpin.Unlock(); + } + notifyPending(); + lock (this) { + while (isPending) { + //try { + Monitor.Wait(this); + //} catch(ThreadInterruptedException) {} + } + Assert(nextPending == null); + } + lock (Lock) { + Assert(numThreadsAlive > 0, + "run() numThreadsAlive should be > 0"); + Assert(numThreadsActive >= 0, + "run() numThreadsActive should be >= 0"); + myNumThreadsAlive = numThreadsAlive; + numThreadsActive++; + myNumThreadsActive = numThreadsActive; + recordUndead(); + } + if (pended) { + DebugPrintSpin.Lock(); + Console.WriteLine(); + Console.Write("T=<"); + Console.Write(threadid); + Console.Write(","); + Console.Write(myNumThreadsAlive); + Console.Write(","); + Console.Write(myNumThreadsActive); + Console.Write("< "); + DebugPrintSpin.Unlock(); + } + traversalsLeft = traversalLimit; + } + traversalsLeft--; + lock (node) { + if (node.numLinks > 0) { + int link = (int)(node.numLinks*random.NextDouble()); + Assert(link >= 0, + "traverse() selected link should be nonnegative"); + Assert(link < node.numLinks, + "traverse() selected link should be < numLinks"); + if (node.links[link] == null) { + DebugPrintSpin.Lock(); + Console.WriteLine("BUG at link "+link); + for (int ii = 0; ii < node.numLinks; ii++) { + Console.WriteLine("link["+ii+"] is " + +node.links[ii]); + } + Console.WriteLine("link["+link+"] is " + +node.links[link]); + DebugPrintSpin.Unlock(); + } + Assert(node.links[link] != null, + "traverse() selected link should not be null"); + node = node.links[link]; + } + } + } + return(node); + } + + bool addLink(Bug00013 last, Bug00013 next) { + Assert(last != null, "addlink() last should not be null"); + Assert(next != null, "addlink() next should not be null"); + if (last == next) return(false); + bool lastLinked = false; + int lastLinks; + bool nextLinked = false; + int nextLinks; + lock (last) { + checkConsistency(); + if (last.numLinks < maxLinks) { + lastLinked = true; + for (int i=0; i0, "addlink() last.numLinks should be > 0"); + last.numLinks--; + for (int i=0; i threadid) { + if (numUndeadThreadids == undeadThreadids.Length) { + numUndeadThreadids--; + } + for (int j=numUndeadThreadids; j>i; j--) { + undeadThreadids[j] = undeadThreadids[j-1]; + } + undeadThreadids[i] = threadid; + numUndeadThreadids++; + return; + } + } + if (numUndeadThreadids == undeadThreadids.Length) return; + undeadThreadids[numUndeadThreadids++] = threadid; + } + + static void DebugPrintUndead() { + char sep = ':'; + for (int i=0; i + + + + + + Bug00013 + Exe + true + 219 + + + + + + + + diff --git a/base/Applications/Tests/Bartok/muwatomic/muwatomic.cs b/base/Applications/Tests/Bartok/muwatomic/muwatomic.cs new file mode 100644 index 0000000..9041fd1 --- /dev/null +++ b/base/Applications/Tests/Bartok/muwatomic/muwatomic.cs @@ -0,0 +1,147 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// + +namespace AtomicTest { + using System; + + internal class Test : Object { + internal int x; + } + + public class muw { + + public volatile static Object o2; + public volatile static Object o3; + + public static void Main(String[] args) { + bool forceGC = true; + + foreach (String arg in args) { + if(arg.Equals("nogc")) { + forceGC = false; + } + } + + for (int i = 0; i < 10; i ++) { + Test lo1 = new Test(); + Test lo2 = new Test(); + Test lo3 = new Test(); + Test lo4 = new Test(); + Test lock_only = new Test(); + int h; + + int h_in1 = 0; + int h_in2 = 0; + int v = 0; + + h = lo3.GetHashCode(); + h = lo4.GetHashCode(); + + // Read from non-inflated objects + Console.WriteLine("\n\nReading in an atomic block"); + try { + v = lo1.x; + v = lo2.x; + if (forceGC) { + GC.Collect(); + } + } catch (AtomicFakeException) { + } + + // Read-modify-write non-inflated objects + Console.WriteLine("\n\nRead-modify-write in an atomic block"); + try { + lo1.x ++; + lo2.x ++; + if (forceGC) { + GC.Collect(); + } + } catch (AtomicFakeException) { + } + + // Read from objects whose multi-use-word is in use + Console.WriteLine("\n\nRead from object with multi-use-word in use"); + try { + v = lo3.x; + v = lo4.x; + if (forceGC) { + GC.Collect(); + } + } catch (AtomicFakeException) { + } + + // Read-modify-write objects whose multi-use-word is in use + Console.WriteLine("\n\nRead-modify-write from object with multi-use-word in use"); + try { + lo3.x ++; + lo4.x ++; + if (forceGC) { + GC.Collect(); + } + } catch (AtomicFakeException) { + } + + // Trigger inflation within a read-modify-write atomic block + Console.WriteLine("\n\nTrigger inflation in a read-modify-write atomic block"); + try { + lo1.x ++; + h_in1 = lo1.GetHashCode(); + if (forceGC) { + GC.Collect(); + } + } catch (AtomicFakeException) { + } + + // Trigger inflation within a read-only atomic block + Console.WriteLine("\n\nTrigger inflation in a read-only atomic block"); + try { + v = lo2.x; + h_in2 = lo2.GetHashCode(); + if (forceGC) { + GC.Collect(); + } + } catch (AtomicFakeException) { + } + + // Read an inflated object + Console.WriteLine("\n\nReading from an inflated object in an atomic block"); + try { + v = lo1.x; + v = lo2.x; + if (forceGC) { + GC.Collect(); + } + } catch (AtomicFakeException) { + } + + // Read-modify-write an inflated object + Console.WriteLine("\n\nRead-modify-write an inflated object in an atomic block"); + try { + v = lo1.x++; + v = lo2.x++; + if (forceGC) { + GC.Collect(); + } + } catch (AtomicFakeException) { + } + + // Read-modify-write an inflated object + Console.WriteLine("\n\nRead-modify-write an inflated object in an atomic block"); + try { + v = lo1.x++; + v = lo2.x++; + if (forceGC) { + GC.Collect(); + } + } catch (AtomicFakeException) { + } + + h = lo1.GetHashCode(); + Console.WriteLine("\n\nDiff on lo1.GetHashCode() = " + (h-h_in1)); + h = lo2.GetHashCode(); + Console.WriteLine("Diff on lo2.GetHashCode() = " + (h-h_in2)); + } + } + } +} diff --git a/base/Applications/Tests/Bartok/muwatomic/muwatomic.csproj b/base/Applications/Tests/Bartok/muwatomic/muwatomic.csproj new file mode 100644 index 0000000..a880347 --- /dev/null +++ b/base/Applications/Tests/Bartok/muwatomic/muwatomic.csproj @@ -0,0 +1,28 @@ + + + + + + + muwatomic + Exe + true + 219 + + + + + + + + diff --git a/base/Applications/Tests/Bartok/readme.txt b/base/Applications/Tests/Bartok/readme.txt new file mode 100644 index 0000000..a5d6b2d --- /dev/null +++ b/base/Applications/Tests/Bartok/readme.txt @@ -0,0 +1 @@ +These tests are copied from the Bartok source tree. \ No newline at end of file diff --git a/base/Applications/Tests/Bartok/tree/tree.cs b/base/Applications/Tests/Bartok/tree/tree.cs new file mode 100644 index 0000000..05c2cf0 --- /dev/null +++ b/base/Applications/Tests/Bartok/tree/tree.cs @@ -0,0 +1,813 @@ +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// The tree implementation comes from Maurice Herlihy's SXM implementation. +// +// Use the command line to set the number of threads and operations, to +// optionally wrap each operation in an atomic or try_all block, and to require +// deterministic output for automated testing. + +namespace Test { + + using System.Threading; + using System.Runtime.CompilerServices; + using System; + using Microsoft.Contracts; + + public enum RunKind { Direct, Atomic, TryAll }; + + public class Config { + + // Create deterministic output for bvt + public static bool DETERMINISTIC = false; + + // Kind of concurrent control to use + public static RunKind KIND; + + // Number of threads to run + public static int THREADS = 1; + + // Number of successful operations per thread (-1 => loop forever) + public static int OP_COUNT = 10000; + + // Range of key values, 0..KEY_SPACE_MASK + public static int KEY_SPACE_MASK = 0xffff; + + // Workload mix, should sum to 0x100 + public static int LOOKUP_FRAC = 0xc0; + public static int REMOVE_FRAC = 0x20; + public static int INSERT_FRAC = 0x20; + } + + // RBTree benchmark originally from Maurice Herlihy's SXM. + + public class RBTree + { + public enum Color {BLACK, RED}; + + public static int INITIAL_SIZE = Config.KEY_SPACE_MASK / 2; + + protected RBNode root; + // sentinelNode is convenient way of indicating a leaf node. + + public static RBNode sentinelNode; + + public int Shadow = 0; + + public int Actual() { + return ActualFrom(root); + } + + public int ActualFrom(RBNode r) { + if (r == sentinelNode) { + return 0; + } else { + return r.Value + ActualFrom(r.Left) + ActualFrom(r.Right); + } + } + + /// + /// Initializes the tree shared by all the threads. + /// + [NotDelayed] + public RBTree() + { + // set up the sentinel node. the sentinel node is the key to a successful + // implementation and for understanding the red-black tree properties. + sentinelNode = new RBNode(); + sentinelNode.Left = null; + sentinelNode.Right = null; + sentinelNode.Parent = null; + sentinelNode.Color = Color.BLACK; + root = sentinelNode; + this.root.Value = Int32.MinValue; + this.root.Color = Color.BLACK; + int size = 0; + Object o = new Object(); + Random random = new Random(o.GetHashCode()); + while (size < INITIAL_SIZE) + { + int n = random.Next(); + // int v = (n >> 8) & 0xfff; + int v = (n >> 8) & Config.KEY_SPACE_MASK; + if ((bool)Insert(v)) { + size++; + Shadow += v; + } + } + } + + /// + /// Inserts an element into the integer set, if it is not already present. + /// + public bool Insert(int key) + { + // traverse tree - find where node belongs + RBNode temp = root; + RBNode parent = null; + + while(temp != sentinelNode) + { // find Parent + parent = temp; + if ( key == temp.Value) + { + return false; + } + else if (key > temp.Value) + { + temp = temp.Right; + } + else + { + temp = temp.Left; + } + } + + // setup node + RBNode node = new RBNode(); + node.Parent = parent; + node.Value = key; + node.Left = sentinelNode; + node.Right = sentinelNode; + + // insert node into tree starting at parent's location + if(node.Parent != null) + { + if (node.Value > node.Parent.Value) + { + node.Parent.Right = node; + } + else + node.Parent.Left = node; + } + else + root = node; // first node added + + RestoreAfterInsert(node); // restore red-black properties + return true; + } + + /// + /// Tests whether item is present. + /// + /// whether the item was present + public bool Contains(int key) + { + RBNode node = root; // begin at root + bool result = false; + + // traverse tree until node is found + while(node != sentinelNode) + { + if (key == node.Value) + { + result = true; + break; + } + else if (key < node.Value) + { + node = node.Left; + } + else + { + node = node.Right; + } + } + return result; + } + + /// + /// Remove item if present. + /// + /// whether the item was removed + public bool Remove(int key) + { + // find node + RBNode node; + + node = root; + while(node != sentinelNode) + { + if (key == node.Value) + { + break; + } + else if (key < node.Value) + { + node = node.Left; + } + else + { + node = node.Right; + } + } + + if(node == sentinelNode) + return false; // key not found + + Delete(node); + return true; + } + + + /// + /// Delete a node + /// + /// node to be deleted + private void Delete(RBNode z) + { + // A node to be deleted will be: + // 1. a leaf with no children + // 2. have one child + // 3. have two children + // If the deleted node is red, the red black properties still hold. + // If the deleted node is black, the tree needs rebalancing + + RBNode x; + RBNode y; // work node + + // find the replacement node (the successor to x) - the node one with + // at *most* one child. + if(z.Left == sentinelNode || z.Right == sentinelNode) + y = z; // node has sentinel as a child + else + { + // z has two children, find replacement node which will + // be the leftmost node greater than z + y = z.Right; // traverse right subtree + while(y.Left != sentinelNode) // to find next node in sequence + y = y.Left; + } + + // at this point, y contains the replacement node. Its content will be copied + // to the values in the node to be deleted + + // x (y's only child) is the node that will be linked to y's old parent. + if(y.Left != sentinelNode) + x = y.Left; + else + x = y.Right; + + // replace x's parent with y's parent and + // link x to proper subtree in parent + // this removes y from the chain + x.Parent = y.Parent; + if(y.Parent != null) + if(y == y.Parent.Left) + y.Parent.Left = x; + else + y.Parent.Right = x; // missing enlist for update + else + root = x; // make x the root node + + // copy the values from y (the replacement node) to the node being deleted. + // note: this effectively deletes the node. + if(y != z) + { + z.Value = y.Value; + } + + if(y.Color == Color.BLACK) + RestoreAfterDelete(x); + } + + /// + /// RestoreAfterDelete + /// Deletions from red-black trees may destroy the red-black + /// properties. Examine the tree and restore. Rotations are normally + /// required to restore it + /// + private void RestoreAfterDelete(RBNode x) + { + // maintain Red-Black tree balance after deleting node + + RBNode y; + + while(x != root && x.Color == Color.BLACK) + { + if(x == x.Parent.Left) // determine sub tree from parent + { + y = x.Parent.Right; // y is x's sibling + if(y.Color == Color.RED) + { // x is black, y is red - make both black and rotate + y.Color = Color.BLACK; + x.Parent.Color = Color.RED; + RotateLeft(x.Parent); + y = x.Parent.Right; + } + if(y.Left.Color == Color.BLACK && + y.Right.Color == Color.BLACK) + { // children are both black + y.Color = Color.RED; // change parent to red + x = x.Parent; // move up the tree + } + else + { + if(y.Right.Color == Color.BLACK) + { + y.Left.Color = Color.BLACK; + y.Color = Color.RED; + RotateRight(y); + y = x.Parent.Right; + } + y.Color = x.Parent.Color; + x.Parent.Color = Color.BLACK; + y.Right.Color = Color.BLACK; + RotateLeft(x.Parent); + x = root; + } + } + else + { // right subtree - same as code above with right and left swapped + y = x.Parent.Left; + if(y.Color == Color.RED) + { + y.Color = Color.BLACK; + x.Parent.Color = Color.RED; + RotateRight (x.Parent); + y = x.Parent.Left; + } + if(y.Right.Color == Color.BLACK && + y.Left.Color == Color.BLACK) + { + y.Color = Color.RED; + x = x.Parent; + } + else + { + if(y.Left.Color == Color.BLACK) + { + y.Right.Color = Color.BLACK; + y.Color = Color.RED; + RotateLeft(y); + y = x.Parent.Left; + } + y.Color = x.Parent.Color; + x.Parent.Color = Color.BLACK; + y.Left.Color = Color.BLACK; + RotateRight(x.Parent); + x = root; + } + } + } + x.Color = Color.BLACK; + } + + private void RestoreAfterInsert(RBNode x) + { + RBNode y; + + // maintain red-black tree properties after adding x + while(x != root && x.Parent.Color == Color.RED) + { + // Parent node is .Colored red; + if(x.Parent == x.Parent.Parent.Left) // determine traversal path + { // is it on the Left or Right subtree? + y = x.Parent.Parent.Right; // get uncle + if(y!= null && y.Color == Color.RED) + { // uncle is red; change x's Parent and uncle to black + x.Parent.Color = Color.BLACK; + y.Color = Color.BLACK; + // grandparent must be red. Why? Every red node that is not + // a leaf has only black children + x.Parent.Parent.Color = Color.RED; + x = x.Parent.Parent; // continue loop with grandparent + } + else + { + // uncle is black; determine if x is greater than Parent + if(x == x.Parent.Right) + { // yes, x is greater than Parent; rotate Left + // make x a Left child + x = x.Parent; + RotateLeft(x); + } + // no, x is less than Parent + x.Parent.Color = Color.BLACK; // make Parent black + x.Parent.Parent.Color = Color.RED; // make grandparent black + RotateRight(x.Parent.Parent); // rotate right + } + } + else + { // x's Parent is on the Right subtree + // this code is the same as above with "Left" and "Right" swapped + y = x.Parent.Parent.Left; + if(y!= null && y.Color == Color.RED) + { + x.Parent.Color = Color.BLACK; + y.Color = Color.BLACK; + x.Parent.Parent.Color = Color.RED; + x = x.Parent.Parent; + } + else + { + if(x == x.Parent.Left) + { + x = x.Parent; + RotateRight(x); + } + x.Parent.Color = Color.BLACK; + x.Parent.Parent.Color = Color.RED; + RotateLeft(x.Parent.Parent); + } + } + } + root.Color = Color.BLACK; // root should always be black + } + + /// + /// RotateLeft + /// Rebalance the tree by rotating the nodes to the left + /// + public void RotateLeft(RBNode x) + { + // pushing node x down and to the Left to balance the tree. x's Right child (y) + // replaces x (since y > x), and y's Left child becomes x's Right child + // (since it's < y but > x). + + RBNode y = x.Right; // get x's Right node, this becomes y + + // set x's Right link + x.Right = y.Left; // y's Left child's becomes x's Right child + + // modify parents + if(y.Left != sentinelNode) + y.Left.Parent = x; // sets y's Left Parent to x + + if(y != sentinelNode) + y.Parent = x.Parent; // set y's Parent to x's Parent + + if(x.Parent != null) + { // determine which side of its Parent x was on + if(x == x.Parent.Left) + x.Parent.Left = y; // set Left Parent to y + else + x.Parent.Right = y; // set Right Parent to y + } + else + root = y; // at root, set it to y + + // link x and y + y.Left = x; // put x on y's Left + if(x != sentinelNode) // set y as x's Parent + x.Parent = y; + } + + /// + /// RotateRight + /// Rebalance the tree by rotating the nodes to the right + /// + public void RotateRight(RBNode x) + { + // pushing node x down and to the Right to balance the tree. x's Left child (y) + // replaces x (since x < y), and y's Right child becomes x's Left child + // (since it's < x but > y). + + RBNode y = x.Left; // get x's Left node, this becomes y + + // set x's Right link + x.Left = y.Right; // y's Right child becomes x's Left child + + // modify parents + if(y.Right != sentinelNode) + y.Right.Parent = x; // sets y's Right Parent to x + + if(y != sentinelNode) + y.Parent = x.Parent; // set y's Parent to x's Parent + + if(x.Parent != null) // null=root, could also have used root + { // determine which side of its Parent x was on + if(x == x.Parent.Right) + x.Parent.Right = y; // set Right Parent to y + else + x.Parent.Left = y; // set Left Parent to y + } + else + root = y; // at root, set it to y + + // link x and y + y.Right = x; // put x on y's Right + if(x != sentinelNode) // set y as x's Parent + x.Parent = y; + } + + private int CountBlackNodes(RBNode root) + { + if (sentinelNode == root) + return 0; + int me = (root.Color == Color.BLACK) ? 1 : 0; + RBNode left = (sentinelNode == root.Left) + ? sentinelNode + : root.Left; + return me + CountBlackNodes(left); + } + + private int Count(RBNode root) + { + if (root == sentinelNode) + return 0; + return 1 + Count(root.Left) + Count(root.Right); + + } + + private void RecursiveValidate(RBNode root, int blackNodes, int soFar) + { + // Empty sub-tree is vacuously OK + if (sentinelNode == root) + return; + + Color rootcolor = root.Color; + soFar += ((Color.BLACK == rootcolor) ? 1 : 0); + root.Marked = true; + + // Check left side + RBNode left = root.Left; + if (sentinelNode != left) + { + if (left.Color == Color.RED && rootcolor == Color.RED) + { + Console.WriteLine("Two consecutive red nodes!"); + return; + } + if (left.Value >= root.Value) + { + Console.WriteLine("Tree values out of order!"); + return; + } + if (left.Marked) + { + Console.WriteLine("Cycle in tree structure!"); + return; + } + RecursiveValidate(left, blackNodes, soFar); + } + + // Check right side + RBNode right = root.Right; + if (sentinelNode != right) + { + if (right.Color == Color.RED && rootcolor == Color.RED) + { + Console.WriteLine("Two consecutive red nodes!"); + return; + } + if (right.Value <= root.Value) + { + Console.WriteLine("Tree values out of order!"); + return; + } + if (right.Marked) + { + Console.WriteLine("Cycle in tree structure!"); + return; + } + RecursiveValidate(right, blackNodes, soFar); + } + + // Check black node count + if (sentinelNode == root.Left || sentinelNode == root.Right) + { + if (soFar != blackNodes) + { + Console.WriteLine("Variable number of black nodes to leaves!"); + return; + } + } + + // Everything checks out if we get this far. + return; + } + + public class RBNode + { + /** creates new tree node **/ + internal int Value = 0; + internal Color Color = Color.RED; + internal bool Marked; + internal RBNode Parent; + internal RBNode Left; + internal RBNode Right; + } + } + + class STMTest { + + static Object o = new Object(); + + public static void ThreadLoop() { + Random random = new Random(); + int my_shadow = 0; + RBTree t = STMTest.t; + bool r; + int i; + + try { + for (i = 0 ; ((Config.OP_COUNT == -1) || (i < Config.OP_COUNT)); i ++) { + int n = random.Next(); + int v = (n >> 8) & Config.KEY_SPACE_MASK; + + r = false; + if ((n & 0xff) < Config.LOOKUP_FRAC) { + if (Config.KIND == RunKind.Atomic) { + try { + r = t.Contains(v); + } catch (AtomicFakeException) { } + } else if (Config.KIND == RunKind.TryAll) { + try { + r = t.Contains(v); + } catch (TryAllFakeException) { } + } else { + r = t.Contains(v); + } + } else if ((n & 0xff) < (Config.LOOKUP_FRAC + Config.REMOVE_FRAC)) { + if (Config.KIND == RunKind.Atomic) { + try { + r = t.Remove(v); + } catch (AtomicFakeException) { } + } else if (Config.KIND == RunKind.TryAll) { + try { + r = t.Remove(v); + } catch (TryAllFakeException) { } + } else { + r = t.Remove(v); + } + if (r) my_shadow -= v; + } else { + if (Config.KIND == RunKind.Atomic) { + try { + r = t.Insert(v); + } catch (AtomicFakeException) { } + } else if (Config.KIND == RunKind.TryAll) { + try { + r = t.Insert(v); + } catch (TryAllFakeException) { } + } else { + r = t.Insert(v); + } + if (r) my_shadow += v; + } + } + } catch (Exception e) { + lock (o) { + Console.WriteLine("Failed with " + e); + } + throw e; + } + + lock (o) { + t.Shadow += my_shadow; + } + } + + static RBTree t; + + private static void Usage(String error) { + Console.WriteLine( +@"Usage: + tree [-t n] [-n n] [-k ] [-d] + + -t n + Use n threads. + + -n n + Perform n operations on each thread. + Runs forever if set to -1. + + -k RunKind + Specify if operation kind should be ""atomic"", ""tryall"", or ""direct"". + + -d + Use deterministic output (for automated testing)."); + + throw new Exception("Illegal input: " + error); + } + + private static String NextArg(string[] args, ref int nextArg) { + if (nextArg >= args.Length) { + Usage("missing argument"); + } + return args[nextArg++]; + } + + private static int NextArgInt(string[] args, ref int nextArg, int min) { + try { + int x = Int32.Parse(NextArg(args, ref nextArg)); + if(x < min) { + Usage("parameter " + (nextArg-1) + " should be >= " + min); + } + return x; + } catch(FormatException) { + Usage("illegal format in parameter " + (nextArg-1)); + return 0; + } catch(OverflowException) { + Usage("overflow in parameter " + (nextArg-1)); + return 0; + } + } + + public static void Main(string[] args) { + + if (Config.LOOKUP_FRAC + Config.REMOVE_FRAC + Config.INSERT_FRAC != 0x100) { + throw new Exception("Operations fractions should sum to 0x100\n"); + } + + int argIndex = 0; + if(argIndex < args.Length) { + if ((String.Compare(args[0], "tree", true) == 0) + || (String.Compare(args[0], "tree.exe", true) == 0) + || (String.Compare(args[0], "tree.x86", true) == 0)) { + argIndex++; + } + } + + // Read config options + while (argIndex < args.Length) { + String arg = NextArg(args, ref argIndex); + switch (arg) { + case "tree": + case "tree.exe": + case "tree.x86": { + // TODO: SINGULARITY: Don't want to see executable name + break; + } + case "-t": { + Config.THREADS = NextArgInt(args, ref argIndex, 0); + break; + } + case "-n": { + Config.OP_COUNT = NextArgInt(args, ref argIndex, -1); + break; + } + case "-k": { + switch (NextArg(args, ref argIndex)) { + case "atomic": { + Config.KIND = RunKind.Atomic; + break; + } + case "tryall": { + Config.KIND = RunKind.TryAll; + break; + } + case "direct": { + Config.KIND = RunKind.Direct; + break; + } + default: { + Usage("Unexpected kind " + args[2]); + break; + } + } + break; + } + case "-d": { + Config.DETERMINISTIC = true; + break; + } + default: { + Usage("unknown parameter: " + arg); + break; + } + } + } + + // Initialise the tree + t = new RBTree(); + + // Start the threads + + // TODO: SINGULARITY: Implement Thread.Name + // Thread.CurrentThread.Name = "Main"; + + Thread[] threads = new Thread[Config.THREADS]; + for (int i = 0; i < Config.THREADS; i ++) { + threads[i] = new Thread (new ThreadStart (ThreadLoop)); + + // TODO: SINGULARITY: Implement Thread.Name + // threads[i].Name = "swapping-thread-" + i; + + threads[i].Start(); + } + + // Wait for the threads to complete + for (int i = 0; i < Config.THREADS; i ++) { + threads[i].Join(); + } + + // Check that dead-reckoned sums agree with what we get + // traversing the tree + int s = t.Shadow; + int a = t.Actual(); + + if (Config.DETERMINISTIC) { + Console.WriteLine("Shadow - Actual = " + (s - a)); + } else { + Console.WriteLine("Shadow = " + s); + Console.WriteLine("Actual = " + a); + } + + if (s != a) { + throw new Exception("Mismatch"); + } + } + } +} diff --git a/base/Applications/Tests/Bartok/tree/tree.csproj b/base/Applications/Tests/Bartok/tree/tree.csproj new file mode 100644 index 0000000..4b6058d --- /dev/null +++ b/base/Applications/Tests/Bartok/tree/tree.csproj @@ -0,0 +1,28 @@ + + + + + + + tree + Exe + true + /codegen:/AtomicSupport=true /codegen:/TryAllSupport=true /codegen:/TryAllSupportLoadStoreOpt=true /codegen:/TryAllSupportSsaNullCheck=true /codegen:/TryAllSupportOptimizePass=true /codegen:/TryAllDecomposeOpt=true /codegen:/IrArrayLoadStoreOpt=false + + + + + + + + diff --git a/base/Applications/Tests/CLink/CLink.csproj b/base/Applications/Tests/CLink/CLink.csproj new file mode 100644 index 0000000..aa8e4bb --- /dev/null +++ b/base/Applications/Tests/CLink/CLink.csproj @@ -0,0 +1,29 @@ + + + + + + + Exe + CLink + + + + + + + + + + + + + diff --git a/base/Applications/Tests/CLink/CLink.sg b/base/Applications/Tests/CLink/CLink.sg new file mode 100644 index 0000000..d99162f --- /dev/null +++ b/base/Applications/Tests/CLink/CLink.sg @@ -0,0 +1,79 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: CLink.sg +// +// Note: Simple ping-pong second child process +// + +using Microsoft.SingSharp; +using Microsoft.SingSharp.Runtime; +using Microsoft.Singularity.Diagnostics.Contracts; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.WebApps; +using Microsoft.Singularity.PingPong.Contracts; +using System; + +namespace Microsoft.Singularity.Applications +{ + public class CLink + { + public static int Main(string[]! args) + { + if (args.Length != 2) { + Console.WriteLine("CLink : Missing identifier arg."); + return 1; + } + string id = args[1]; + + Endpoint * in ExHeap ein = Process.GetStartupEndpoint(0); + PongContract.Exp cin = ein as PongContract.Exp; + if (cin == null) { + delete ein; + Console.WriteLine("CLink{0,2}: Missing incoming PongContract endpoint.", id); + return 2; + } + Endpoint * in ExHeap eout = Process.GetStartupEndpoint(1); + PongContract.Imp cout = eout as PongContract.Imp; + if (cout == null) { + delete eout; + delete cin; + Console.WriteLine("CLink{0,2}: Missing outgoing PongContract endpoint.", id); + return 3; + } + + Console.WriteLine("CLink{0,2}: Waiting for child ready...", id); + cout.RecvPongReady(); + + Console.WriteLine("CLink{0,2}: Ready...", id); + cin.SendPongReady(); + + try { + while(true) { + switch receive { + case cin.Ping(int data): + Console.WriteLine("CLink{0,2}: Ping({1}) to Ping...", id, data); + cout.SendPing(data + 10); + cout.RecvPong(out data); + Console.WriteLine("CLink{0,2}: Pong({1}) to Pong...", id, data); + cin.SendPong(data + 100); + break; + + case cin.ChannelClosed(): + return 0; + } + } + } + finally { + delete cin; + delete cout; + } + Console.WriteLine("CLink{0:d2}: Exiting.", id); + return 3; + } + } +} diff --git a/base/Applications/Tests/CPing/CPing.csproj b/base/Applications/Tests/CPing/CPing.csproj new file mode 100644 index 0000000..8c6307c --- /dev/null +++ b/base/Applications/Tests/CPing/CPing.csproj @@ -0,0 +1,29 @@ + + + + + + + Exe + CPing + + + + + + + + + + + + + diff --git a/base/Applications/Tests/CPing/CPing.sg b/base/Applications/Tests/CPing/CPing.sg new file mode 100644 index 0000000..5d29262 --- /dev/null +++ b/base/Applications/Tests/CPing/CPing.sg @@ -0,0 +1,94 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: CPing.sg +// +// Note: Simple ping-pong test child app #1 +// + +using Microsoft.SingSharp; +using Microsoft.SingSharp.Runtime; +using Microsoft.Singularity; +using Microsoft.Singularity.Diagnostics.Contracts; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.PingPong.Contracts; +using System; +using System.Diagnostics; + +namespace Microsoft.Singularity.Applications +{ + public class CPing + { + public static int Main(String[]! args) + { + int links = 0; + if (args.Length == 2) { + links = Int32.Parse(args[1]); + } + if (args.Length > 1 && links == 0) { + Console.WriteLine("Usage:\n" + + " ping [links]\n" + + "Summary\n" + + " Starts one cpong process and 'links' clink processes."); + return 1; + } + + // Start up the pong process. + PongContract.Imp! pongImp; + PongContract.Exp! pongExp; + + PongContract.NewChannel(out pongImp, out pongExp); + + Console.WriteLine("CPing : Starting cpong."); + + string[] cargs = new string[1]; + cargs[0] = "CPong.x86"; + Process child = new Process(cargs, null, 1); + child.SetStartupEndpoint(0, (Endpoint * in ExHeap)pongExp); + child.Start(); + + // Start up each link process. + for (int i = 0; i < links; i++) { + PongContract.Imp! linkImp; + PongContract.Exp! linkExp; + + PongContract.NewChannel(out linkImp, out linkExp); + + Console.WriteLine("CPing : Starting clink[{0}].", i); + cargs = new string[2]; + cargs[0] = "CLink.x86"; + cargs[1] = i.ToString(); + + child = new Process(cargs, null, 2); + child.SetStartupEndpoint(0, (Endpoint * in ExHeap)linkExp); + child.SetStartupEndpoint(1, (Endpoint * in ExHeap)pongImp); + child.Start(); + + pongImp = linkImp; + } + + Console.WriteLine("CPing : Waiting for cpong."); + pongImp.RecvPongReady(); + + try { + for (int i = 1; i <= 5; ++i) { + int data = i * 1000; + Console.WriteLine("CPing : Ping({0}).", data); + pongImp.SendPing(data); + pongImp.RecvPong(out data); + Console.WriteLine("CPing : Pong({0}).", data); + } + Console.WriteLine("CPing : Finished."); + return 0; + } + finally { + delete pongImp; + } + return 1; + } + } +} diff --git a/base/Applications/Tests/CPong/CPong.csproj b/base/Applications/Tests/CPong/CPong.csproj new file mode 100644 index 0000000..71d1a3a --- /dev/null +++ b/base/Applications/Tests/CPong/CPong.csproj @@ -0,0 +1,29 @@ + + + + + + + Exe + CPong + + + + + + + + + + + + + diff --git a/base/Applications/Tests/CPong/CPong.sg b/base/Applications/Tests/CPong/CPong.sg new file mode 100644 index 0000000..40e1fe3 --- /dev/null +++ b/base/Applications/Tests/CPong/CPong.sg @@ -0,0 +1,58 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: CPong.sg +// +// Note: Simple ping-pong second child process +// + +using Microsoft.SingSharp; +using Microsoft.SingSharp.Runtime; +using Microsoft.Singularity.Diagnostics.Contracts; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.WebApps; +using Microsoft.Singularity.PingPong.Contracts; +using System; + +namespace Microsoft.Singularity.Applications +{ + public class CPong + { + public static int Main() + { + Endpoint * in ExHeap ep = Process.GetStartupEndpoint(0); + PongContract.Exp conn = ep as PongContract.Exp; + if (conn == null) { + delete ep; + Console.WriteLine("CPong : Missing PongContract endpoint."); + return 2; + } + + Console.WriteLine("CPong : Ready..."); + conn.SendPongReady(); + + try { + while(true) { + switch receive { + case conn.Ping(int data): + Console.WriteLine("CPong : Ping({0}) to Pong...", data); + conn.SendPong(data + 1); + break; + + case conn.ChannelClosed(): + return 0; + } + } + } + finally { + delete conn; + } + Console.WriteLine("CPong : Exiting..."); + return 3; + } + } +} diff --git a/base/Applications/Tests/Cast/Cast.cs b/base/Applications/Tests/Cast/Cast.cs new file mode 100644 index 0000000..6fb0ab5 --- /dev/null +++ b/base/Applications/Tests/Cast/Cast.cs @@ -0,0 +1,113 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Cast.cs +// +// Note: Simple Singularity test program. +// +using System; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications { + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal Parameters(); + + internal int AppMain() { + return Cast.AppMain(this); + } + } + + public class Cast + { + private class CastTest + { + int value; + } + + private class CastTestChild : CastTest + { + } + + private static bool TestIs(CastTest c) + { + return c is CastTestChild; + } + + private static bool TestTypeOf(CastTest! c) + { + return c.GetType() == typeof(CastTestChild); + } + + private static CastTestChild TestAs(CastTest c) + { + return c as CastTestChild; + } + + private static CastTestChild TestCast(CastTest c) + { + return (CastTestChild)c; + } + + //[ShellCommand("cast", "Test speed of cast operations")] + internal static int AppMain(Parameters! config) + { + Console.WriteLine("CPU TSC as reference for delay yields:"); + + ulong beg; + ulong end; + + CastTest c = new CastTestChild(); + + Console.Write("Testing Is: "); + beg = Processor.CycleCount; + for (int i = 0; i < 1000; i++) { + TestIs(c); + } + end = Processor.CycleCount; + Console.WriteLine("{0,15}", (end - beg) / 1000); + + Console.Write("Testing Typeof: "); + beg = Processor.CycleCount; + for (int i = 0; i < 1000; i++) { + TestTypeOf(c); + } + end = Processor.CycleCount; + Console.WriteLine("{0,15}", (end - beg) / 1000); + + Console.Write("Testing As: "); + beg = Processor.CycleCount; + for (int i = 0; i < 1000; i++) { + TestAs(c); + } + end = Processor.CycleCount; + Console.WriteLine("{0,15}", (end - beg) / 1000); + + Console.Write("Testing Cast: "); + beg = Processor.CycleCount; + for (int i = 0; i < 1000; i++) { + TestCast(c); + } + end = Processor.CycleCount; + Console.WriteLine("{0,15}", (end - beg) / 1000); + + return 0; + } + } +} diff --git a/base/Applications/Tests/Cast/cast.csproj b/base/Applications/Tests/Cast/cast.csproj new file mode 100644 index 0000000..b04eca4 --- /dev/null +++ b/base/Applications/Tests/Cast/cast.csproj @@ -0,0 +1,25 @@ + + + + + + + Exe + Cast + + + + + + + + + diff --git a/base/Applications/Tests/ChannelDemo/ChannelDemo.csproj b/base/Applications/Tests/ChannelDemo/ChannelDemo.csproj new file mode 100644 index 0000000..480c35d --- /dev/null +++ b/base/Applications/Tests/ChannelDemo/ChannelDemo.csproj @@ -0,0 +1,36 @@ + + + + + + + ChannelDemo + Exe + true + true + + + + + + + + + + + + + + diff --git a/base/Applications/Tests/ChannelDemo/ChannelDemo.sg b/base/Applications/Tests/ChannelDemo/ChannelDemo.sg new file mode 100644 index 0000000..4ec717b --- /dev/null +++ b/base/Applications/Tests/ChannelDemo/ChannelDemo.sg @@ -0,0 +1,156 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: ChannelDemo.cs +// +// Note: Simple Singularity test program. +// +using System; +using System.Threading; +using Microsoft.Singularity.V1.Services; +using Microsoft.Singularity.Channels; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications { + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal Parameters(); + + internal int AppMain() { + return ChannelDemo.AppMain(this); + } + } + + public class ChannelDemo + { + public contract ChannelTest { + in message Hi(int x); + out message Ack(); + + state Start: Hi? -> Ack! -> Start; + } + + private static TRef! endpoint1; + private static TRef! endpoint2; + + + public static void ChannelThread1() + { + ChannelTest.Exp e1 = endpoint1.Acquire(); + + for (int i = 1; i <= 3; i++) { + Console.WriteLine("Thread 1 receiving message {0}...", i); + DebugStub.Print("Thread 1 receiving message {0}...\n", __arglist(i)); + + int len; + e1.RecvHi(out len); + e1.SendAck(); + + Console.WriteLine("Thread 1 received Hi message {0}.", len); + DebugStub.Print("Thread 1 received Hi message {0}.\n", __arglist(len)); + } + + delete e1; + } + + public static void ChannelThread2() + { + ChannelTest.Imp e2 = endpoint2.Acquire(); + Console.WriteLine("Thread 2 sending message 1..."); + DebugStub.Print("Thread 2 sending message 1...\n"); + e2.SendHi(1); + e2.RecvAck(); + + Thread.Yield(); + + Console.WriteLine("Thread 2 sending message 2..."); + DebugStub.Print("Thread 2 sending message 2...\n"); + e2.SendHi(2); + e2.RecvAck(); + + Console.WriteLine("Thread 2 sending message 3..."); + DebugStub.Print("Thread 2 sending message 3...\n"); + e2.SendHi(3); + e2.RecvAck(); + + delete e2; + } + + static TimeSpan TwoSecondTimeout = new TimeSpan(0, 0, 0, 2); + + public static void TimeoutDemo() { + ChannelTest.Exp! exp; + ChannelTest.Imp! imp; + ChannelTest.NewChannel(out imp, out exp); + + Console.WriteLine("Timeout test"); + Console.WriteLine("Time now: {0}", DateTime.Now); + Console.WriteLine("Timeout: {0}", TwoSecondTimeout); + + switch receive { + case exp.Hi(x): + Console.WriteLine("Got Hi, but shouldn't have"); + DebugService.Break(); + break; + + case timeout(TwoSecondTimeout): + Console.WriteLine("Got timeout"); + Console.WriteLine("Time now: {0}", DateTime.Now); + break; + } + delete exp; + delete imp; + } + + + //[ShellCommand("channel", "Run channel demo")] + internal static int AppMain(Parameters! config) + { + // Now test timeout feature + TimeoutDemo(); + + // Make a new channel. + ChannelTest.Imp! e2; + ChannelTest.Exp! e1; + + ChannelTest.NewChannel(out e2, out e1); + + // Endpoints are initially owned by the creating thread. + // We're going to transfer ownership to other threads, so + // we release them here. + endpoint1 = new TRef(e1); + endpoint2 = new TRef(e2); + + // Create our two threads. + Thread t1 = new Thread(new ThreadStart(ChannelThread1)); + t1.Start(); + + Thread t2 = new Thread(new ThreadStart(ChannelThread2)); + t2.Start(); + + // Yield a bunch of times to give our threads a chance to + // do their work. + for (int i = 0; i < 10; i++) { + Thread.Yield(); + } + + return 0; + } + } +} + diff --git a/base/Applications/Tests/ChannelPerf/ChannelPerf.csproj b/base/Applications/Tests/ChannelPerf/ChannelPerf.csproj new file mode 100644 index 0000000..eebc476 --- /dev/null +++ b/base/Applications/Tests/ChannelPerf/ChannelPerf.csproj @@ -0,0 +1,25 @@ + + + + + + + Exe + ChannelPerf + + + + + + + + + diff --git a/base/Applications/Tests/ChannelPerf/ChannelPerf.sg b/base/Applications/Tests/ChannelPerf/ChannelPerf.sg new file mode 100644 index 0000000..3a22208 --- /dev/null +++ b/base/Applications/Tests/ChannelPerf/ChannelPerf.sg @@ -0,0 +1,203 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: ChannelPerf.cs +// +// Note: Simple Singularity test program. +// +using System; +using System.Threading; +using Microsoft.Singularity.Channels; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications { + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [LongParameter( "count", Position=0, Default=1000, HelpMessage="count")] + internal long count; + + [BoolParameter( "a", Default=false, HelpMessage="Do Allocation")] + internal bool doAlloc; + + [BoolParameter( "t", Default=false, HelpMessage="Do ThreadCount2 test")] + internal bool doThread2; + + reflective internal Parameters(); + + internal int AppMain() { + return ChannelPerf.AppMain(this); + } + } + + public class ChannelPerf + { + public contract ChannelPerfTest { + message Req(int x); + message Resp(int x); + + state Start: Req? -> Resp! -> Start; + } + + private static TRef! cpendpoint1; + private static TRef! cpendpoint2; + + public static void ChannelPerfThread1() + { + ChannelPerfTest.Exp e1 = cpendpoint1.Acquire(); + int arg; + + while (true) { + e1.RecvReq(out arg); + if (arg == -1) break; + e1.SendResp(arg); + } + + delete e1; + } + + public static void ChannelPerfThread3( int count, bool doAlloc ) + { + ChannelPerfTest.Imp e2 = cpendpoint2.Acquire(); + int arg; + int num = count; + byte [] foo; + + int collectorCountStart; + long collectorMillisStart, collectorBytesStart; + + int collectorCountEnd; + long collectorMillisEnd, collectorBytesEnd; + + Console.WriteLine("Sending/(switch) recving {0} messages ...", num); + if (doAlloc) + Console.WriteLine(" will do allocation "); + + ulong before = Processor.CycleCount; + GC.PerformanceCounters(out collectorCountStart, out collectorMillisStart, out collectorBytesStart); + + for (int i = 0; i < num; i++) { + arg = i; + e2.SendReq(arg); + switch receive + { + case e2.Resp(reply): + if (doAlloc) + { + foo = new byte[20000]; + foo[1] = 0x3; // keep the compiler happy + } + break; + case e2.ChannelClosed(): + throw new Exception("Didn't e2.Resp(arg)"); + break; + } + } + + GC.PerformanceCounters( out collectorCountEnd, out collectorMillisEnd, out collectorBytesEnd); + ulong after = Processor.CycleCount; + Console.WriteLine("Done sending messages ..."); + e2.SendReq(-1); + delete e2; + Console.WriteLine("Elapsed cycles {0}", after - before); + Console.WriteLine("Cycles/RPC {0}", (after - before)/(ulong)num); + + Console.WriteLine(" num GCs:{0}, milli={1}, bytes={2}\n", + (collectorCountEnd - collectorCountStart), + (collectorMillisEnd - collectorMillisStart), + (collectorBytesEnd - collectorBytesStart) + ); + } + + public static void ChannelPerfThread2() + { + ChannelPerfTest.Imp e2 = cpendpoint2.Acquire(); + int arg; + const int num = 1000; + int collectorCountStart; + long collectorMillisStart, collectorBytesStart; + + int collectorCountEnd; + long collectorMillisEnd, collectorBytesEnd; + + Console.WriteLine("Sending/recving {0} messages ...", num); + GC.PerformanceCounters(out collectorCountStart, out collectorMillisStart, out collectorBytesStart); + + Console.WriteLine(" Start: num GCs:{0}, milli={1}, bytes={2}\n", + collectorCountStart, + collectorMillisStart, + collectorBytesStart + ); + + ulong before = Processor.CycleCount; + for (int i = 0; i < num; i++) { + arg = i; + e2.SendReq(arg); + e2.RecvResp(out arg); + } + + GC.PerformanceCounters( out collectorCountEnd, out collectorMillisEnd, out collectorBytesEnd); + + ulong after = Processor.CycleCount; + Console.WriteLine("Done sending messages ..."); + e2.SendReq(-1); + delete e2; + Console.WriteLine("Elapsed cycles {0}", after - before); + Console.WriteLine("Cycles/RPC {0}", (after - before)/num); + Console.WriteLine(" num GCs:{0}, milli={1}, bytes={2}\n", + (collectorCountEnd - collectorCountStart), + (collectorMillisEnd - collectorMillisStart), + (collectorBytesEnd - collectorBytesStart) + ); + + } + + //[ShellCommand("channelperf", "Measure channel performance")] + internal static int AppMain(Parameters! config) + { + + bool doAlloc = config.doAlloc; + int count = (int) config.count; + + // Make a new channel. + ChannelPerfTest.Imp! e2; + ChannelPerfTest.Exp! e1; + + ChannelPerfTest.NewChannel(out e2, out e1); + + // Endpoints are initially owned by the creating thread. + // We're going to transfer ownership to other threads, so + // we release them here. + cpendpoint1 = new TRef(e1); + cpendpoint2 = new TRef(e2); + + // Create our two threads. + Thread t1 = new Thread(new ThreadStart(ChannelPerfThread1)); + t1.Start(); + + //Thread t2 = new Thread(new ThreadStart(ChannelPerfThread2)); + //t2.Start(); + + // Actually just call into Thread2 so we don't have to sit here + // twiddling our thumbs! :-) + + if (config.doThread2) ChannelPerfThread2(); + else ChannelPerfThread3(count,doAlloc); + return 0; + } + } +} diff --git a/base/Applications/Tests/ClockTest/ClockTest.cs b/base/Applications/Tests/ClockTest/ClockTest.cs new file mode 100644 index 0000000..ecb655c --- /dev/null +++ b/base/Applications/Tests/ClockTest/ClockTest.cs @@ -0,0 +1,90 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: ClockTest.cs +// +// Note: Simple Singularity test program. +// +using System; +using Microsoft.Singularity.V1.Services; + +using Microsoft.Singularity.Channels; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications { + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal Parameters(); + + internal int AppMain() { + return ClockTest.AppMain(this); + } + } + + public class ClockTest + { + //[ShellCommand("clocktest", "Run clock test")] + internal static int AppMain(Parameters! config) + { + Console.WriteLine("CPU TSC as reference for delay yields:"); + + for (uint divisor = 512; divisor > 0; divisor >>= 1) { + ulong deltaTSC = (ulong) (ProcessService.GetCyclesPerSecond() / divisor); + + long endKernelTicks = 0; + ulong endTSC; + + long startKernelTicks = ProcessService.GetUpTime().Ticks; + ulong startTSC = (ulong) (ProcessService.GetCycleCount()); + + ulong finalTSC = startTSC + deltaTSC; + + do { + endKernelTicks = ProcessService.GetUpTime().Ticks; + endTSC = (ulong) (ProcessService.GetCycleCount()); + } while (endTSC < finalTSC); + + long usKernel = (endKernelTicks - startKernelTicks) / 10; + ulong usTSC = 1000000u * (endTSC - startTSC) / (ulong) (ProcessService.GetCyclesPerSecond()); + Console.Write(" Target {0,7} us TSC {1,7} us HW {2,7} us\n", + 1000000 / divisor, (int)usTSC, (int)usKernel); + } + + Console.WriteLine("\nHW Clock as reference for delay yields:"); + for (uint divisor = 512; divisor > 0; divisor >>= 1) { + long endKernelTicks = 0; + ulong endTSC; + + long startKernelTicks = ProcessService.GetUpTime().Ticks; + ulong startTSC = (ulong) (ProcessService.GetCycleCount()); + + long finalKernelTicks = startKernelTicks + 10000000 / divisor; + + do { + endKernelTicks = ProcessService.GetUpTime().Ticks; + endTSC = (ulong) (ProcessService.GetCycleCount()); + } while (endKernelTicks < finalKernelTicks); + + long usKernel = (endKernelTicks - startKernelTicks) / 10; + ulong usTSC = 1000000u * (endTSC - startTSC) / (ulong) (ProcessService.GetCyclesPerSecond()); + Console.Write(" Target {0,7} us TSC {1,7} us HW {2,7} us\n", + 1000000 / divisor, (int)usTSC, (int)usKernel); + } + return 0; + } + } +} diff --git a/base/Applications/Tests/ClockTest/ClockTest.csproj b/base/Applications/Tests/ClockTest/ClockTest.csproj new file mode 100644 index 0000000..6ed035d --- /dev/null +++ b/base/Applications/Tests/ClockTest/ClockTest.csproj @@ -0,0 +1,25 @@ + + + + + + + Exe + ClockTest + + + + + + + + + diff --git a/base/Applications/Tests/Collect/Collect.cs b/base/Applications/Tests/Collect/Collect.cs new file mode 100644 index 0000000..1a7b1ad --- /dev/null +++ b/base/Applications/Tests/Collect/Collect.cs @@ -0,0 +1,146 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Collect.cs +// +// Note: Simple Singularity test program. +// +using System; +using Microsoft.Singularity.V1.Services; +using Microsoft.Contracts; +using Microsoft.Singularity.Channels; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications { + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [BoolParameter( "set", Default=false, HelpMessage="Run set test.")] + internal bool doSetTest; + + reflective internal Parameters(); + + internal int AppMain() { + return Collect.AppMain(this); + } + } + + public class Collect + { + class LinkedList + { + private LinkedList next; + private LinkedList prev; + public int value; + private byte[]! data; + + private LinkedList(int i, [Delayed] LinkedList _prev) + { + prev = _prev; + value = i; + + if (i <= 1) + { + next = null; + } + else + { + next = new LinkedList(i - 1, this); + } + data = new byte [24576 + 1024 * i]; + } + + ~LinkedList() + { + DebugStub.Print("Finalizer called for Value={0}.\n", __arglist(value)); + } + + public void Print() + { + Console.WriteLine("Print {0}", value); + } + + public void PrintNext() + { + Console.WriteLine("Linked Data: [{0} items]", value); + PrintNext(value); + } + + private void PrintNext(int _value) + requires next != null; + { + Console.WriteLine(" Value = {0} [Next] {1}, {2} bytes payload", + value, next.value, data.Length); + if (next.value != _value) + { + next.PrintNext(_value); + } + } + + public void PrintPrev() + { + Console.WriteLine("PrintPrev {0}", value); + PrintPrev(value); + } + + private void PrintPrev(int _value) + requires prev != null; + { + Console.WriteLine(" Value = {0} [Prev] {1}", value, prev.value); + if (prev.value != _value) + { + prev.PrintPrev(_value); + } + } + + private LinkedList! Last() + { + if (next != null) + { + return next.Last(); + } + return this; + } + + public static LinkedList! CreateCycle(int links) + { + LinkedList root = new LinkedList(links, null); + LinkedList last = root.Last(); + + root.prev = last; + last.next = root; + + return root; + } + } + + internal static int AppMain(Parameters! config) + { + LinkedList root = LinkedList.CreateCycle(4); + root.PrintNext(); + root = null; + + Console.WriteLine(); + + Console.WriteLine("Collecting garbage [before heap: {0,8} bytes]", + GC.GetTotalMemory(false)); + GC.Collect(); + Console.WriteLine("Collecting garbage [after heap: {0,8} bytes]", + GC.GetTotalMemory(false)); + return 0; + } + } +} diff --git a/base/Applications/Tests/Collect/Collect.csproj b/base/Applications/Tests/Collect/Collect.csproj new file mode 100644 index 0000000..4f47838 --- /dev/null +++ b/base/Applications/Tests/Collect/Collect.csproj @@ -0,0 +1,25 @@ + + + + + + + Exe + Collect + + + + + + + + + diff --git a/base/Applications/Tests/ConsoleDemo/ConsoleDemo.csproj b/base/Applications/Tests/ConsoleDemo/ConsoleDemo.csproj new file mode 100644 index 0000000..6a85612 --- /dev/null +++ b/base/Applications/Tests/ConsoleDemo/ConsoleDemo.csproj @@ -0,0 +1,25 @@ + + + + + + + Exe + ConsoleDemo + + + + + + + + + diff --git a/base/Applications/Tests/ConsoleDemo/ConsoleDemo.sg b/base/Applications/Tests/ConsoleDemo/ConsoleDemo.sg new file mode 100644 index 0000000..6dae956 --- /dev/null +++ b/base/Applications/Tests/ConsoleDemo/ConsoleDemo.sg @@ -0,0 +1,385 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: ChannelDemo.cs +// +// Note: Simple Singularity test program. +// + +using System; +using System.Threading; +using Microsoft.Singularity.V1.Services; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Io; +using Microsoft.SingSharp; + +using Microsoft.Singularity.Channels; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications.Tests { + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal Parameters(); + + internal int AppMain() { + return ConsoleDemo.AppMain(this); + } + } + + public class ConsoleDemo + { + private static ConsoleDeviceContract.Imp + OpenConsoleInternal(DirectoryServiceContract.Imp! nsImp, + [Claims] char[]! in ExHeap deviceName) + { + ConsoleDeviceContract.Exp! exp; + ConsoleDeviceContract.Imp! imp; + ConsoleDeviceContract.NewChannel(out imp, out exp); + + nsImp.SendBind(deviceName, exp); + switch receive + { + case nsImp.AckBind(): + return imp; + break; + case nsImp.NakBind(rejectImp, error): + delete rejectImp; + delete imp; + break; + case nsImp.ChannelClosed(): + throw new Exception("Channel closed during Console bind."); + delete imp; + break; + case nsImp.NakBindReparse(path, rest, linked, backExp): + assert linked == true; + assert rest == null; + delete backExp; + delete imp; + + return OpenConsoleInternal(nsImp, path); + break; + } + return null; + } + + private static ConsoleDeviceContract.Imp OpenConsole(string! devName) + { + DirectoryServiceContract.Imp ns = DirectoryService.NewClientEndpoint(); + ConsoleDeviceContract.Imp imp = + OpenConsoleInternal(ns, Bitter.FromString2(devName)); + delete ns; + + if (imp != null) { + switch receive + { + case imp.Success(): + break; + case imp.ContractNotSupported(): + throw new Exception("ConsoleOutput: ContractNotSupported"); + break; + case imp.ChannelClosed(): + throw new Exception("ConsoleOutput: ChannelClosed"); + break; + } + } + return imp; + } + + private static void ConsoleWrite(ConsoleDeviceContract.Imp! imp, + string! message) + { + char[]! in ExHeap m = Bitter.FromString2(message); + imp.SendWrite(m, 0, m.Length); + imp.RecvAckWrite(out m); + delete m; + } + + private static void DrawLine(ConsoleDeviceContract.Imp! imp, + int x1, int y1, int x2, int y2, + char c) + { + int dx = x2 - x1; + int dy = y2 - y1; + + if (dx == 0) { + if (dy == 0) { + imp.SendPutCharAt(c, x1, y1); + imp.RecvAckPutCharAt(); + return; + } + + dy = dy / Math.Abs(dy); + for (int y = y1; y != y2; y += dy) { + imp.SendPutCharAt(c, x1, y); + imp.RecvAckPutCharAt(); + } + return; + } + else if (dy == 0) { + dx = dx / Math.Abs(dx); + for (int x = x1; x != x2; x += dx) { + imp.SendPutCharAt(c, x, y1); + imp.RecvAckPutCharAt(); + } + return; + } + + if (dx < 0) dx = -dx; + if (dy < 0) dy = -dy; + + double scale = 0; + int end = 0; + if (dx > dy) { + scale = 1.0 / (double)dx; + end = dx; + } + else { + scale = 1.0 / (double)dy; + end = dy; + } + for (int i = 0; i < end; i++) { + double x = (x1 * i * scale) + (x2 * (end - i - 1) * scale); + double y = (y1 *i* scale) + (y2 * (end - i - 1) * scale); + imp.SendPutCharAt(c, (int)x, (int)y); + imp.RecvAckPutCharAt(); + } + } + + private static void BoxDemo(ConsoleDeviceContract.Imp! imp, + int columns, int rows) + { + int cc = columns / 2; + int cr = rows / 2; + int edge = Math.Min(cc, cr); + for (int i = 0 ; i < edge; i++) { + DrawLine(imp, cc - i, cr - i, cc - i, cr + i, '*'); + DrawLine(imp, cc - i, cr + i, cc + i, cr + i, '*'); + DrawLine(imp, cc + i, cr + i, cc + i, cr - i, '*'); + DrawLine(imp, cc + i, cr - i, cc - i, cr - i, '*'); + Thread.Sleep(TimeSpan.FromMilliseconds(20)); + DrawLine(imp, cc - i, cr - i, cc - i, cr + i, ' '); + DrawLine(imp, cc - i, cr + i, cc + i, cr + i, ' '); + DrawLine(imp, cc + i, cr + i, cc + i, cr - i, ' '); + DrawLine(imp, cc + i, cr - i, cc - i, cr - i, ' '); + } + } + + private static void SpinBoxDemo(ConsoleDeviceContract.Imp! imp, + int columns, int rows) + { + const int twoPiSteps = 16; + int cc = columns / 2; + int cr = rows / 2; + int r = 2 * Math.Min(cc, cr) / 3; + double tau = 2 * Math.PI / twoPiSteps; + for (int i = 0 ; i < 5 * twoPiSteps; i++) { + double theta = i * tau; + int x = (int)(r * Math.Sin(theta)); + int y = (int)(r * Math.Cos(theta)); + DrawLine(imp, cc + x, cr + y, cc + y, cr - x, 'O'); + DrawLine(imp, cc + y, cr - x, cc - x, cr - y, 'O'); + DrawLine(imp, cc - x, cr - y, cc - y, cr + x, 'O'); + DrawLine(imp, cc - y, cr + x, cc + x, cr + y, 'O'); + Thread.Sleep(TimeSpan.FromMilliseconds(20)); + DrawLine(imp, cc + x, cr + y, cc + y, cr - x, ' '); + DrawLine(imp, cc + y, cr - x, cc - x, cr - y, ' '); + DrawLine(imp, cc - x, cr - y, cc - y, cr + x, ' '); + DrawLine(imp, cc - y, cr + x, cc + x, cr + y, ' '); + } + } + + private static void AnnounceDemo(ConsoleDeviceContract.Imp! imp, + string! title) + { + Thread.Sleep(TimeSpan.FromSeconds(3)); + imp.SendClear(); + imp.RecvAckClear(); + imp.SendSetCursorPosition(0, 1); // Avoid top line for thread state + imp.RecvAckSetCursorPosition(); + char []! in ExHeap buffer = Bitter.FromString2(title); + imp.SendWrite(buffer, 0, title.Length); + imp.RecvAckWrite(out buffer); + delete buffer; + Thread.Sleep(TimeSpan.FromSeconds(1)); + } + + private static void RunDemo(ConsoleDeviceContract.Imp! imp) + { + // This is just a quick placeholder that shows + // we can write at arbitrary points on the screen. + + AnnounceDemo(imp, "Text positioning demo (diagonal 2:1)"); + + int columns, rows; + imp.SendGetDisplayDimensions(); + imp.RecvDisplayDimensions(out columns, out rows); + + int oldColumn, oldRow; + imp.SendGetCursorPosition(); + imp.RecvCursorPosition(out oldColumn, out oldRow); + + char []! in ExHeap message = Bitter.FromString2("Hello World"); + + for (int i = 2; i < 11; i++) { + imp.SendSetCursorPosition(2 * i, i); + imp.RecvAckSetCursorPosition(); + imp.SendWrite(message, 0, message.Length); + imp.RecvAckWrite(out message); + } + Thread.Sleep(TimeSpan.FromMilliseconds(3000)); + delete message; + + // --------------------------------------------------------------- + + AnnounceDemo(imp, "Testing PutCharAt(). Cursor here..."); + + for (int i = 0; i < columns; i++) { + imp.SendPutCharAt('#', i, 0); + imp.RecvAckPutCharAt(); + imp.SendPutCharAt('#', i, rows - 1); + imp.RecvAckPutCharAt(); + Thread.Sleep(TimeSpan.FromMilliseconds(10)); + } + for (int i = 0; i < rows; i++) { + imp.SendPutCharAt('#', 0, i); + imp.RecvAckPutCharAt(); + imp.SendPutCharAt('#', columns - 1, i); + imp.RecvAckPutCharAt(); + Thread.Sleep(TimeSpan.FromMilliseconds(10)); + } + + // --------------------------------------------------------------- + + AnnounceDemo(imp, "Testing SetCursorSize(Large)..."); + + imp.SendSetCursorSize(CursorSize.Large); + switch receive { + case imp.AckSetCursorSize(): + ConsoleWrite(imp, "okay"); + break; + case imp.NotSupported(): + ConsoleWrite(imp, "not supported"); + break; + } + + // --------------------------------------------------------------- + + AnnounceDemo(imp, "Testing SetCursorSize(Small)..."); + + imp.SendSetCursorSize(CursorSize.Small); + switch receive { + case imp.AckSetCursorSize(): + Console.Write("okay"); + break; + case imp.NotSupported(): + Console.Write("not supported"); + break; + } + + // --------------------------------------------------------------- + + AnnounceDemo(imp, "Testing SetCursorPosition()/PutChar(). Cursor moving."); + + imp.SendSetCursorPosition(columns / 2, rows / 2); + imp.RecvAckSetCursorPosition(); + + imp.SendCursorShow(); + imp.RecvAckCursorShow(); + for (int i = 0; i < columns; i++) { + imp.SendSetCursorPosition(i, rows / 2); + imp.RecvAckSetCursorPosition(); + imp.SendPutChar('>'); + imp.RecvAckPutChar(); + Thread.Sleep(TimeSpan.FromMilliseconds(10)); + } + for (int i = 0; i < columns; i++) { + imp.SendSetCursorPosition(columns - i - 1, rows / 2); + imp.RecvAckSetCursorPosition(); + imp.SendPutChar('<'); + imp.RecvAckPutChar(); + Thread.Sleep(TimeSpan.FromMilliseconds(10)); + } + + // --------------------------------------------------------------- + + AnnounceDemo(imp, "Testing ClearCursorToEndOfLine()."); + + for (int c = 0; c < columns; c++) { + for (int r = 0; r < 10; r++) { + imp.SendPutCharAt('A', c, r + 3); + imp.RecvAckPutCharAt(); + } + } + for (int r = 0; r < 5; r++) { + imp.SendSetCursorPosition(columns - r - 1, r + 3); + imp.RecvAckSetCursorPosition(); + imp.SendClearCursorToEndOfLine(); + imp.RecvAckClearCursorToEndOfLine(); + Thread.Sleep(TimeSpan.FromMilliseconds(1000)); + } + for (int r = 5; r < 10; r++) { + imp.SendSetCursorPosition(columns - 10 + r, r + 3); + imp.RecvAckSetCursorPosition(); + imp.SendClearCursorToEndOfLine(); + imp.RecvAckClearCursorToEndOfLine(); + Thread.Sleep(TimeSpan.FromMilliseconds(1000)); + } + + // --------------------------------------------------------------- + + AnnounceDemo(imp, "Cursor is about to be hidden and boxes drawn."); + + imp.SendCursorHide(); + imp.RecvAckCursorHide(); + + BoxDemo(imp, columns, rows); + + // --------------------------------------------------------------- + + AnnounceDemo(imp, "Spinning Box demo."); + + SpinBoxDemo(imp, columns, rows); + + // --------------------------------------------------------------- + + imp.SendCursorShow(); + imp.RecvAckCursorShow(); + + imp.SendClear(); + imp.RecvAckClear(); + + imp.SendSetCursorPosition(oldColumn, oldRow); + imp.RecvAckSetCursorPosition(); + } + + internal static int AppMain(Parameters! config) + { + foreach (string s in new string [] { "/dev/video-text", + "/dev/conout" }) { + ConsoleDeviceContract.Imp imp = OpenConsole((!)s); + if (imp != null) { + Console.WriteLine("Opened {0}\n", s); + RunDemo(imp); + delete imp; + break; + } + } + return 0; + } + } +} diff --git a/base/Applications/Tests/DumpPages/DumpPages.cs b/base/Applications/Tests/DumpPages/DumpPages.cs new file mode 100644 index 0000000..b38a6d4 --- /dev/null +++ b/base/Applications/Tests/DumpPages/DumpPages.cs @@ -0,0 +1,24 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: DumpPages.cs +// +// Note: Simple Singularity test program. +// +using System; + +namespace Microsoft.Singularity.Applications +{ + public class DumpPages + { + //[ShellCommand("dump", "Dump page table")] + public static int Main(String[] args) + { + AppRuntime.DumpPageTable(); + return 0; + } + } +} diff --git a/base/Applications/Tests/DumpPages/DumpPages.csproj b/base/Applications/Tests/DumpPages/DumpPages.csproj new file mode 100644 index 0000000..3b29a89 --- /dev/null +++ b/base/Applications/Tests/DumpPages/DumpPages.csproj @@ -0,0 +1,35 @@ + + + + + + + DumpPages + Exe + true + true + + + + + + + + + + + + + diff --git a/base/Applications/Tests/GcStress/GcStress.csproj b/base/Applications/Tests/GcStress/GcStress.csproj new file mode 100644 index 0000000..e779eb4 --- /dev/null +++ b/base/Applications/Tests/GcStress/GcStress.csproj @@ -0,0 +1,32 @@ + + + + + + + Exe + Cast + + + + + + + + + + + + + + + + diff --git a/base/Applications/Tests/GcStress/GcStress.sg b/base/Applications/Tests/GcStress/GcStress.sg new file mode 100644 index 0000000..afedb9d --- /dev/null +++ b/base/Applications/Tests/GcStress/GcStress.sg @@ -0,0 +1,177 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: GcStress.sg +// +// Note: Simple Singularity test program. +// +using System; +using System.Collections; +using Microsoft.SingSharp; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Stress.Contracts; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications { + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [BoolParameter( "kernel", Default=false, HelpMessage="Run kernel test.")] + internal bool doKernelTest; + + reflective internal Parameters(); + + internal int AppMain() { + return GcStress.AppMain(this); + } + } + + public class GcStress : Microsoft.Singularity.Stress.GcStress + { + override protected void Print(string! s) + { + Console.Write(s); + } + + //[ShellCommand("gcstress", "Stress garbage collector")] + internal static int AppMain(Parameters! config) + { + const int ARGS_START = 1; + + if (!config.doKernelTest) + { + new GcStress().Run(); + } + else { + DirectoryServiceContract.Imp! epNS = DirectoryService.NewClientEndpoint(); + + try + { + StressContract.Imp! imp; + StressContract.Exp! exp; + StressContract.NewChannel(out imp, out exp); + + ErrorCode errorOut; + bool ok = SdsUtils.Bind(StressContract.ModuleName, epNS, exp, out errorOut); + if (!ok) { + Console.Write("failure on lookup of name " + StressContract.ModuleName + + "reason: " + SdsUtils.ErrorCodeToString(errorOut)); + delete imp; + if (errorOut == ErrorCode.ChannelClosed) + { + throw new Exception("Encountered a ChannelClosed"); + } + return 1; + } + else { + switch receive + { + case imp.Ready() : + break; + case imp.ContractNotSupported() : + Console.Write("failure: contract not supported"); + delete imp; + return 1; + case imp.ChannelClosed() : + Console.Write("failure: channel closed prematurely"); + delete imp; + return 1; + } + imp.SendGcStress(); + while (true) + { + switch receive + { + case imp.Print(char[] in ExHeap s) : + Console.Write(Bitter.ToString(s)); + imp.SendAckPrint(); + delete s; + break; + + case imp.GcStressDone() : + delete imp; + return 0; + + case imp.ChannelClosed() : + delete imp; + return 0; + } + } + } +/* +// epNS.SendBind(Bitter.FromString2(StressContract.ModuleName), exp); + + switch receive + { + case epNS.NakBind(rejected, error) : + // failure + Console.Write("failure on lookup of name " + StressContract.ModuleName); + delete imp; + delete rejected; + return 1; + + case epNS.AckBind() : + // success + switch receive + { + case imp.Ready() : + break; + case imp.ContractNotSupported() : + Console.Write("failure: contract not supported"); + delete imp; + return 1; + case imp.ChannelClosed() : + Console.Write("failure: channel closed prematurely"); + delete imp; + return 1; + } + imp.SendGcStress(); + while (true) + { + switch receive + { + case imp.Print(char[] in ExHeap s) : + Console.Write(Bitter.ToString(s)); + imp.SendAckPrint(); + delete s; + break; + + case imp.GcStressDone() : + delete imp; + return 0; + + case imp.ChannelClosed() : + delete imp; + return 0; + } + } + case epNS.ChannelClosed() : + throw new Exception("epNS channel closed"); + } +*/ + } + finally + { + delete epNS; + } + } + return 0; + } + } +} diff --git a/base/Applications/Tests/Hog/Hog.cs b/base/Applications/Tests/Hog/Hog.cs new file mode 100644 index 0000000..d7820cf --- /dev/null +++ b/base/Applications/Tests/Hog/Hog.cs @@ -0,0 +1,61 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Hog.cs +// +// Note: Simple Singularity test program. +// +using System; +using System.Threading; + +using Microsoft.Singularity.Channels; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications { + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal Parameters(); + + internal int AppMain() { + return Hog.AppMain(this); + } + } + + public class Hog + { + public static void HogFunction() + { + int i = 0; + while (true) { + if ((i % 10000000) == 0) { + Console.Write("."); + } + i++; + } + } + + //[ShellCommand("hog", "Run processor hog")] + internal static int AppMain(Parameters! config) + { + Console.WriteLine("Starting a hog..."); + + Thread hog = new Thread(new ThreadStart(HogFunction)); + hog.Start(); + return 0; + } + } +} diff --git a/base/Applications/Tests/Hog/Hog.csproj b/base/Applications/Tests/Hog/Hog.csproj new file mode 100644 index 0000000..5c72a92 --- /dev/null +++ b/base/Applications/Tests/Hog/Hog.csproj @@ -0,0 +1,25 @@ + + + + + + + Exe + Hog + + + + + + + + + diff --git a/base/Applications/Tests/KPTest/KPTest.csproj b/base/Applications/Tests/KPTest/KPTest.csproj new file mode 100644 index 0000000..679c07a --- /dev/null +++ b/base/Applications/Tests/KPTest/KPTest.csproj @@ -0,0 +1,33 @@ + + + + + + + KPTest + Exe + true + true + true + + + + + + + + + + diff --git a/base/Applications/Tests/KPTest/KPTest.sg b/base/Applications/Tests/KPTest/KPTest.sg new file mode 100644 index 0000000..0a61118 --- /dev/null +++ b/base/Applications/Tests/KPTest/KPTest.sg @@ -0,0 +1,223 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: KPTest.sg +// +// Note: Tests the kernel-process boundary. +// +// Feel free to add more commands to this file. + +using System; +using System.Collections; +using System.Threading; +using Microsoft.SingSharp; +using Microsoft.Singularity; +using Microsoft.Singularity.Memory; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.V1.Services; +using Microsoft.Singularity.Stress.Contracts; + +using Microsoft.Singularity.Channels; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications { + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [BoolParameter( "help", Default=false, HelpMessage="Display Extended help message.")] + internal bool doHelp; + + [StringArrayParameter( "args", HelpMessage="arg bucket")] + internal string[] args; + + reflective internal Parameters(); + + internal int AppMain() { + return KPTest.AppMain(this); + } + } + + public class KPTest : Microsoft.Singularity.Stress.KPTestBase + { + static Hashtable! processes = new Hashtable(); // maps strings to Processes + + internal static int AppMain(Parameters! config) + { + assume config.args != null; + string[] args; + if(config.doHelp) { + Console.WriteLine("usage:"); + Console.WriteLine(" kptest command1 ... commandn"); + Console.WriteLine("where each command is one of:"); + Console.WriteLine(" print s {print s; ...remaining commands...;}"); + Console.WriteLine(" print- s {...remaining commands...; print s}"); + Console.WriteLine(" print^ s {print s; ...remaining commands...; print s}"); + Console.WriteLine(" catch s {try {...remaining commands...} catch(Exception) {print s}}"); + Console.WriteLine(" finally s {try {...remaining commands...} finally {print s}}"); + Console.WriteLine(" break {break; ...remaining commands...; break}"); + Console.WriteLine(" kernel {enter kernel; ...remaining commands...; leave kernel"); + Console.WriteLine(" frames n {make n stack frames; ...remaining commands...; free frames}"); + Console.WriteLine(" throw {throw ArgumentException}"); + Console.WriteLine(" throwstop {throw ProcessStopException} (kernel only)"); + Console.WriteLine(" delay n {for i=1 to n {compute} ...remaining commands...}"); + Console.WriteLine(" sleep n {sleep n milliseconds ...remaining commands...}"); + Console.WriteLine(" yield {yield; ...remaining commands...}"); + Console.WriteLine(" wall {block forever}"); + Console.WriteLine(" (* n ... ) {repeat n {...}; ...remaining commands...}}"); + Console.WriteLine(" (| ... ) {new thread(...); ...remaining commands...}} (process only)"); + Console.WriteLine(" (& s ... ) {new proc s(...); ...remaining commands...}} (process only)"); + Console.WriteLine(" suspend s {suspend proc s; ...remaining commands...} (process only)"); + Console.WriteLine(" resume s {resume proc s; ...remaining commands...} (process only)"); + Console.WriteLine(" stop s {stop proc s; ...remaining commands...} (process only)"); + Console.WriteLine("where s is any string and n is any nonnegative integer"); + Console.WriteLine("example: kptest print hello catch foo frames 1000 kernel finally bar throw"); + Console.WriteLine("example: kptest print 1 (& p print hi delay 100 print bye ) delay 50 stop p"); + Console.WriteLine("example: kptest 'print 1 (& p print hi delay 100 print bye ) delay 50 stop p'"); + return 0; + } + else if (config.args.Length == 1) { + // Turn a single quoted string into a list of arguments. + // Beware: this doesn't handle multiple spaces between commands. + string foo = config.args[0] ; + assert foo != null; + args = foo.Split(new char[] {' '}); + } + else args = config.args; + + Console.WriteLine("return value: {0:x}", new KPTest().Go(args, 0)); + return 0; + } + + public KPTest() + { + } + + private string[] args; + + private KPTest(String[]! args) + { + this.args = args; + } + + private void Run() + requires this.args != null; + { + Console.WriteLine("new thread running"); + Console.WriteLine("thread return value: {0:x}", Go(args, 0)); + } + + public override uint Go(string[]! args, int i) + { + if (i >= args.Length) return 0x12345678; + string arg = args[i]; + if (arg == "kernel" || arg == "_kernel") + { + ArgList* in ExHeap exArgs = null; + for(int j = args.Length - 1; j >= 0; j--) + { + exArgs = new[ExHeap] ArgList(Bitter.FromString(args[j]), exArgs); + } + + if (arg == "kernel") + { + Console.WriteLine("calling kernel"); + } + unsafe + { + uint r = Microsoft.Singularity.V1.Stress.StressDirect.KPTest((SharedHeapService.Allocation*) exArgs, i + 1); + if (arg == "kernel") + { + Console.WriteLine("returned from kernel"); + } + return r; + } + } + else if (arg == "(|") + { + int rParen = FindClosingRParen((!) args, i + 1); + string[] before = new string[rParen - (i + 1)]; + Array.Copy(args, i + 1, before, 0, before.Length); + string[] after = new string[args.Length - (rParen + 1)]; + Array.Copy(args, rParen + 1, after, 0, after.Length); + new Thread(new ThreadStart(new KPTest(before).Run)).Start(); + return Go(after, 0); + } + else if (arg == "(&") + { + string! name = (!)args[i + 1]; + int rParen = FindClosingRParen((!) args, i + 2); + string[] before = new string[rParen - (i + 2) + 1]; + before[0] = "kptest"; + Array.Copy(args, i + 2, before, 1, before.Length - 1); + string[] after = new string[args.Length - (rParen + 1)]; + Array.Copy(args, rParen + 1, after, 0, after.Length); + Process p = new Process(before); + processes[name] = p; + p.Start(); + return Go(after, 0); + } + else if (arg == "suspend" || arg == "_suspend") + { + string! name = (!)args[i + 1]; + Process! p = (!)(processes[name] as Process); + if (arg == "suspend") + { + Console.WriteLine("suspending " + name); + } + p.Suspend(false); + if (arg == "suspend") + { + Console.WriteLine("suspended " + name); + } + return Go(args, i + 2); + } + else if (arg == "resume" || arg == "_resume") + { + string! name = (!)args[i + 1]; + Process! p = (!)(processes[name] as Process); + if (arg == "resume") + { + Console.WriteLine("resuming " + name); + } + p.Resume(false); + if (arg == "resume") + { + Console.WriteLine("resumed " + name); + } + return Go(args, i + 2); + } + else if (arg == "stop" || arg == "_stop") + { + string! name = (!)args[i + 1]; + Process! p = (!)(processes[name] as Process); + if (arg == "stop") + { + Console.WriteLine("stopping " + name); + } + p.Stop(); + if (arg == "stop") + { + Console.WriteLine("stopped " + name); + } + return Go(args, i + 2); + } + else + { + return base.Go(args, i); + } + } + } +} diff --git a/base/Applications/Tests/KPTest/StressLib.cs b/base/Applications/Tests/KPTest/StressLib.cs new file mode 100644 index 0000000..1f7162d --- /dev/null +++ b/base/Applications/Tests/KPTest/StressLib.cs @@ -0,0 +1,30 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: KPTest.sg +// +// Note: Tests the kernel-process boundary. +// +// Feel free to add more commands to this file. + +using System; +using Microsoft.SingSharp; +using Microsoft.Singularity; +using Microsoft.Singularity.Stress; +using Microsoft.Singularity.Memory; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.V1.Services; +using System.Runtime.CompilerServices; + +namespace Microsoft.Singularity.Stress +{ + public class StressDirect + { + [OutsideGCDomain] + [MethodImpl(MethodImplOptions.InternalCall)] + public static extern unsafe uint KPTest(SharedHeapService.Allocation* sharedArgs, int i); + } +} diff --git a/base/Applications/Tests/Keys/Keys.csproj b/base/Applications/Tests/Keys/Keys.csproj new file mode 100644 index 0000000..3be0e1b --- /dev/null +++ b/base/Applications/Tests/Keys/Keys.csproj @@ -0,0 +1,25 @@ + + + + + + + Exe + Keys + + + + + + + + + diff --git a/base/Applications/Tests/Keys/Keys.sg b/base/Applications/Tests/Keys/Keys.sg new file mode 100644 index 0000000..edbc2bc --- /dev/null +++ b/base/Applications/Tests/Keys/Keys.sg @@ -0,0 +1,140 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Keys.sg +// +// Note: Simple Singularity test program. +// + +using Microsoft.SingSharp; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.V1.Services; + +using System; + +using Keyboard = Microsoft.Singularity.Io.Keyboard; + +namespace Microsoft.Singularity.Applications +{ + public class Keys + { + //[ShellCommand("keys", "Test keyboard")] + public static int Main(String[] args) + { + Console.WriteLine("Press a mouse button to exit."); + + KeyboardDeviceContract.Imp keyboard = OpenKeyboard("/dev/keyboard"); + if (keyboard == null) return -1; + + for (;;) { + int x; + int y; + uint key = 0; + keyboard.SendGetKey(); + switch receive + { + case keyboard.AckKey(ikey): + key = ikey; + break; + case keyboard.NakKey(): + break; + case keyboard.ChannelClosed(): + throw new Exception("Didn't get reply from Keyboard"); + } + + if (key == 0) { + Tracing.Log(Tracing.Warning, "GetKey failed."); + break; + } + if ((key & (uint)Keyboard.Qualifiers.KEY_DOWN) == 0) { + continue; + } + + if ((key & (uint)Keyboard.Qualifiers.KEY_MOUSE) != 0) { + if ((key & (uint)Keyboard.Qualifiers.MOUSE_BUTTON_ALL) != 0) { + break; + } + } + +#if DO_MOUSE + mouse.GetPosition(out x, out y); + Console.WriteLine("{0,8:x8}:{1,4},{2,4}", key, x, y); +#endif + Console.Write(key); + } + + delete keyboard; + + return 0; + } + + private static KeyboardDeviceContract.Imp:Ready + OpenKeyboardInternal(DirectoryServiceContract.Imp! nsImp, + [Claims] char[]! in ExHeap devName) + { + KeyboardDeviceContract.Exp! keyExp; + KeyboardDeviceContract.Imp! keyImp; + KeyboardDeviceContract.NewChannel(out keyImp, out keyExp); + + nsImp.SendBind(devName, keyExp); + switch receive + { + case nsImp.AckBind(): + return keyImp; + break; + case nsImp.NakBind(rejected, error): + delete rejected; + delete keyImp; + break; + case nsImp.ChannelClosed(): + throw new Exception("Didn't Keyboard.RecvAckConnect"); + delete keyImp; + break; + case nsImp.NakBindReparse(path, rest, linkFound, backExp): + assert linkFound == true; + assert rest == null; + + delete backExp; + delete keyImp; + + return OpenKeyboardInternal(nsImp, path); + break; + } + return null; + } + + public static KeyboardDeviceContract.Imp:Ready + OpenKeyboard(string! devName) + { + // get NS endpoint + DirectoryServiceContract.Imp ns = DirectoryService.NewClientEndpoint(); + + KeyboardDeviceContract.Imp imp = + OpenKeyboardInternal(ns, Bitter.FromString2(devName)); + delete ns; + + if (imp == null) { + DebugStub.Print("OpenKeyboard lookup of {0} failed.\n", __arglist(devName)); + return null; + } + + switch receive + { + case imp.Success(): + break; + case imp.ContractNotSupported(): + throw new Exception("Didn't imp.RecvAckConnect: ContractNotSupported"); + break; + case imp.ChannelClosed(): + throw new Exception("Channel closed unexpectedly"); + break; + } + return imp; + } + } +} diff --git a/base/Applications/Tests/MathTest/MathTest.cs b/base/Applications/Tests/MathTest/MathTest.cs new file mode 100644 index 0000000..5507df3 --- /dev/null +++ b/base/Applications/Tests/MathTest/MathTest.cs @@ -0,0 +1,79 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: MathTest.cs +// +using System; + +namespace Microsoft.Singularity.Applications +{ + public class MathTest + { + private static void spec_zipf_setup(int size, double Z) + { + Console.WriteLine("spec_zipf_setup size={0}",size); + for (int i = 1; i <= size; i++) { + // compute zipf values for samples 1-n. + + double d0 = 1.0 / (double)i; + double d1 = Math.Pow(d0, Z); + Console.WriteLine("pow({0,9:f6}, {1,9:f6})={2,9:f6}", d0, Z, d1); + } + } + + //[ShellCommand("mathtest", "Run simple math tests.")] + public static int Main() + { + double x1 = Math.PI / 4; + double x2 = 0.50; + + Console.WriteLine("Asin ({0,9:f6}) = {1,9:f6} : {2,9:f6}", + x1, Math.Asin(x1), 0.903339); + Console.WriteLine("Acos ({0,9:f6}) = {1,9:f6} : {2,9:f6}", + x1, Math.Acos(x1), 0.667457); + Console.WriteLine("Sin ({0,9:f6}) = {1,9:f6} : {2,9:f6}", + x1, Math.Sin(x1), 0.707107); + Console.WriteLine("Cos ({0,9:f6}) = {1,9:f6} : {2,9:f6}", + x1, Math.Cos(x1), 0.707107); + Console.WriteLine("Tan ({0,9:f6}) = {1,9:f6} : {2,9:f6}", + x1, Math.Tan(x1), 1.000000); + Console.WriteLine("Atan ({0,9:f6}) = {1,9:f6} : {2,9:f6}", + x1, Math.Atan(x1), 0.665774); + Console.WriteLine("Atan2({0,9:f6}, {1,9:f6}) = {2,9:f6} : {3,9:f6}", + x1, x2, Math.Atan2(x1, x2), 1.003885); + Console.WriteLine("Abs ({0,9:f6}) = {1,9:f6} : {2,9:f6}", + x1, Math.Abs(x1), 0.785398); + Console.WriteLine("Sqrt ({0,9:f6}) = {1,9:f6} : {2,9:f6}", + x1, Math.Sqrt(x1), 0.886227); + Console.WriteLine("Log ({0,9:f6}) = {1,9:f6} : {2,9:f6}", + x1, Math.Log(x1), -0.241564); + Console.WriteLine("Log10({0,9:f6}) = {1,9:f6} : {2,9:f6}", + x1, Math.Log10(x1), -0.104910); + Console.WriteLine("Pow ({0,9:f6}, {1,9:f6}) = {2,9:f6} : {3,9:f6}", + x1, x2, Math.Pow(x1, x2), 0.886227); + Console.WriteLine("Fmod ({0,9:f6}, {1,9:f6}) = {2,9:f6} : {3,9:f6}", + x1, x2, Math.Mod(x1, x2), 0.285398); + Console.WriteLine("Floor({0,9:f6}) = {1,9:f6} : {2,9:f6}", + x1, Math.Floor(x1), 0.000000); + Console.WriteLine("Ceil ({0,9:f6}) = {1,9:f6} : {2,9:f6}", + x1, Math.Ceiling(x1), 1.000000); + Console.WriteLine("Round({0,9:f6}) = {1,9:f6} : {2,9:f6}", + x1, Math.Round(x1), 1.000000); + Console.WriteLine("Round({0,9:f6}, {1}) = {2,9:f6} : {3,9:f6}", + (double)Math.PI, 2, Math.Round(Math.PI, 2), 3.14, 999, 99); + Console.WriteLine("Sinh ({0,9:f6}) = {1,9:f6} : {2,9:f6}", + x1, Math.Sinh(x1), 0.868671); + Console.WriteLine("Tanh ({0,9:f6}) = {1,9:f6} : {2,9:f6}", + x1, Math.Tanh(x1), 0.655794); + Console.WriteLine("Cosh ({0,9:f6}) = {1,9:f6} : {2,9:f6}", + x1, Math.Cosh(x1), 1.324609); + + spec_zipf_setup(24, 1.0); + + return 0; + } + } +} diff --git a/base/Applications/Tests/MathTest/MathTest.csproj b/base/Applications/Tests/MathTest/MathTest.csproj new file mode 100644 index 0000000..9ba6bfa --- /dev/null +++ b/base/Applications/Tests/MathTest/MathTest.csproj @@ -0,0 +1,25 @@ + + + + + + + Exe + MathTest + + + + + + + + + diff --git a/base/Applications/Tests/MonitorTest/MonitorTest.cs b/base/Applications/Tests/MonitorTest/MonitorTest.cs new file mode 100644 index 0000000..ce98728 --- /dev/null +++ b/base/Applications/Tests/MonitorTest/MonitorTest.cs @@ -0,0 +1,63 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: MonitorTest.cs +// +// Note: Some basic tests of the monitor code. +// + +using System; +using System.Threading; + +using Microsoft.Singularity.UnitTest; + +using Microsoft.Singularity.Channels; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications { + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal Parameters(); + + internal int AppMain() { + return MonitorTest.AppMain(this); + } + } + + public class MonitorTest + { + internal static int AppMain(Parameters! config) + { + for (int i = 0; i < 2; i++) { + UnitTest.Add("Many Threads PulseAll", + new UnitTest.TestDelegate(PulseAllTest.ManyThreadsTest)); + + UnitTest.Add("Few Threads Pulse", + new UnitTest.TestDelegate(PulseAllTest.FewThreadsTest)); + + UnitTest.Add("Low-density Pulse", + new UnitTest.TestDelegate(PulseTest.LowDensityTest)); + UnitTest.Add("Medium-density Pulse", + new UnitTest.TestDelegate(PulseTest.MediumDensityTest)); + UnitTest.Add("High-density Pulse", + new UnitTest.TestDelegate(PulseTest.HighDensityTest)); + } + return ((UnitTest.Run(true) == UnitTest.Result.Passed) && + Assert.Failures == 0) ? 0 : 1; + } + } +} diff --git a/base/Applications/Tests/MonitorTest/MonitorTest.csproj b/base/Applications/Tests/MonitorTest/MonitorTest.csproj new file mode 100644 index 0000000..24f633c --- /dev/null +++ b/base/Applications/Tests/MonitorTest/MonitorTest.csproj @@ -0,0 +1,36 @@ + + + + + + + MonitorTest + Exe + true + true + + + + + + + + + + + + + + diff --git a/base/Applications/Tests/MonitorTest/PulseAllTest.cs b/base/Applications/Tests/MonitorTest/PulseAllTest.cs new file mode 100644 index 0000000..3216b04 --- /dev/null +++ b/base/Applications/Tests/MonitorTest/PulseAllTest.cs @@ -0,0 +1,178 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: PulseTest.cs +// +// Note: +// + +using System; +using System.Threading; + +using Microsoft.Singularity.UnitTest; + +namespace Microsoft.Singularity.Applications +{ + /// + /// A test of Monitor.PulseAll. A collection of threads waits on + /// a single monitor for a pulse all. + /// + internal sealed class PulseAllTest + { + int waiterCount = 50; + int timeoutSeconds = 2; + + int passedBarrier = 0; + bool waiterRunning = false; + volatile bool timedOut = false; + volatile bool stop = false; + volatile int generation = 0; + + ManualResetEvent! controllerReady = new ManualResetEvent(false); + ManualResetEvent! finishedEvent = new ManualResetEvent(false); + AutoResetEvent! barrierEvent = new AutoResetEvent(false); + object! monitor = new object(); + bool []! visited; + + private static void Yield() + { +#if SINGULARITY + Thread.Yield(); +#else + Thread.Sleep(0); +#endif + } + + public void WatchdogThreadMain() + { + TimeSpan delta = TimeSpan.FromSeconds(timeoutSeconds); + + int now = this.generation; + int last = 0; + do { + last = now; + if (finishedEvent.WaitOne(delta)) { + return; + } + Yield(); + now = this.generation; + } while (last != now); + + DebugStub.Break(); + + this.timedOut = true; + } + + public void ControllerThreadMain() + { + const int iterations = 1000; + + const int YieldFudge = 50; + + // Signal worker threads to start + controllerReady.Set(); + Yield(); + + for (int i = 1; i <= iterations; i++) { + barrierEvent.WaitOne(); + // There is a potential + // race between the last thread reaching the barrier + // setting the barrierEvent and reaching the Monitor.Wait + // call. By yielding a few times we should give the + // thread enough time to get there. + for (int n = 0; n < YieldFudge; n++) + Yield(); + lock (this.monitor) { + // Reset check state + this.passedBarrier = 0; + for (int j = 0; j < visited.Length; j++) { + visited[j] = false; + } + + // Set stop flag if end is reached + this.stop = (i == iterations); + + // Wake up waiters + Monitor.PulseAll(this.monitor); + } + } + finishedEvent.Set(); + } + + public void WaiterThreadMain() + { + while (!stop) { + Monitor.Enter(this.monitor); + try { + Assert.True(waiterRunning == false, + "Two waiters have monitor."); + waiterRunning = true; + + Assert.False(this.visited[this.passedBarrier], + "Thread already reached barrier."); + this.visited[this.passedBarrier] = true; + + this.passedBarrier++; + this.generation++; + + Assert.LessOrEqual(this.passedBarrier, waiterCount, + "More waiters passed barrier than expected."); + + if (this.passedBarrier == this.waiterCount) { + barrierEvent.Set(); + } + + this.waiterRunning = false; + Monitor.Wait(this.monitor); + this.waiterRunning = true; + } + finally { + this.waiterRunning = false; + Monitor.Exit(this.monitor); + } + } + } + + public void RunTest() + { + Thread watchdog = + new Thread(new ThreadStart(WatchdogThreadMain)); + Thread controller = + new Thread(new ThreadStart(ControllerThreadMain)); + + watchdog.Start(); + controller.Start(); + + controllerReady.WaitOne(); + for (int i = 0; i < waiterCount; i++) { + Thread t = new Thread(new ThreadStart(WaiterThreadMain)); + t.Start(); + } + + while (!controller.Join(TimeSpan.FromMilliseconds(100))) { + Assert.False(this.timedOut, "Timed out!"); + } + watchdog.Join(); + } + + public PulseAllTest(int threadCount, int timeoutSeconds) + { + this.waiterCount = threadCount; + this.timeoutSeconds = timeoutSeconds; + this.visited = new bool [threadCount]; + } + + public static void FewThreadsTest() + { + (new PulseAllTest(8, 2)).RunTest(); + } + + public static void ManyThreadsTest() + { + (new PulseAllTest(50, 2)).RunTest(); + } + } +} diff --git a/base/Applications/Tests/MonitorTest/PulseTest.cs b/base/Applications/Tests/MonitorTest/PulseTest.cs new file mode 100644 index 0000000..94f4f6a --- /dev/null +++ b/base/Applications/Tests/MonitorTest/PulseTest.cs @@ -0,0 +1,211 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: PulseTest.cs +// +// Note: +// + +using System; +using System.Threading; + +using Microsoft.Singularity.UnitTest; + +namespace Microsoft.Singularity.Applications +{ + /// + /// A class for testing Monitor.Pulse. + /// + /// This class creates a group of monitors (Node class) that + /// a collection of threads then enters, spins, pulses, and exits. + /// + /// + internal sealed class PulseTest + { + internal class Node + { + volatile bool inVisit = false; + + internal void BeginVisit() + { + Monitor.Enter(this); + Assert.False(inVisit, "Node is visited by two threads"); + inVisit = true; + } + + internal void EndVisit() + { + Assert.True(inVisit, "Unpaired visit ending"); + Monitor.Pulse(this); + inVisit = false; + Monitor.Exit(this); + } + } + + internal sealed class VisitPath + { + int[]! path; + int remainLength; + int cycles; + + internal VisitPath(int pathLength) + { + this.path = new int[pathLength]; + this.remainLength = pathLength; + this.cycles = 0; + } + + internal void Initialize() + { + // This is a separate method so + // we can compile compatibly on Win32. SGC wants + // the Sing# specific NonDelayed attribute otherwise. + for (int i = 0; i < this.remainLength; i++) { + this.path[i] = i; + } + } + + internal int Pick(int randomNumber) + { + int n = randomNumber % this.remainLength; + int r = this.path[n]; + + this.remainLength--; + this.path[r] = this.path[this.remainLength]; + this.path[this.remainLength] = r; + + if (this.remainLength == 0) { + this.cycles++; + this.remainLength = this.path.Length; + } + return r; + } + + internal int Cycles { get { return this.cycles; } } + } + + private Node[]! nodes; + private readonly int threadCount; + private readonly int maxCycles; + private volatile int startedCount; + private volatile int finishedCount; + private volatile int generation; + private ManualResetEvent! finishedEvent; + + private static void Yield() + { +#if SINGULARITY + Thread.Yield(); +#else + Thread.Sleep(0); +#endif + } + + internal void VisitorThreadMain() + { + // Wait until all other threads have started + int threadNumber; + lock (this) { + threadNumber = startedCount++; + } + while (startedCount != this.threadCount) { + Yield(); + } + + Random rng = new Random(threadNumber); + VisitPath path = new VisitPath(this.nodes.Length); + path.Initialize(); + + while (path.Cycles != this.maxCycles) { + // Select a node previously unvisited in this cycle + Node/*!*/ n = /*^(!)^*/ nodes[path.Pick(rng.Next())]; + n.BeginVisit(); + + // Yield up to number of threads to give other + // threads a chance to run + int yieldCount = rng.Next(this.threadCount); + while (yieldCount-- > 0) + Yield(); + + n.EndVisit(); + // Console.Write("[{0}]", threadNumber); + this.generation++; + } + + lock (this) { + this.finishedCount++; + if (this.finishedCount == this.threadCount) { + this.finishedEvent.Set(); + } + } + } + + private void WatchdogThreadMain() + { + int last = this.generation; + for (;;) { + Thread.Sleep(TimeSpan.FromSeconds(5)); + if (this.finishedCount == this.threadCount) { + return; + } + int now = this.generation; + Assert.True(last != now, "Deadlock detected."); + last = now; + } + } + + internal PulseTest(int numberOfNodes, int numberOfThreads, int iterations) + { + this.nodes = new Node[numberOfNodes]; + this.threadCount = numberOfThreads; + this.maxCycles = iterations; + this.startedCount = 0; + this.finishedCount = 0; + this.finishedEvent = new ManualResetEvent(false); + } + + private void Initialize() + { + for (int i = 0; i < nodes.Length; i++) { + nodes[i] = new Node(); + } + } + + internal void RunTest() + { + for (int i = 0; i < this.threadCount; i++) { + (new Thread(new ThreadStart(VisitorThreadMain))).Start(); + } + Thread watchdog = new Thread(new ThreadStart(WatchdogThreadMain)); + watchdog.Start(); + + finishedEvent.WaitOne(); + watchdog.Join(); + Assert.True(Assert.Failures == 0, "Failures within threads."); + } + + internal static void LowDensityTest() + { + PulseTest p = new PulseTest(128, 17, 20); + p.Initialize(); + p.RunTest(); + } + + internal static void MediumDensityTest() + { + PulseTest p = new PulseTest(32, 32, 20); + p.Initialize(); + p.RunTest(); + } + + internal static void HighDensityTest() + { + PulseTest p = new PulseTest(4, 128, 20); + p.Initialize(); + p.RunTest(); + } + } +} diff --git a/base/Applications/Tests/Ntlm/NtlmUnitTest.csproj b/base/Applications/Tests/Ntlm/NtlmUnitTest.csproj new file mode 100644 index 0000000..0340e5b --- /dev/null +++ b/base/Applications/Tests/Ntlm/NtlmUnitTest.csproj @@ -0,0 +1,35 @@ + + + + + + {3F9845B1-E3A1-40DD-96E5-AFD900858FA4} + Exe + NtlmUnitTest + 4 + true + + + + + + + + + + + + + + + + + diff --git a/base/Applications/Tests/Ntlm/NtlmUnitTest.sg b/base/Applications/Tests/Ntlm/NtlmUnitTest.sg new file mode 100644 index 0000000..8fec4a9 --- /dev/null +++ b/base/Applications/Tests/Ntlm/NtlmUnitTest.sg @@ -0,0 +1,757 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: NtlmSupplicant.cs +// +// Note: +// +// This app is a unit test for the NTLM authentication library. It can +// be run in two modes: local, and remote. +// +// In local mode, the program runs through a hard-coded list of known +// NTLM inputs (password and challenge) and outputs (NT and LM response). +// It uses the known inputs and computes the outputs, then compares the +// known (desired) outputs and compares them with the actual, computed +// outputs. If a difference is detected, then the NTLM implementation +// is broken. +// +// In remote mode, this program uses TCP/IP to communicate with a Windows +// machine, which must be running the NtlmWinHost program. (NtlmWinHost +// lives in Singularity/Windows/UnitTests.) NtlmWinHost listens for TCP/IP +// connections from NtlmUnitTest, receives NTLM Negotiate requests, and +// performs an NTLM exchange. The user must specify a valid account name +// and password. "Valid" means that the account name and password are +// known to (or resolvable by) the Windows host machine. Typically, this +// is a test account created on the Windows machine, NOT your Corpnet +// domain credentials! +// +// +//////////////////////////////////////////////////////////////////////////////// + +using System; +using System.Runtime.InteropServices; +using System.Collections; +using System.Diagnostics; +using System.Net.IP; +using System.Net; +using System.Text; +using System.Net.Sockets; + +using Microsoft.Contracts; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +using Microsoft.Singularity.Security; +using Microsoft.SingSharp; +using Microsoft.SingSharp.Reflection; + +using System.Security.Protocols.Ntlm; + +[assembly: Transform(typeof(ApplicationResourceTransform))] + +[ConsoleCategory(HelpMessage="Runs offline BVT for NTLM authentication library", DefaultAction=true)] +internal class DefaultCommand +{ + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal DefaultCommand(); + + static void WriteLine(string! line) + { + DebugStub.WriteLine(line); + Console.WriteLine(line); + } + + static void WriteLine(string! format, params object[]! list) + { + WriteLine(String.Format(format, list)); + } + + internal int AppMain() + { + Console.WriteLine("Checking known responses:"); + + int failureCount = 0; + + foreach (NtlmKnownResponse known in KnownResponses) + { + string! line = String.Format("password: {0,-20} challenge: {1} LM response: {2} NT response: {3}", + "'" + known.Password + "'", + known.Challenge, + known.LmResponse, + known.NtResponse); + WriteLine(line); + + byte[]! known_challenge = Util.HexStringToByteArray(known.Challenge); + byte[]! known_lm_response = Util.HexStringToByteArray(known.LmResponse); + byte[]! known_nt_response = Util.HexStringToByteArray(known.NtResponse); + + byte[]! computed_lm_response = NtlmSupplicant.ComputeLmResponse(known_challenge, known.Password); + byte[]! computed_nt_response = NtlmSupplicant.ComputeNtResponse(known_challenge, known.Password); + + if (Util.CompareArraySpans(known_lm_response, computed_lm_response) != 0) { + WriteLine(" FAILURE: Computed LM response differs: " + Util.ByteArrayToString(computed_lm_response)); + failureCount++; + } + + if (Util.CompareArraySpans(known_nt_response, computed_nt_response) != 0) { + WriteLine(" FAILURE: Computed NT response differs: " + Util.ByteArrayToString(computed_lm_response)); + failureCount++; + } + } + + if (failureCount == 0) { + WriteLine("All computed responses match known good values. Test passes."); + return 0; + } else { + WriteLine("Failures: " + failureCount); + return -1; + } + } + + static NtlmKnownResponse[] KnownResponses = { + // These were generated using the @gen command, below. +new NtlmKnownResponse("2c87546b170c54bf", "Z_bE`", "16b291e268a4e19a23b36eeeb685c02260391bc2827fc05d", "43f56c81a2805383a7622fe0c170ad659b04f25dbeedd6a6"), +new NtlmKnownResponse("8fd1f7048f3dee73", "Z_bE`", "c2d6e331411a109341a9ba76d10506d03b262fcf3f473e9d", "cbc03bbe559766a6807db7b9d60c68d26a795c5a20a2a016"), +new NtlmKnownResponse("22abc82a344df2de", "Z_bE`", "931fa8a43c90dc2797f0335b8882c4f5593444cf3dc1b643", "652e822eaa467371770180fdc771d1dddff1cd902f144c74"), +new NtlmKnownResponse("c3a7fe9867b8c99e", "Z_bE`", "daa43f8730d593d7a4f6cfe542fb2e28102fa87b84365267", "0f8a1c55eda6cb21908be3d165011616a141e0d36af3e9d4"), +new NtlmKnownResponse("1b08c97f49cb7c01", "ra%Z)ZE&},t", "142b2855d2786061ab295d14e39f871473d949df16536005", "0cfc316813c5423f927fe9892ccaaa451068224648afcbeb"), +new NtlmKnownResponse("ed3c7bdf9575a770", "ra%Z)ZE&},t", "c1f1055ae66caf6eecc70b191b006536ed7e1337abafe85f", "d2149ecb23779f255774559bc6b09a40da0b67f764a7fc61"), +new NtlmKnownResponse("0dbc57d708580cb0", "ra%Z)ZE&},t", "ba09f4b51d59efba03e931788c5914dc06fc578b9e85d090", "812298742928dcd6711b4c932108897528e45dbca9463a40"), +new NtlmKnownResponse("89dfd5090d601936", "ra%Z)ZE&},t", "ce82f6b3341f1cdd425bdf44953bf83452fd0efa25360264", "e99a1428fd64d46cb9e771bba3aaf315f5fb8c8780cd37a6"), +new NtlmKnownResponse("4f9c3bc7b0ba63d4", "$gdqN", "4b21b010c976506aecd6da792faa4e6efd7083e5b953de5f", "bbec0eb714b01e4146dcc538215d2ebe011d0f209b2da2d3"), +new NtlmKnownResponse("7928722e5955a64b", "$gdqN", "01e1b5ef4bfcf849521454e5b5d2942b181951c33efe3473", "2f763a9ee207803bad0011081a3d25332b044822b2cf00a1"), +new NtlmKnownResponse("dec3fb19f56af673", "$gdqN", "ff555fc0302beb74f637ccbe6e17e8ce65a3861552512d6c", "c369bf569205073d7aecdb02df6cf3977e9dda975f5bbce0"), +new NtlmKnownResponse("f48d2345b489b2eb", "$gdqN", "40a4e20fa00d72a301f856a658ef0ff642b2d89a633567ef", "f9c74c29211779384b699da935e5570bdb4ae6d4457767df"), +new NtlmKnownResponse("b565ac97df07c48f", "THdY7]>;", "41fa9c2d34c75683135620def7a5e3c3aeb7320d21bd6148", "ebe810de662ab1a09d5b25f4f671ec1be89710b874c3185f"), +new NtlmKnownResponse("df2dffc0c489e4a6", "THdY7]>;", "8a1e615c5b0d0a1de96094b5fa165c7461aa496f0cc25267", "00620bb34513503d449999a55e587b84ce87fd9a7b972549"), +new NtlmKnownResponse("c8d323961e1fef75", "THdY7]>;", "6a99cd29b2bfdbf78d594aafca00a612408de2fd0de1065c", "c8b651d08eb804c63ebd18d26f5b70522b6a0f38936771ee"), +new NtlmKnownResponse("869bcae8ebaf9d1a", "THdY7]>;", "5efdb0fcac134c8a7db9a5716c923d6414439975052947ab", "259fee21ae873b1b5316a8bac744ebc361a9b08e20287d5e"), +new NtlmKnownResponse("d55cb32bcd058815", "k7!;p'QCb", "151a0d8ee9d3c57f4e150caf18f0b9fcfff69d67e5ea5cf8", "d09d2158bf15e85bde1cc2972bb3439cdff15cab1c460d5c"), +new NtlmKnownResponse("d36d84bb2d967536", "k7!;p'QCb", "96d5a808abdfe8cc19c9e8623af7f11208d176d5190c0fa9", "5f541049ac3a839126da2321d0109d301e3a4513fdb98689"), +new NtlmKnownResponse("10433cdba4308fe4", "k7!;p'QCb", "d6b4d9da498c332f3be34e4ad3d6559ad606c4d39573258f", "1d2020a20240db913bf8d7722ca208eb08c11dcbd1e1158e"), +new NtlmKnownResponse("17f649df5cecbe9d", "k7!;p'QCb", "b25e6ab956567240b86916024c7d5b7a047ef706f1549245", "e2ca8cd6f3d54aabc961552da96b9c575fb60de8a72ccde7"), +new NtlmKnownResponse("cec55fd6db3096ed", "F;VgA", "b18e9cc93374068a20957c5c8b72be0fd8fa5a0f1c16caf2", "9e12c04257e01bd265bd587967ce27b77e7ac6426b0be1f0"), +new NtlmKnownResponse("9fa98f13cad14983", "F;VgA", "a5578f61bdfc14b353754c81cff647364605146c9756d3ea", "64e796cbceb4fc5514370b4aa7b40cfc8c9ffb63acb78cca"), +new NtlmKnownResponse("11a5cdce13d6bba8", "F;VgA", "fd7bc9bcf082d0afdd7894fe530bf59e2911a2297095f7e3", "49f4ed6fe661adaab06b235bb119da63e9f0d2c15d4e0703"), +new NtlmKnownResponse("b8e6aee684c54ce2", "F;VgA", "f5234fdcdf683d4a11b0379a36dec631566b7a0ec22dec60", "dffd5accafddebcb55dffd0662a57eef238aadea67ef96c8"), +new NtlmKnownResponse("4e2956a0504822ed", "bKKMk?B", "451ada0c60f1e1b397463a1784349ad93b46071e6d38acce", "7519f4aac3c0ad7bf26d9a482712efddceeb2fec4ac3d049"), +new NtlmKnownResponse("54b356a4c5f447f7", "bKKMk?B", "cabbf9c6952bf1fad2b6347c371613cd0be114a6d8677f1c", "606b433725d633065d1cb883cef1f88c3e95af1a75bd5b28"), +new NtlmKnownResponse("0ab71df482af69da", "bKKMk?B", "913b755617905bd71d0fa0db6e6ed6c77bc601cb4ac420b1", "488537a0be68c967ba7641c84675789253f3fec251f09b78"), +new NtlmKnownResponse("5dac9f155cd20743", "bKKMk?B", "68a4c94dab62058e1eb00f473a379130ae9339dcc9cd3a1e", "90e0baad7052eb4a4e8be6afed9a0e3fb38ea2d6c366c546"), +new NtlmKnownResponse("70c4c091d16ea71c", "HOvO)@", "0756c8011d61e60e483ada98e28668833e60e0f530acc1dd", "5f95ae24a78bad77dda82ae72e25d09feb8a958f3941de0f"), +new NtlmKnownResponse("7f6d7d6cc5b060db", "HOvO)@", "2402df78a95018e8db8fc9dae83acb8a7add3846aec0cd32", "e021108fe5b8cc86d1244b2f5dc8a98b4a7bd82a1c11f0a8"), +new NtlmKnownResponse("9ec07c43a3a80c91", "HOvO)@", "993145b5aa6197cbc03b0652d41b43b4f03f2a446cb846a5", "5690852bdf3e17719632dcaee3002b408e531232061e8681"), +new NtlmKnownResponse("82ab135456745d77", "HOvO)@", "a3c8bd4330a288d41e4da989145855192fde833ce7e1fea4", "a7d72d0c0c604a0062fcd646bd1fd47cedb9bfa0e6c95ffb"), + + }; +} + +[ConsoleCategory(Action="gen", HelpMessage="Generates a bunch of random hashes and passwords, and computes and displays the NT and LM responses.")] +internal class GenerateCommand +{ + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [LongParameter("count", Mandatory=false, Default=8, HelpMessage="The number of hashes to generate.")] + public long IterationCount; + + reflective internal GenerateCommand(); + + internal int AppMain() + { + StringBuilder buf = new StringBuilder(); + Random rand = new Random(); + + Console.WriteLine("NtlmKnownResponse[] KnownResponses = {"); + + for (int i = 0; i < this.IterationCount; i++) + { + buf.Length = 0; + + int pwlength = 4 + rand.Next(8); + for (int j = 0; j < pwlength; j++) { + char c = (char)(rand.Next(32, 126)); + if (c == '\\' || c == '"') + c = '?'; + buf.Append(c); + } + + string! password = buf.ToString(); + + // Use the same password with 4 different challenges. + + for (int j = 0; j < 4; j++) { + byte[]! challenge = new byte[8]; + rand.NextBytes(challenge); + + byte[]! lm_response = NtlmSupplicant.ComputeLmResponse(challenge, password); + byte[]! nt_response = NtlmSupplicant.ComputeNtResponse(challenge, password); + + string! line = String.Format("new NtlmKnownResponse(\"{0}\", \"{1}\", \"{2}\", \"{3}\"),", + Util.ByteArrayToString(challenge), + EscapeString(password), + Util.ByteArrayToString(lm_response), + Util.ByteArrayToString(nt_response)); + + Console.WriteLine(line); + DebugStub.WriteLine(line); + } + } + Console.WriteLine("};"); + + return 0; + } + + static string! EscapeString(string! str) + { + return str.Replace(@"\", @"\\"); + } +} + + + +struct NtlmKnownResponse +{ + public NtlmKnownResponse(string! challenge, string! password, string! lm_response, string! nt_response) + { + this.Challenge = challenge; + this.Password = password; + this.NtResponse = nt_response; + this.LmResponse = lm_response; + } + + public string! Challenge; + public string! Password; + public string! NtResponse; + public string! LmResponse; +} + + + +class Util +{ + public static byte[]! HexStringToByteArray(string! str) + { + if ((str.Length % 2) != 0) + throw new Exception("Input string cannot be odd in length."); + + byte[]! result = new byte[str.Length / 2]; + for (int i = 0; i < result.Length; i++) + { + byte high = CharToHex(str[i * 2]); + byte low = CharToHex(str[i * 2 + 1]); + result[i] = (byte)((high << 4) | low); + } + + return result; + } + + static byte CharToHex(char c) + { + if (c >= '0' && c <= '9') + return (byte)(c - '0'); + if (c >= 'a' && c <= 'f') + return (byte)(c - 'a' + 10); + if (c >= 'A' && c <= 'F') + return (byte)(c - 'A' + 10); + throw new ArgumentException("Invalid hex char"); + } + + public static string! ByteArrayToString(byte[]! buffer) + { + return ByteArrayToString(buffer, 0, buffer.Length); + } + + const string HexDigits = "0123456789abcdef"; + + public static string! ByteArrayToString(byte[]! buffer, int index, int length) + { + StringBuilder sb = new StringBuilder(length * 2); + for (int i = 0; i < length; i++) + { + byte b = buffer[index + i]; + sb.Append(HexDigits[b >> 4]); + sb.Append(HexDigits[b & 0xf]); + } + return sb.ToString(); + } + + public static void ShowException(Exception! chain) + { + Exception current = chain; + while (current != null) + { + Console.WriteLine("{0}: {1}", current.GetType().FullName, current.Message); + current = current.InnerException; + } + } + + public static int CompareArraySpans(byte[]! array1, byte[]! array2) + { + return CompareArraySpans(array1, 0, array2, 0, array1.Length); + } + + public static int CompareArraySpans(byte[]! array1, int offset1, byte[]! array2, int offset2, int length) + { + for (int i = 0; i < length; i++) + { + byte element1 = array1[offset1 + i]; + byte element2 = array2[offset2 + i]; + if (element1 < element2) + return -1; + if (element1 > element2) + return 1; + } + + return 0; + } + +} + +[ConsoleCategory(Action="remote", HelpMessage="Attempts to connect to a remote Windows host (running NtlmTestServer.exe) and authenticates using NTLM.")] +internal class RemoteAuthTestCommand +{ + reflective internal RemoteAuthTestCommand(); + + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [StringParameter("server", Mandatory=true, HelpMessage="The remote server name or IP address.")] + public string ServerName; + + [StringParameter("user", Mandatory=true, HelpMessage="The [domain\\]username to use.")] + public string UserName; + + [StringParameter("password", Mandatory=true, HelpMessage="The password to use.", Default="Z@n%zilNaga")] + public string Password; + + [LongParameter("count", Mandatory=false, Default=1, HelpMessage="The number of iterations to perform.")] + public long IterationCount; + + [StringParameter("hostdomain", Mandatory=false, Default="WORKGROUP", HelpMessage="Specifies the domain name of the client computer. Default is WORKGROUP.")] + public string ClientMachineDomainName; + + [StringParameter("workstation", Mandatory=false, Default="SINGULARITY", HelpMessage="Specifies the name of the local client machine. Default is SINGULARITY.")] + public string Workstation; + + internal int AppMain() + { + // Split the username into domain\username, if the user has specified domain name. + string! username = this.UserName; + string! domain; + int index = username.IndexOf('\\'); + if (index != -1) { + domain = username.Substring(0, index); + username = username.Substring(index + 1); + } else { + domain = "."; + } + + string! password = this.Password; + + // First, connect to BVT test server. + // The sole purpose of the server is to test NTLMSSP messages. + + + try { + // Bartok is failing on Dns.GetLocalHostAddresses + /* + IPHostEntry! he = (!)Dns.GetHostByName(this.ServerName); + IPAddress[]! addresses = (!)he.AddressList; + */ + IPv4 addr = IPv4.Parse(this.ServerName); + IPAddress[]! addresses = { new IPAddress(addr) }; + + if (addresses.Length == 0) { + Console.WriteLine("Resolution failed; no address."); + return -1; + } + + using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + // -XXX- Work around a bug in NetStack regarding quick reuse of TCP tuples + Random rand = new Random(); + IPEndPoint local = new IPEndPoint(IPAddress.Any, 1000 + rand.Next(1000)); + socket.Bind(local); + + bool connected = false; + + foreach (IPAddress address_null in addresses) + { + IPAddress! address = (!)address_null; + Console.WriteLine("Connecting: " + address.ToString()); + IPEndPoint ep = new IPEndPoint(address, NtlmUnitTestProtocol.TcpPort); + + try { + socket.Connect(ep); + Console.WriteLine("Connected."); + connected = true; + } catch(Exception ex) { + Console.WriteLine("Connection failed."); + Util.ShowException(ex); + connected = false; + } + + if (connected) + break; + } + + if (!connected) { + Console.WriteLine("Failed to connect to server."); + return -1; + } + + + for (int iteration = 0; iteration < IterationCount; iteration++) { + if (IterationCount > 1) + Console.WriteLine("[Iteration {0}/{1}]", iteration, IterationCount.ToString()); + + try { + + Console.WriteLine(" Sending NEGOTIATE"); + + byte[]! negotiate = NtlmSupplicant.GetNegotiate( + NtlmNegotiateFlags.None, + this.ClientMachineDomainName, + this.Workstation); + + NtlmUnitTestProtocol.SendMessage(socket, TestMessageType.Negotiate, negotiate); + + Console.WriteLine(" Waiting for CHALLENGE"); + + byte[]! challenge = NtlmUnitTestProtocol.ReceiveExpectedMessage(socket, TestMessageType.Challenge); + + byte[]! response = NtlmSupplicant.GetResponse( + challenge, + domain, + username, + this.Workstation, + password); + + Console.WriteLine(" Sending RESPONSE"); + + NtlmUnitTestProtocol.SendMessage(socket, TestMessageType.Response, response); + + Console.WriteLine(" Waiting RESULT"); + + byte[]! resultBuffer = NtlmUnitTestProtocol.ReceiveExpectedMessage(socket, TestMessageType.Result); + + Console.WriteLine(" Received RESULT:"); + ref ResultMessage result = ref resultBuffer[0]; + string! resulttext = Encoding.Unicode.GetString(resultBuffer, sizeof(ResultMessage), resultBuffer.Length - sizeof(ResultMessage)); + + if (result.Succeeded != 0) { + Console.WriteLine(" Succeeded = TRUE"); + } else { + Console.WriteLine(" Succeeded = FALSE"); + } + Console.WriteLine(" Message: " + resulttext); + + } catch(Exception ex) { + Console.WriteLine("Exception occurred during test."); + Util.ShowException(ex); + } + } + + } + + return 0; + } catch(Exception ex) { + Console.WriteLine("Exception occurred during test."); + Util.ShowException(ex); + return -1; + } + + + } +} + +[ConsoleCategory(Action="remote-cm", HelpMessage="Attempts to connect to a remote Windows host (running NtlmTestServer.exe) and authenticates using NTLM via the Credentials Manager service.")] +internal class RemoteAuthTestCredMgrCommand +{ + reflective internal RemoteAuthTestCredMgrCommand(); + + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [StringParameter("server", Mandatory=false, HelpMessage="The remote server name or IP address.")] + public string ServerName; + + [StringParameter("credentials", Mandatory=true, HelpMessage="The credentials to use, such as [domain\\]user.")] + public string CredentialsName; + + [StringParameter("tag", Mandatory=false, HelpMessage="The credentials tag, if necessary.")] + public string CredentialsTag; + + [LongParameter("count", Mandatory=false, Default=1, HelpMessage="The number of iterations to perform.")] + public long IterationCount; + + internal int AppMain() + { + // First, connect to BVT test server. + // The sole purpose of the server is to test NTLMSSP messages. + + string! credentialsName = this.CredentialsName; + string! credentialsTag = this.CredentialsTag != null ? this.CredentialsTag : ""; + + try { + // Bartok is failing on Dns.GetLocalHostAddresses + /* + IPHostEntry! he = (!)Dns.GetHostByName(this.ServerName); + IPAddress[]! addresses = (!)he.AddressList; + */ + IPv4 addr = IPv4.Parse(this.ServerName); + IPAddress[]! addresses = { new IPAddress(addr) }; + + if (addresses.Length == 0) { + Console.WriteLine("Resolution failed; no address."); + return -1; + } + + using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + // -XXX- Work around a bug in NetStack regarding quick reuse of TCP tuples + Random rand = new Random(); + IPEndPoint local = new IPEndPoint(IPAddress.Any, 1000 + rand.Next(1000)); + socket.Bind(local); + + bool connected = false; + + foreach (IPAddress address_null in addresses) + { + IPAddress! address = (!)address_null; + Console.WriteLine("Connecting: " + address.ToString()); + IPEndPoint ep = new IPEndPoint(address, NtlmUnitTestProtocol.TcpPort); + + try { + socket.Connect(ep); + Console.WriteLine("Connected."); + connected = true; + } catch(Exception ex) { + Console.WriteLine("Connection failed."); + Util.ShowException(ex); + connected = false; + } + + if (connected) + break; + } + + if (!connected) { + Console.WriteLine("Failed to connect to server."); + return -1; + } + + + for (int iteration = 0; iteration < IterationCount; iteration++) { + if (IterationCount > 1) + Console.WriteLine("[Iteration {0}/{1}]", iteration, IterationCount.ToString()); + + try { + + Console.WriteLine("Acquiring security context"); + GssSupplicantContract.Imp! supplicant; + GssSupplicantContract.Exp! supplicant_exp; + GssSupplicantContract.NewChannel(out supplicant, out supplicant_exp); + + CredentialsManager.CreateSupplicant( + AuthenticationProtocolNames.Ntlm, + credentialsName, + credentialsTag, + supplicant_exp); + try { + + Console.WriteLine(" Getting NEGOTIATE from security context"); + byte[]! negotiate; + switch receive { + case supplicant.FirstToken(token): + // Console.WriteLine(" Received first token from security context"); + negotiate = Bitter.ToByteArray(token); + delete token; + break; + + case supplicant.NeedFirstToken(): + throw new Exception("Received unexpected token from security context (NeedFirstToken)"); + } + + Console.WriteLine(" Sending NEGOTIATE"); + + NtlmUnitTestProtocol.SendMessage(socket, TestMessageType.Negotiate, negotiate); + + Console.WriteLine(" Waiting for CHALLENGE"); + + byte[]! challenge = NtlmUnitTestProtocol.ReceiveExpectedMessage(socket, TestMessageType.Challenge); + + Console.WriteLine(" Sending challenge to security context"); + supplicant.SendAcceptToken(Bitter.FromByteArray(challenge)); + + Console.WriteLine(" Waiting for response from security context"); + + byte[]! response; + switch receive { + case supplicant.CompleteWithToken(token): + // Console.WriteLine(" Received token from security context, and authentication is complete"); + response = Bitter.ToByteArray(token); + delete token; + break; + + case supplicant.Complete(): + throw new Exception("Security context returned unexpected message (Complete)"); + + case supplicant.ContinueNeeded(token): + delete token; + throw new Exception("Security context returned unexpected message(ContinueNeeded)"); + + case supplicant.AuthenticationFailed(error): + throw new Exception("Security context returned unexpected message (AuthenticationFailed): " + CredentialsManager.GssErrorCodeToString(error)); + } + + Console.WriteLine(" Sending RESPONSE"); + + NtlmUnitTestProtocol.SendMessage(socket, TestMessageType.Response, response); + + Console.WriteLine(" Waiting RESULT"); + + byte[]! resultBuffer = NtlmUnitTestProtocol.ReceiveExpectedMessage(socket, TestMessageType.Result); + + Console.WriteLine(" Received RESULT:"); + ref ResultMessage result = ref resultBuffer[0]; + string! resulttext = Encoding.Unicode.GetString(resultBuffer, sizeof(ResultMessage), resultBuffer.Length - sizeof(ResultMessage)); + + if (result.Succeeded != 0) { + Console.WriteLine(" Succeeded = TRUE"); + } else { + Console.WriteLine(" Succeeded = FALSE"); + } + Console.WriteLine(" Message: " + resulttext); + + } finally { + delete supplicant; + } + + } catch(Exception ex) { + Console.WriteLine("Exception occurred during test."); + Util.ShowException(ex); + } + } + + } + + return 0; + } catch(Exception ex) { + Console.WriteLine("Exception occurred during test."); + Util.ShowException(ex); + return -1; + } + + + } +} + +class NtlmUnitTestProtocol +{ + public const int TcpPort = 720; + + public static void SendMessage(Socket! socket, TestMessageType type, byte[]! payload) + { + byte[]! headerBuffer = new byte[sizeof(TestMessageHeader)]; + ref TestMessageHeader header = ref headerBuffer[0]; + header.TotalLength = (uint)(sizeof(TestMessageHeader) + payload.Length); + header.MessageType = (uint)type; + + socket.Send(headerBuffer); + + socket.Send(payload); + } + + public static byte[]! ReceiveExpectedMessage(Socket! socket, TestMessageType type) + { + TestMessageType actualType; + byte[]! msg = ReceiveMessage(socket, out actualType); + if (actualType != type) { + Console.WriteLine("Received message, but its type is not the expected type!"); + Console.WriteLine("Received type {0}, wanted type {1}", actualType, type); + throw new Exception("Invalid message received."); + } + return msg; + } + + public static byte[]! ReceiveMessage(Socket! socket, out TestMessageType type) + { + byte[]! headerBuffer = new byte[sizeof(TestMessageHeader)]; + + int length = socket.Receive(headerBuffer, sizeof(TestMessageHeader), SocketFlags.None); + if (length == 0) { + throw new Exception("Server has closed socket."); + } + + if (length < sizeof(TestMessageHeader)) { + throw new Exception("Received short data from server."); + } + ref TestMessageHeader header = ref headerBuffer[0]; + + if (header.TotalLength < sizeof(TestMessageHeader)) { + throw new Exception("Received invalid header from server (length is too short)"); + } + + if (header.TotalLength > 0x10000) { + throw new Exception("Received excessively large message from server."); + } + + int bodyLength = (int)(header.TotalLength - sizeof(TestMessageHeader)); + byte[]! body = new byte[bodyLength]; + + length = socket.Receive(body, bodyLength, SocketFlags.None); + if (length == 0) + throw new Exception("Server has closed socket."); + + if (length < bodyLength) + throw new Exception("Received short data (payload) from server."); + + type = (TestMessageType)header.MessageType; + return body; + } +} + +enum TestMessageType +{ + Negotiate = 1, + Challenge = 2, + Response = 3, + Result = 4, +} + +[StructLayout(LayoutKind.Sequential)] +pointerfree struct ResultMessage +{ + public int Succeeded; + // unicode string of error follows, no nul terminator +} + +[StructLayout(LayoutKind.Sequential)] +pointerfree struct TestMessageHeader +{ + public uint TotalLength; + public uint MessageType; +} + diff --git a/base/Applications/Tests/Null/Null.cs b/base/Applications/Tests/Null/Null.cs new file mode 100644 index 0000000..66a5507 --- /dev/null +++ b/base/Applications/Tests/Null/Null.cs @@ -0,0 +1,49 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Null.cs +// +// Note: Simple Singularity test program. +// +using System; +using Microsoft.Singularity.V1.Services; + +using Microsoft.Singularity.Channels; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications { + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal Parameters(); + + internal int AppMain() { + return Null.AppMain(this); + } + } + public class Null + { + //[ShellCommand("null", "Test null reference access")] + internal static int AppMain(Parameters! config) + { + DebugStub.Print("Calling null.ToString\n"); + Object obj = null; + String s = obj.ToString(); + DebugStub.Print("Output: " + s); + return 0; + } + } +} diff --git a/base/Applications/Tests/Null/Null.csproj b/base/Applications/Tests/Null/Null.csproj new file mode 100644 index 0000000..7c38cae --- /dev/null +++ b/base/Applications/Tests/Null/Null.csproj @@ -0,0 +1,26 @@ + + + + + + + Exe + Null + true + + + + + + + + + diff --git a/base/Applications/Tests/Recursion/Recursion.cs b/base/Applications/Tests/Recursion/Recursion.cs new file mode 100644 index 0000000..a899560 --- /dev/null +++ b/base/Applications/Tests/Recursion/Recursion.cs @@ -0,0 +1,67 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Recursion.cs +// +// Note: Simple Singularity test program. +// +using System; +using System.Threading; + +using Microsoft.Singularity.Channels; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications { + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal Parameters(); + + internal int AppMain() { + return Recursion.AppMain(this); + } + } + public class Recursion + { + public static void RecursiveMethod(int i) + { + if (i > 0) { + if ((i % 10) == 0) { + Console.WriteLine("Down: {0}", i); + } + + RecursiveMethod(i - 1); + + if ((i % 10) == 0) { + Console.WriteLine("Up: {0}", i); + } + } + } + + public static void RecursiveThreadMethod() + { + RecursiveMethod(500); + } + + //[ShellCommand("recur", "Run recursive thread demo")] + internal static int AppMain(Parameters! config) + { + Thread t1 = new Thread(new ThreadStart(RecursiveThreadMethod)); + t1.Start(); + return 0; + } + } +} diff --git a/base/Applications/Tests/Recursion/Recursion.csproj b/base/Applications/Tests/Recursion/Recursion.csproj new file mode 100644 index 0000000..bac2607 --- /dev/null +++ b/base/Applications/Tests/Recursion/Recursion.csproj @@ -0,0 +1,25 @@ + + + + + + + Exe + Recursion + + + + + + + + + diff --git a/base/Applications/Tests/SDSTest/SDSTest.csproj b/base/Applications/Tests/SDSTest/SDSTest.csproj new file mode 100644 index 0000000..469edf6 --- /dev/null +++ b/base/Applications/Tests/SDSTest/SDSTest.csproj @@ -0,0 +1,35 @@ + + + + + + + SDSTest + Exe + true + true + + + + + + + + + + + + + diff --git a/base/Applications/Tests/SDSTest/SDSTest.sg b/base/Applications/Tests/SDSTest/SDSTest.sg new file mode 100644 index 0000000..f9c0355 --- /dev/null +++ b/base/Applications/Tests/SDSTest/SDSTest.sg @@ -0,0 +1,566 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: SDSTest.sg +// +// Note: +// + +using System; +using System.Threading; +using Microsoft.Singularity; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Security; +using Microsoft.Singularity.V1.Services; +using Microsoft.SingSharp; +using Microsoft.SingSharp.Runtime; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Configuration; + +using Microsoft.Contracts; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Io; + +[assembly: Transform(typeof(ApplicationResourceTransform))] +[assembly: ApplicationPublisherAttribute("singularity.microsoft.com")] +[assembly: AssertPrivilegeAttribute("$register-privilege.localhost")] + +namespace Microsoft.Singularity.Applications +{ + [ConsoleCategory(HelpMessage="Test SIP-based Directory Service", DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [Endpoint] + public readonly TRef nsRef; + + [StringParameter( "mountPoint", Mandatory=true, Position=0, HelpMessage="Location of dsp to test")] + internal string mountPoint; + + [BoolParameter( "debug", Default=false, HelpMessage="Send results to debugger")] + internal bool printDebug; + + reflective internal Parameters(); + + internal int AppMain() { + return DirectoryMain.AppMain(this); + } + } + + + public contract Dummy : ServiceContract + { + out message Garbage(); + + override state Start: one + { + Garbage! -> End; + } + state End: one {} + } + + public class DirectoryServiceTests + { + public int passCount; + public int failCount; + private bool nakLoaded; + private bool dspLoaded; + private bool doDebug; + + public DirectoryServiceTests (bool nakLoaded, bool dspLoaded, bool doDebug) + { + failCount = 0; + passCount = 0; + this.nakLoaded = nakLoaded; + this.dspLoaded= dspLoaded; + this.doDebug = doDebug; + } + + public void CheckError( string! verb, string path, ErrorCode expected, ErrorCode actual, bool ok) + { if (ok){ + //Console.WriteLine("{0} on {1} was successful.", verb, path); + } + if (expected != actual) { + failCount++; + string s = String.Format("FAIL: {0} on {1}. expected={2}, actual={3}. ok={4}", + verb, + path, + SdsUtils.ErrorCodeToString(expected), + SdsUtils.ErrorCodeToString(actual), + ok ? "true" : "false" + ); + Console.WriteLine(s); + if (doDebug) DebugStub.WriteLine(s); + //DebugStub.Break(); + } + else { + passCount++; + string s = String.Format("PASS: {0} on {1} ({2}) ok={3}.", + verb, + path, + SdsUtils.ErrorCodeToString(expected), + ok ? "true" : "false" + ); + Console.WriteLine(s); + if (doDebug) DebugStub.WriteLine(s); + } + } + + public void CheckError( string! verb, string path, NodeType expected, NodeType actual, bool ok) + { if (ok){ + //Console.WriteLine("{0} on {1} was successful.", verb, path); + } + if (expected != actual) { + failCount++; + Console.WriteLine("FAIL: {0} on {1}. expected={2}, actual={3}. ok={4}", + verb, + path, + SdsUtils.NodeTypeToString(expected), + SdsUtils.NodeTypeToString(actual), + ok ? "true" : "false" + ); + } + else { + passCount++; + Console.WriteLine("PASS: {0} on {1} ({2}) ok={3}.", + verb, + path, + SdsUtils.NodeTypeToString(expected), + ok ? "true" : "false" + ); + } + } + + public bool DoCreateDirectory(DirectoryServiceContract.Imp! ds, string! path, ErrorCode expected) + { + ErrorCode errorOut; + bool ok = SdsUtils.CreateDirectory(path, ds, out errorOut); + CheckError("CreateDirectory", path, expected, errorOut, ok); + return ok; + } + + public void DoDeleteDirectory(DirectoryServiceContract.Imp! ds, string! path, ErrorCode expected) + { + ErrorCode errorOut; + bool ok = SdsUtils.DeleteDirectory(path, ds, out errorOut); + CheckError("DeleteDirectory", path, expected, errorOut, ok); + } + + public void DoCreateLink(DirectoryServiceContract.Imp! ds, string! path, string! value, ErrorCode expected) + { + ErrorCode errorOut; + bool ok = SdsUtils.CreateLink(path, value, ds, out errorOut); + CheckError("CreateLink", path, expected, errorOut, ok); + } + + public void DoGetLink(DirectoryServiceContract.Imp! ds, string! path, string expectedValue, ErrorCode expected) + { + ErrorCode errorOut; + string linkValue; + bool ok = SdsUtils.GetLinkValue(path, ds, out linkValue, out errorOut); + CheckError("GetLinkValue", path, expected, errorOut, ok); + if (ok) { + if (expectedValue != linkValue){ + Console.WriteLine(" expected({0}) got({1})", expectedValue, linkValue); + } + } + } + + public bool DoBind(DirectoryServiceContract.Imp! ds, string! path, + [Claims]ServiceContract.Exp! exp, ErrorCode expected) + { + ErrorCode errorOut; + string linkValue; + bool ok = SdsUtils.Bind(path, ds, exp, out errorOut); + CheckError("Bind", path, expected, errorOut, ok); + return ok; + } + + //simulate FileOpen in FsUtils + public bool DoBind(string! path, + [Claims]ServiceContract.Exp! exp, ErrorCode expected) + { + + DirectoryServiceContract.Imp! ds = DirectoryService.NewClientEndpoint(); + ErrorCode errorOut; + string linkValue; + bool ok = SdsUtils.Bind(path, ds, exp, out errorOut); + CheckError("Bind", path, expected, errorOut, ok); + delete ds; + return ok; + } + + public void DoDeleteLink(DirectoryServiceContract.Imp! ds, string! path, ErrorCode expected) + { + ErrorCode errorOut; + bool ok = SdsUtils.DeleteLink(path, ds, out errorOut); + CheckError("DeleteLink", path, expected, errorOut, ok); + } + + public void DoRegister(DirectoryServiceContract.Imp! ds, + string! path, + [Claims] ServiceProviderContract.Imp! service, + ErrorCode expected) + { + ErrorCode errorOut; + bool ok = SdsUtils.Register(path, ds, service, out errorOut); + CheckError("Register", path, expected, errorOut, ok); + } + + public void DoDeregister(DirectoryServiceContract.Imp! ds, string! path, ErrorCode expected) + { + ErrorCode errorOut; + ServiceProviderContract.Imp:Start service; + + bool ok = SdsUtils.Deregister(path, ds, out service, out errorOut); + CheckError("Deregister", path, expected, errorOut, ok); + delete service; + } + + public void DoGetAttributes(DirectoryServiceContract.Imp! ds, + string! path, + ErrorCode expected, + NodeType expectedNodeType) + { + ErrorCode errorOut; + long length; + NodeType nodeType; + + bool ok = SdsUtils.GetAttributes(path, ds, out length, out nodeType, out errorOut); + CheckError("GetAttributes", path, expectedNodeType, nodeType, ok); + CheckError("GetAttributes", path, expected, errorOut, ok); + } + + public void AttributesTests(DirectoryServiceContract.Imp! ds) + { + DoCreateDirectory(ds, "/d1", ErrorCode.NoError); + DoCreateDirectory(ds, "/d2", ErrorCode.NoError); + DoCreateLink(ds, "/d1/Link1", "/d2", ErrorCode.NoError); + DoCreateDirectory(ds, "/d1/Link1/d2", ErrorCode.NoError); + + DoGetAttributes(ds, "/d1", ErrorCode.NoError, NodeType.Directory); + DoGetAttributes(ds, "/d1/Link1", ErrorCode.NoError, NodeType.SymLink); + DoGetAttributes(ds, "/init/testpe/testpe.x86", ErrorCode.NoError, NodeType.IoMemory); + DoGetAttributes(ds, "/stress", ErrorCode.NoError, NodeType.ServiceProvider); + DoGetAttributes(ds, "/d1/Link1/d2", ErrorCode.NoError, NodeType.Directory); + DoGetAttributes(ds, "/d1/garbage", ErrorCode.NotFound, NodeType.BadNode); + + DoDeleteLink(ds, "/d1/Link1",ErrorCode.NoError); + DoDeleteDirectory(ds, "/d1", ErrorCode.NoError); + DoDeleteDirectory(ds, "/d2/d2", ErrorCode.NoError); + DoDeleteDirectory(ds, "/d2", ErrorCode.NoError); + } + + public void ProviderTests(DirectoryServiceContract.Imp! ds) + { + + ServiceProviderContract.Imp! c1; + ServiceProviderContract.Exp! s1; + ServiceProviderContract.NewChannel(out c1, out s1); + + ServiceProviderContract.Imp! c2; + ServiceProviderContract.Exp! s2; + ServiceProviderContract.NewChannel(out c2, out s2); + + ServiceProviderContract.Imp! c3; + ServiceProviderContract.Exp! s3; + ServiceProviderContract.NewChannel(out c3, out s3); + + DoRegister(ds, "/dev/sp1", c1, ErrorCode.NoError); + DoRegister(ds, "/dev/sp1", c2, ErrorCode.AlreadyExists); + DoRegister(ds, "/notFound/sp1", c3, ErrorCode.NotFound); + DoDeregister(ds, "/dev/sp1", ErrorCode.NoError); + + // manipulate providers within an SDS provider (DSP) + if (dspLoaded) { + ServiceProviderContract.Imp! c4; + ServiceProviderContract.Exp! s4; + ServiceProviderContract.NewChannel(out c4, out s4); + + ServiceProviderContract.Imp! c5; + ServiceProviderContract.Exp! s5; + ServiceProviderContract.NewChannel(out c5, out s5); + + ServiceProviderContract.Imp! c6; + ServiceProviderContract.Exp! s6; + ServiceProviderContract.NewChannel(out c6, out s6); + + DoRegister(ds, "/dsp/sp1", c4, ErrorCode.NoError); + DoRegister(ds, "/dsp/sp1", c5, ErrorCode.AlreadyExists); + DoDeregister(ds, "/dsp/sp1", ErrorCode.NoError); + DoCreateDirectory(ds, "/dsp/dir1", ErrorCode.NoError); + DoRegister(ds, "/dsp/dir1/sp1", c6, ErrorCode.NoError); + DoDeregister(ds, "/dsp/dir1/sp1", ErrorCode.NoError); + DoDeleteDirectory(ds, "/dsp/dir1", ErrorCode.NoError); + delete s4; + delete s5; + delete s6; + } + delete s1; + delete s2; + delete s3; + } + + public int DirectoryTests(DirectoryServiceContract.Imp! ds) + { + // create and delete directories with and without symbolic links + + //create and delete some directories + DoCreateDirectory(ds, "/d1", ErrorCode.NoError); + DoCreateDirectory(ds, "/d1", ErrorCode.AlreadyExists); + DoCreateDirectory(ds, "/d2", ErrorCode.NoError); + DoCreateDirectory(ds, "/d1/d1", ErrorCode.NoError); + + + // add a symbolic link to the mix + DoCreateLink(ds, "/d1/Link1", "/d2", ErrorCode.NoError); + DoCreateDirectory(ds, "/d1/Link1/d2", ErrorCode.NoError); + + DoDeleteDirectory(ds, "/d1/Link1/d2", ErrorCode.NoError); + DoDeleteDirectory(ds, "/d1/Link1/d2", ErrorCode.NotFound); + + // create a link to a link + DoCreateLink(ds, "/d1/LinkToLink", "/d2/Link1", ErrorCode.NoError); + DoCreateLink(ds, "/d2/Link1", "/d3", ErrorCode.NoError); + DoCreateDirectory(ds, "/d3", ErrorCode.NoError); + DoCreateDirectory(ds, "/d1/LinkToLink/d3", ErrorCode.NoError); + + // try and delete a non-empty directory + DoDeleteDirectory(ds, "/d1", ErrorCode.DirectoryNotEmpty); + + // Attempt to delete non directories + + //service provider + DoDeleteDirectory(ds, "/stress", ErrorCode.NotDirectory); + //link + DoDeleteDirectory(ds, "/d2/Link1", ErrorCode.NotDirectory); + //IoMemory + DoDeleteDirectory(ds, "/init/testpe/manifest", ErrorCode.NotDirectory); + + + // clean up residual files + DoDeleteDirectory(ds, "/d1/d1", ErrorCode.NoError); + DoDeleteLink(ds, "/d1/Link1",ErrorCode.NoError); + DoDeleteLink(ds, "/d1/LinkToLink",ErrorCode.NoError); + DoDeleteDirectory(ds, "/d1", ErrorCode.NoError); + DoDeleteDirectory(ds, "/d1", ErrorCode.NotFound); + + DoDeleteLink(ds, "/d2/Link1",ErrorCode.NoError); + DoDeleteDirectory(ds, "/d2", ErrorCode.NoError); + + DoDeleteDirectory(ds, "/d3/d3", ErrorCode.NoError); + DoDeleteDirectory(ds, "/d3", ErrorCode.NoError); + + return 0; + } + + public void LinkTests(DirectoryServiceContract.Imp! ds) + { + DoCreateLink(ds, "/d2/Link1", "/d3", ErrorCode.NotFound); // no /dir1 + DoCreateDirectory(ds, "/d2", ErrorCode.NoError); + DoCreateLink(ds, "/d2/Link1", "/d3", ErrorCode.NoError); + DoCreateLink(ds, "/d2/Link1", "/d3", ErrorCode.AlreadyExists); + + DoGetLink(ds, "/d2/Link1", "/d3", ErrorCode.NoError); + DoGetLink(ds, "/d2", "", ErrorCode.NotLink); + DoDeleteLink(ds, "/d2/Link1",ErrorCode.NoError); + DoDeleteLink(ds, "/d2/Link1",ErrorCode.NotFound); + + DoDeleteDirectory(ds, "/d2", ErrorCode.NoError); + + if (dspLoaded) { + DoCreateLink(ds, "/dsp/rootlink", "/d2", ErrorCode.NoError); + DoCreateLink(ds, "/dsp/rootlink", "/d2", ErrorCode.AlreadyExists); + DoCreateDirectory(ds, "/dsp/d1", ErrorCode.NoError); + DoCreateLink(ds, "/dsp/d1/Link1", "/d2", ErrorCode.NoError); + DoDeleteLink(ds, "/dsp/d1/Link1",ErrorCode.NoError); + DoDeleteLink(ds, "/dsp/rootlink",ErrorCode.NoError); + DoDeleteDirectory(ds, "dsp/d1", ErrorCode.NoError); + } + } + + public void BindTests(DirectoryServiceContract.Imp! ds) + { + // try to bind to the various node types within the root dsp + + FileContract.Imp! fc; + FileContract.Exp! fs; + + ServiceProviderContract.Imp! sc; + ServiceProviderContract.Exp! ss; + + DirectoryServiceContract.Imp! imp; + DirectoryServiceContract.Exp! exp; + + Dummy.Imp! dC; + Dummy.Exp! dS; + + FileContract.NewChannel(out fc, out fs); + DoBind(ds,"/init/testpe/testpe.x86",fs,ErrorCode.NoError); + delete fc; + + Dummy.NewChannel(out dC, out dS); + DoBind(ds,"/init/testpe/testpe.x86",dS,ErrorCode.ContractNotSupported); + delete dC; + + DirectoryServiceContract.NewChannel(out imp , out exp); + DoBind(ds,"/init/testpe/testpe.x86",exp,ErrorCode.ContractNotSupported); + delete imp; + + DoCreateLink(ds, "/link", "/init", ErrorCode.NoError); + FileContract.NewChannel(out fc, out fs); + DoBind(ds,"/link/testpe/testpe.x86",fs,ErrorCode.NoError); + delete fc; + DoDeleteLink(ds, "/link", ErrorCode.NoError); + + FileContract.NewChannel(out fc, out fs); + // bind to dir with File + DoBind(ds,"/init",fs,ErrorCode.ContractNotSupported); + delete fc; + + FileContract.NewChannel(out fc, out fs); + //bind to ServiceProvider with File + DoBind(ds,"/FsCtrl",fs,ErrorCode.ContractNotSupported); + delete fc; + + FileContract.NewChannel(out fc, out fs); + + delete fc; + delete fs; + + //ServiceProvider.NewChannel(out sc, out ss); + // try binding to a dir with all the other types + // bind through links + if (dspLoaded) { + DoCreateDirectory(ds, "/dsp/BindTest", ErrorCode.NoError); + DoCreateLink(ds, "/dsp/BindTest/link", "/BindTest/d2", ErrorCode.NoError); + DoCreateDirectory(ds, "/dsp/BindTest/d1", ErrorCode.NoError); + DoCreateDirectory(ds, "/dsp/BindTest/d2", ErrorCode.NoError); + + DirectoryServiceContract.NewChannel(out imp, out exp); + DoBind(ds,"/dsp/BindTest/d1",exp,ErrorCode.NoError); + delete imp; + + DirectoryServiceContract.NewChannel(out imp, out exp); + DoBind(ds,"/dsp/BindTest/link",exp,ErrorCode.NoError); + delete imp; + + //DoCreateLink(ds, "/dsp/d1/link", "/d2", ErrorCode.NoError); + + + DoDeleteLink(ds, "/dsp/BindTest/link",ErrorCode.NoError); + //DoDeleteLink(ds, "/dsp/d1/link",ErrorCode.NoError); + DoDeleteDirectory(ds, "/dsp/BindTest/d1", ErrorCode.NoError); + DoDeleteDirectory(ds, "/dsp/BindTest/d2", ErrorCode.NoError); + DoDeleteDirectory(ds, "/dsp/BindTest",ErrorCode.NoError); + } + if (nakLoaded) { + // attempt to bind to nak service + // attempt to bind to a closed channel + } + } + } + + public class DirectoryMain + { + private static Process LoadProcess(string[]! arguments) + { + try { + Process process = new Process(arguments); + if (process == null) { + Console.WriteLine("Unable to create process {0}",arguments[0]); + return null; + } + else { + process.Start(); + return process; + } + } + catch (ProcessCreateException) { + Console.WriteLine("Unable to create process {0}",arguments[0]); + } + return null; + } + + internal static int AppMain(Parameters! config) + { + Process dsp = null; + ErrorCode errorOut; + + if (config.nsRef == null) { + throw new Exception("Unable to acquire handle to the Directory Service root"); + } + DirectoryServiceContract.Imp ds = config.nsRef.Acquire(); + + ds.RecvSuccess(); + + // see if the test DSP is loaded by attempting to bind to it + // if not present load it + + bool ok; + /// + /// FIXFIX SdsUtils FlushCache needs to be re-implemented + /// in order for us to be able to wait for NakService termination + /// + + DirectoryServiceContract.Imp! dspImp; + DirectoryServiceContract.Exp! dspExp; + DirectoryServiceContract.NewChannel(out dspImp, out dspExp); + + string dspMountPoint = config.mountPoint; + ok = SdsUtils.Bind(dspMountPoint, ds, dspExp, out errorOut); + delete dspImp; + + bool dspLoaded = false; + if (!ok) { + Console.WriteLine(" unable to bind to {0}. Reason={1}", + dspMountPoint, SdsUtils.ErrorCodeToString(errorOut)); + delete ds; + return 1; + } + else dspLoaded = true; + + DirectoryServiceTests t = new DirectoryServiceTests(false ,dspLoaded, config.printDebug); + + try { + t.DirectoryTests(ds); + t.AttributesTests(ds); + t.ProviderTests(ds); + t.LinkTests(ds); + t.BindTests(ds); + + Console.WriteLine(" pass={0}, fail={1}", t.passCount, t.failCount); + + + //Thread.Sleep(TimeSpan.FromMilliseconds(1000)); + + if (dsp != null) { + t.DoDeregister(ds,dspMountPoint, ErrorCode.NoError); + } + delete ds; + + //Thread.Sleep(TimeSpan.FromMilliseconds(1000)); + + if (dsp != null) { + dsp.Join(); + } + } + finally { + } + return 0; + } + + private static void Usage(string name) + { + Console.WriteLine("{0} creates a directory.",name); + } + } // class Test +} diff --git a/base/Applications/Tests/SdsTiming/SdsTiming.csproj b/base/Applications/Tests/SdsTiming/SdsTiming.csproj new file mode 100644 index 0000000..c4e85d6 --- /dev/null +++ b/base/Applications/Tests/SdsTiming/SdsTiming.csproj @@ -0,0 +1,29 @@ + + + + + + + Exe + SdsTiming + + + + + + + + + + + + + diff --git a/base/Applications/Tests/SdsTiming/SdsTiming.sg b/base/Applications/Tests/SdsTiming/SdsTiming.sg new file mode 100644 index 0000000..a4784af --- /dev/null +++ b/base/Applications/Tests/SdsTiming/SdsTiming.sg @@ -0,0 +1,428 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: SDSTest.sg +// +// Note: +// + +using System; +using System.Threading; +using Microsoft.Singularity; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.V1.Services; +using Microsoft.SingSharp; +using Microsoft.SingSharp.Runtime; + +namespace Microsoft.Singularity.Applications +{ + public contract Dummy : ServiceContract + { + out message Garbage(); + + override state Start: one + { + Garbage! -> End; + } + state End: one {} + } + + public class DirectoryServiceTests + { + private const int ITERATIONS = 10000; + + public int passCount; + public int failCount; + private bool nakLoaded; + private bool dspLoaded; + + + public DirectoryServiceTests (bool nakLoaded, bool dspLoaded) + { + failCount = 0; + passCount = 0; + this.nakLoaded = nakLoaded; + this.dspLoaded= dspLoaded; + } + + public void CheckError( string! verb, string path, ErrorCode expected, ErrorCode actual, bool ok) + { if (ok){ + //Console.WriteLine("{0} on {1} was successful.", verb, path); + } + if (expected != actual) { + failCount++; + Console.WriteLine("FAIL: {0} on {1}. expected={2}, actual={3}. ok={4}", + verb, + path, + SdsUtils.ErrorCodeToString(expected), + SdsUtils.ErrorCodeToString(actual), + ok ? "true" : "false" + ); + //DebugStub.Break(); + } + else { + passCount++; + if (false) { + Console.WriteLine("PASS: {0} on {1} ({2}) ok={3}.", + verb, + path, + SdsUtils.ErrorCodeToString(expected), + ok ? "true" : "false" + ); + } + } + } + + public void CheckError( string! verb, string path, NodeType expected, NodeType actual, bool ok) + { if (ok){ + //Console.WriteLine("{0} on {1} was successful.", verb, path); + } + if (expected != actual) { + failCount++; + Console.WriteLine("FAIL: {0} on {1}. expected={2}, actual={3}. ok={4}", + verb, + path, + SdsUtils.NodeTypeToString(expected), + SdsUtils.NodeTypeToString(actual), + ok ? "true" : "false" + ); + } + else { + passCount++; + Console.WriteLine("PASS: {0} on {1} ({2}) ok={3}.", + verb, + path, + SdsUtils.NodeTypeToString(expected), + ok ? "true" : "false" + ); + } + } + + public bool DoCreateDirectory(DirectoryServiceContract.Imp! ds, string! path, ErrorCode expected) + { + ErrorCode errorOut; + bool ok = SdsUtils.CreateDirectory(path, ds, out errorOut); + CheckError("CreateDirectory", path, expected, errorOut, ok); + return ok; + } + + public void DoDeleteDirectory(DirectoryServiceContract.Imp! ds, string! path, ErrorCode expected) + { + ErrorCode errorOut; + bool ok = SdsUtils.DeleteDirectory(path, ds, out errorOut); + CheckError("DeleteDirectory", path, expected, errorOut, ok); + } + + public void DoCreateLink(DirectoryServiceContract.Imp! ds, string! path, string! value, ErrorCode expected) + { + ErrorCode errorOut; + bool ok = SdsUtils.CreateLink(path, value, ds, out errorOut); + CheckError("CreateLink", path, expected, errorOut, ok); + } + + public void DoGetLink(DirectoryServiceContract.Imp! ds, string! path, string expectedValue, ErrorCode expected) + { + ErrorCode errorOut; + string linkValue; + bool ok = SdsUtils.GetLinkValue(path, ds, out linkValue, out errorOut); + CheckError("GetLinkValue", path, expected, errorOut, ok); + if (ok) { + if (expectedValue != linkValue){ + Console.WriteLine(" expected({0}) got({1})", expectedValue, linkValue); + } + } + } + + public bool DoBind(DirectoryServiceContract.Imp! ds, string! path, + [Claims]ServiceContract.Exp! exp, ErrorCode expected) + { + ErrorCode errorOut; + string linkValue; + bool ok = SdsUtils.Bind(path, ds, exp, out errorOut); + CheckError("Bind", path, expected, errorOut, ok); + return ok; + } + + //simulate FileOpen in FsUtils + public bool DoBind(string! path, + [Claims]ServiceContract.Exp! exp, ErrorCode expected) + { + + DirectoryServiceContract.Imp! ds = DirectoryService.NewClientEndpoint(); + ErrorCode errorOut; + string linkValue; + bool ok = SdsUtils.Bind(path, ds, exp, out errorOut); + CheckError("Bind", path, expected, errorOut, ok); + delete ds; + return ok; + } + + public void DoDeleteLink(DirectoryServiceContract.Imp! ds, string! path, ErrorCode expected) + { + ErrorCode errorOut; + bool ok = SdsUtils.DeleteLink(path, ds, out errorOut); + CheckError("DeleteLink", path, expected, errorOut, ok); + } + + public void DoRegister(DirectoryServiceContract.Imp! ds, + string! path, + [Claims] ServiceProviderContract.Imp! service, + ErrorCode expected) + { + ErrorCode errorOut; + bool ok = SdsUtils.Register(path, ds, service, out errorOut); + CheckError("Register", path, expected, errorOut, ok); + } + + public void DoDeregister(DirectoryServiceContract.Imp! ds, string! path, ErrorCode expected) + { + ErrorCode errorOut; + ServiceProviderContract.Imp:Start service; + + bool ok = SdsUtils.Deregister(path, ds, out service, out errorOut); + CheckError("Deregister", path, expected, errorOut, ok); + delete service; + } + + public void DoGetAttributes(DirectoryServiceContract.Imp! ds, + string! path, + ErrorCode expected, + NodeType expectedNodeType) + { + ErrorCode errorOut; + long length; + NodeType nodeType; + + bool ok = SdsUtils.GetAttributes(path, ds, out length, out nodeType, out errorOut); + CheckError("GetAttributes", path, expectedNodeType, nodeType, ok); + CheckError("GetAttributes", path, expected, errorOut, ok); + } + + public void BindTimeTests(DirectoryServiceContract.Imp! ds) + { + // try to bind to the various node types within the root dsp + + FileContract.Imp! fc; + FileContract.Exp! fs; + + ServiceProviderContract.Imp! sc; + ServiceProviderContract.Exp! ss; + + DirectoryServiceContract.Imp! imp; + DirectoryServiceContract.Exp! exp; + + DirectoryServiceContract.Imp! dspImp; + DirectoryServiceContract.Exp! dspExp; + + DirectoryServiceContract.Imp! dspDirImp; + DirectoryServiceContract.Exp! dspDirExp; + + Dummy.Imp! dC; + Dummy.Exp! dS; + + TimeSpan start; + TimeSpan end; + TimeSpan elapsed; + + DebugStub.WriteLine("\nstart get DirectoryService endpoint"); + start = ProcessService.GetUpTime(); + for ( int i = 0; i < ITERATIONS; i++) { + DirectoryServiceContract.Imp! d = DirectoryService.NewClientEndpoint(); + delete d; + } + end = ProcessService.GetUpTime(); + elapsed = end - start; + Console.WriteLine("\nBind DirectoryService.newEndpoint count={0} time={1}", + ITERATIONS, elapsed); + + /// + + DebugStub.WriteLine("\nstart bind to /init/testpe/testpe.x86"); + start = ProcessService.GetUpTime(); + for ( int i = 0; i < ITERATIONS; i++) { + FileContract.NewChannel(out fc, out fs); + DoBind(ds,"/init/testpe/testpe.x86",fs,ErrorCode.NoError); + delete fc; + } + end = ProcessService.GetUpTime(); + elapsed = end - start; + Console.WriteLine("\nBind /init/testpe/testpe.x86 count={0} time={1}", + ITERATIONS, elapsed); + + /// + if (dspLoaded) { + DebugStub.WriteLine("\nstart bind to /dsp"); + start = ProcessService.GetUpTime(); + for ( int i = 0; i < ITERATIONS; i++) { + DirectoryServiceContract.NewChannel(out dspImp, out dspExp); + DoBind(ds,"/dsp",dspExp,ErrorCode.NoError); + delete dspImp; + } + end = ProcessService.GetUpTime(); + elapsed = end - start; + Console.WriteLine("\nBind /dsp count={0} time={1}", + ITERATIONS, elapsed); + + /// create sub directory and bind to it + + DirectoryServiceContract.NewChannel(out dspImp, out dspExp); + bool haveDsp = DoBind(ds,"/dsp",dspExp,ErrorCode.NoError); + bool haveDir = DoCreateDirectory(ds, "/dsp/bindtime", ErrorCode.NoError); + if (haveDir && haveDsp) { + DebugStub.WriteLine("\nstart bind to /dsp/bindtime"); + start = ProcessService.GetUpTime(); + for ( int i = 0; i < ITERATIONS; i++) { + DirectoryServiceContract.NewChannel(out dspDirImp, out dspDirExp); + DoBind(ds,"/dsp/bindtime",dspDirExp,ErrorCode.NoError); + delete dspDirImp; + } + end = ProcessService.GetUpTime(); + elapsed = end - start; + Console.WriteLine("\nBind /dsp/bindtime via root count={0} time={1}", + ITERATIONS, elapsed); + + /// now from the mount point + + DebugStub.WriteLine("\nstart bind to /dsp/bindtime via mountpoint"); + dspImp.RecvSuccess(); + start = ProcessService.GetUpTime(); + for ( int i = 0; i < ITERATIONS; i++) { + DirectoryServiceContract.NewChannel(out dspDirImp, out dspDirExp); + DoBind(dspImp,"/bindtime",dspDirExp,ErrorCode.NoError); + delete dspDirImp; + } + end = ProcessService.GetUpTime(); + elapsed = end - start; + Console.WriteLine("\nBind /dsp/bindtime via mountpoint count={0} time={1}", + ITERATIONS, elapsed); + + } + delete dspImp; + } + + DebugStub.WriteLine("start bind to /init/testpe/testpe.x86 with NoAllocateAttribute ds"); + TimeSpan s2 = ProcessService.GetUpTime(); + for ( int i = 0; i < ITERATIONS; i++) { + FileContract.NewChannel(out fc, out fs); + DoBind("/init/testpe/testpe.x86",fs,ErrorCode.NoError); + delete fc; + } + TimeSpan e2 = ProcessService.GetUpTime(); + TimeSpan elapsed2 = e2 -s2; + Console.WriteLine("Bind testpe.x86 count={0} time={1}", + ITERATIONS, elapsed2); + + DebugStub.WriteLine("start directory to /init/testpe"); + TimeSpan s3 = ProcessService.GetUpTime(); + for ( int i = 0; i < ITERATIONS; i++) { + DirectoryServiceContract.NewChannel(out imp, out exp); + DoBind("/init/testpe",exp,ErrorCode.NoError); + delete imp; + } + + TimeSpan e3 = ProcessService.GetUpTime(); + TimeSpan elapsed3 = e3 -s3; + Console.WriteLine("Bind dir count={0} time={1}", + ITERATIONS, elapsed3); + } + + } + + public class DirectoryMain + { + private static Process LoadProcess(string[]! arguments) + { + try { + Process process = new Process(arguments); + if (process == null) { + Console.WriteLine("Unable to create process {0}",arguments[0]); + return null; + } + else { + process.Start(); + return process; + } + } + catch (ProcessCreateException) { + Console.WriteLine("Unable to create process {0}",arguments[0]); + } + return null; + } + + public static int Main(string[]! args) + { + Process dsp = null; + ErrorCode errorOut; + + string dspName = "TestDSP.x86"; + string dspMountPoint = "/dsp"; + + DirectoryServiceContract.Imp! ds = DirectoryService.NewClientEndpoint(); + + // see if the test DSP is loaded by attempting to bind to it + // if not present load it + + bool ok; + bool nakLoaded = false; + DirectoryServiceContract.Imp! dspImp; + DirectoryServiceContract.Exp! dspExp; + DirectoryServiceContract.NewChannel(out dspImp, out dspExp); + + ok = SdsUtils.Bind(dspMountPoint, ds, dspExp, out errorOut); + delete dspImp; + + bool dspLoaded = false; + if (!ok) { + Console.WriteLine("Bind to {0} Failed. reason:{1} Will attempt to load {2}", + dspMountPoint, + SdsUtils.ErrorCodeToString(errorOut), + dspName + ); + string [] arguments2 = new string[2]; + arguments2[0] = dspName; + arguments2[1] = dspMountPoint; + dsp = LoadProcess(arguments2); + if (dsp == null) { + Console.WriteLine("unable to load {0}",dspName); + dspLoaded = false; + } + } + else dspLoaded = true; + + DirectoryServiceTests t = new DirectoryServiceTests(nakLoaded ,dspLoaded); + + try { + + t.BindTimeTests(ds); + Console.WriteLine(" pass={0}, fail={1}", t.passCount, t.failCount); + + + //Thread.Sleep(TimeSpan.FromMilliseconds(1000)); + + if (dsp != null) { + t.DoDeregister(ds,dspMountPoint, ErrorCode.NoError); + } + + delete ds; + + //Thread.Sleep(TimeSpan.FromMilliseconds(1000)); + + + if (dsp != null) { + dsp.Join(); + } + } + finally { + } + return 0; + } + + private static void Usage(string name) + { + Console.WriteLine("{0} creates a directory.",name); + } + } // class Test +} diff --git a/base/Applications/Tests/Select/Select.csproj b/base/Applications/Tests/Select/Select.csproj new file mode 100644 index 0000000..2352fe8 --- /dev/null +++ b/base/Applications/Tests/Select/Select.csproj @@ -0,0 +1,34 @@ + + + + + + + select + Exe + true + + + + + + + + + + + + + diff --git a/base/Applications/Tests/Select/Select.sg b/base/Applications/Tests/Select/Select.sg new file mode 100644 index 0000000..a0a7fdf --- /dev/null +++ b/base/Applications/Tests/Select/Select.sg @@ -0,0 +1,467 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Select.cs +// +// Note: Simple Singularity test program. +// +using System; +using System.Threading; +using Microsoft.Singularity.Channels; + +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications { + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [BoolParameter( "set", Default=false, HelpMessage="Run set test.")] + internal bool doSetTest; + + reflective internal Parameters(); + + internal int AppMain() { + return Select.AppMain(this); + } + } + + public class Select + { + private contract SelectTest { + in message A(); + in message B(); + in message C(); + out message Ack(); + + state Start: one { + A? -> Ack! -> Start; + B? -> Ack! -> Start; + C? -> Ack! -> Start; + } + } + + private static TRef[] impEndpoints; + + + public static void SelectThread() + { + SelectTest.Imp[] channel = new SelectTest.Imp [3]; + for (int i = 0; i < 3; i++) { + channel[i] = impEndpoints[i].Acquire(); + } + + channel[2].SendA(); + channel[2].RecvAck(); + + channel[2].SendA(); + channel[2].RecvAck(); + + channel[2].SendA(); + channel[2].RecvAck(); + + channel[1].SendC(); + channel[0].SendB(); + channel[1].RecvAck(); + channel[0].RecvAck(); + + channel[0].SendA(); + channel[1].SendC(); + channel[0].RecvAck(); + channel[1].RecvAck(); + + channel[1].SendC(); + channel[0].SendA(); + + channel[0].RecvAck(); + channel[1].RecvAck(); + + channel[0].SendB(); + channel[1].SendA(); + channel[2].SendC(); + + delete channel[0]; + delete channel[1]; + delete channel[2]; + } + + //[ShellCommand("selectb", "Run select test")] + public static int DoSelect() + { + SelectTest.Exp[] expEndpoints = new SelectTest.Exp [3]; + impEndpoints = new TRef [3]; + + for (int i = 0; i < 3; i++) { + SelectTest.Imp! imp; + SelectTest.Exp! exp; + SelectTest.NewChannel(out imp, out exp); + expEndpoints[i] = exp; + impEndpoints[i] = new TRef(imp); + } + + Thread t1 = new Thread(new ThreadStart(SelectThread)); + t1.Start(); + + SelectTest.Exp a = expEndpoints[0]; + SelectTest.Exp b = expEndpoints[1]; + SelectTest.Exp c = expEndpoints[2]; + + bool failed = false; + ActuallySelect(a, b, c, 0, ref failed); + ActuallySelect(a, b, c, 0, ref failed); + ActuallySelect(a, b, c, 0, ref failed); + ActuallySelect(a, b, c, 1, ref failed); + ActuallySelect(a, b, c, 2, ref failed); + ActuallySelect(a, b, c, 2, ref failed); + ActuallySelect(a, b, c, -1, ref failed); + + if (failed) { + Console.WriteLine("[1] Done (FAILED)."); + return 1; + } + else { + Console.WriteLine("[1] Done (Success)."); + return 0; + } + } + + private static void ActuallySelect(SelectTest.Exp a, + SelectTest.Exp b, + SelectTest.Exp c, + int expect, + ref bool failed) + { + int got; + switch receive { + case c.RecvA(): + c.SendAck(); + got = 0; + break; + + case a.RecvB() && b.RecvC(): + a.SendAck(); + b.SendAck(); + got = 1; + break; + + case a.RecvA() && b.RecvC(): + a.SendAck(); + b.SendAck(); + got = 2; + break; + + case unsatisfiable: + got = -1; + break; + } + + Console.WriteLine("[1] expected {0}, got {1}", expect, got); + if (expect != got) { + failed = true; + } + } + + private static void ActuallySelect(ESet eset, + int expect, + ref bool failed) + { + int got; + switch receive { + case a.RecvA() in eset: + got = 0; + a.SendAck(); + eset.Add(a); + break; + + case b.RecvB() in eset: + got = 1; + b.SendAck(); + eset.Add(b); + break; + + case c.RecvC() in eset: + got = 2; + c.SendAck(); + eset.Add(c); + break; + + case unsatisfiable: + got = -1; + break; + } + + Console.WriteLine("[1] expected {0}, got {1}", expect, got); + if (expect != got) { + failed = true; + } + } + + public static int DoSelectSet() + { + SelectTest.Exp[] expEndpoints = new SelectTest.Exp [3]; + impEndpoints = new TRef [3]; + + for (int i = 0; i < 3; i++) { + SelectTest.Imp! imp; + SelectTest.Exp! exp; + SelectTest.NewChannel(out imp, out exp); + expEndpoints[i] = exp; + impEndpoints[i] = new TRef(imp); + } + + Thread t1 = new Thread(new ThreadStart(SelectThread)); + t1.Start(); + + SelectTest.Exp a = expEndpoints[0]; + SelectTest.Exp b = expEndpoints[1]; + SelectTest.Exp c = expEndpoints[2]; + + ESet eset = new ESet(); + eset.Add(a); + eset.Add(b); + eset.Add(c); + + bool failed = false; + ActuallySelect(eset, 0, ref failed); + ActuallySelect(eset, 0, ref failed); + ActuallySelect(eset, 0, ref failed); + ActuallySelect(eset, 1, ref failed); + ActuallySelect(eset, 2, ref failed); + ActuallySelect(eset, 0, ref failed); + ActuallySelect(eset, 2, ref failed); + ActuallySelect(eset, 0, ref failed); + ActuallySelect(eset, 2, ref failed); + ActuallySelect(eset, 0, ref failed); + ActuallySelect(eset, 1, ref failed); + ActuallySelect(eset, 2, ref failed); + ActuallySelect(eset, -1, ref failed); + + if (failed) { + Console.WriteLine("[1] Done (FAILED)."); + return 1; + } + else { + Console.WriteLine("[1] Done (Success)."); + return 0; + } + } + + /* + //[ShellCommand("select", "Run select test")] + public static int DoSelect() + { + SelectTest.Exp[] expEndpoints = new SelectTest.Exp [3]; + impEndpoints = new TRef [3]; + + for (int i = 0; i < 3; i++) { + SelectTest.Imp! imp; + SelectTest.Exp! exp; + SelectTest.NewChannel(out imp, out exp); + expEndpoints[i] = exp; + impEndpoints[i] = new TRef(imp); + } + + Thread t1 = new Thread(new ThreadStart(SelectThread)); + t1.Start(); + + int[][] patterns = new int[3][]; + patterns[0] = new int [] { 0, 0, SelectTest.Tags.A }; + patterns[1] = new int [] { SelectTest.Tags.B, SelectTest.Tags.C, 0 }; + patterns[2] = new int [] { SelectTest.Tags.A, SelectTest.Tags.C, 0 }; + + ISelectable[] selects = new ISelectable[3]; + for (int i = 0; i<3; i++) { + selects[i] = expEndpoints[i]; + } + + object setMatch; + int i1 = Endpoint.Select(patterns, selects, out setMatch); + Console.WriteLine("[1] Got {0}! (Expected 0.)", i1); + + expEndpoints[2].RecvA(); + expEndpoints[2].SendAck(); + + int i2 = Endpoint.Select(patterns, selects, out setMatch); + Console.WriteLine("[1] Got {0}! (Expected 0.)", i2); + + expEndpoints[2].RecvA(); + expEndpoints[2].SendAck(); + + int i3 = Endpoint.Select(patterns, selects, out setMatch); + Console.WriteLine("[1] Got {0}! (Expected 0.)", i3); + + expEndpoints[2].RecvA(); + expEndpoints[2].SendAck(); + + int i4 = Endpoint.Select(patterns, selects, out setMatch); + Console.WriteLine("[1] Got {0}! (Expected 1.)", i4); + + expEndpoints[0].RecvB(); + expEndpoints[1].RecvC(); + expEndpoints[0].SendAck(); + expEndpoints[1].SendAck(); + + int i5 = Endpoint.Select(patterns, selects, out setMatch); + Console.WriteLine("[1] Got {0}! (Expected 2.)", i5); + + expEndpoints[0].RecvA(); + expEndpoints[1].RecvC(); + expEndpoints[0].SendAck(); + expEndpoints[1].SendAck(); + + int i6 = Endpoint.Select(patterns, selects, out setMatch); + Console.WriteLine("[1] Got {0}! (Expected 2.)", i6); + + expEndpoints[0].RecvA(); + expEndpoints[1].RecvC(); + expEndpoints[0].SendAck(); + expEndpoints[1].SendAck(); + + int i7 = Endpoint.Select(patterns, selects, out setMatch); + Console.WriteLine("[1] Got {0}! (Expected -1.)", i7); + + Console.WriteLine("[1] Done."); + return 0; + } + + + //[ShellCommand("selectset", "Run select set test")] + public static int DoSelectSet() + { + SelectTest.Exp[] expEndpoints = new SelectTest.Exp [3]; + impEndpoints = new TRef [3]; + + for (int i = 0; i < 3; i++) { + SelectTest.Imp! imp; + SelectTest.Exp! exp; + SelectTest.NewChannel(out imp, out exp); + expEndpoints[i] = exp; + impEndpoints[i] = new TRef(imp); + } + + Thread t1 = new Thread(new ThreadStart(SelectThread)); + t1.Start(); + + int[][] patterns = new int[3][]; + patterns[0] = new int [] { SelectTest.Tags.A }; + patterns[1] = new int [] { SelectTest.Tags.B }; + patterns[2] = new int [] { SelectTest.Tags.C }; + + ESet eset = new ESet(); + eset.Add(expEndpoints[0]); + eset.Add(expEndpoints[1]); + eset.Add(expEndpoints[2]); + + ISelectable[] selectEPs = new ISelectable[1]{eset}; + + object setMatch; + int i1 = Endpoint.Select(patterns, selectEPs, out setMatch); + Console.WriteLine("[1] Got {0}! (Expected 0.)", i1); + + SetRecvA(setMatch, eset); + + int i2 = Endpoint.Select(patterns, selectEPs, out setMatch); + Console.WriteLine("[1] Got {0}! (Expected 0.)", i2); + + SetRecvA(setMatch, eset); + + int i3 = Endpoint.Select(patterns, selectEPs, out setMatch); + Console.WriteLine("[1] Got {0}! (Expected 0.)", i3); + + SetRecvA(setMatch, eset); + + int i4 = Endpoint.Select(patterns, selectEPs, out setMatch); + Console.WriteLine("[1] Got {0}! (Expected 1.)", i4); + + SetRecvB(setMatch, eset); + + int i5 = Endpoint.Select(patterns, selectEPs, out setMatch); + Console.WriteLine("[1] Got {0}! (Expected 2.)", i5); + + SetRecvC(setMatch, eset); + + int i6 = Endpoint.Select(patterns, selectEPs, out setMatch); + Console.WriteLine("[1] Got {0}! (Expected 0.)", i6); + + SetRecvA(setMatch, eset); + + int i7 = Endpoint.Select(patterns, selectEPs, out setMatch); + Console.WriteLine("[1] Got {0}! (Expected 2.)", i7); + + SetRecvC(setMatch, eset); + + int i8 = Endpoint.Select(patterns, selectEPs, out setMatch); + Console.WriteLine("[1] Got {0}! (Expected 0.)", i8); + + SetRecvA(setMatch, eset); + + int i9 = Endpoint.Select(patterns, selectEPs, out setMatch); + Console.WriteLine("[1] Got {0}! (Expected 2.)", i9); + + SetRecvC(setMatch, eset); + + int i10 = Endpoint.Select(patterns, selectEPs, out setMatch); + Console.WriteLine("[1] Got {0}! (Expected 0.)", i10); + + SetRecvA(setMatch, eset); + + int i11 = Endpoint.Select(patterns, selectEPs, out setMatch); + Console.WriteLine("[1] Got {0}! (Expected 1.)", i11); + + SetRecvB(setMatch, eset); + + int i12 = Endpoint.Select(patterns, selectEPs, out setMatch); + Console.WriteLine("[1] Got {0}! (Expected 2.)", i12); + + SetRecvC(setMatch, eset); + + int i13 = Endpoint.Select(patterns, selectEPs, out setMatch); + Console.WriteLine("[1] Got {0}! (Expected -1.)", i13); + + Console.WriteLine("[1] Done."); + return 0; + } + + private static void SetRecvA(object match, ESet eset) { + SelectTest.Exp exp = eset.Extract(match); + exp.RecvA(); + exp.SendAck(); + eset.Add(exp); + } + + private static void SetRecvB(object match, ESet eset) { + SelectTest.Exp exp = eset.Extract(match); + exp.RecvB(); + exp.SendAck(); + eset.Add(exp); + } + + private static void SetRecvC(object match, ESet eset) { + SelectTest.Exp exp = eset.Extract(match); + exp.RecvC(); + exp.SendAck(); + eset.Add(exp); + } + */ + + internal static int AppMain(Parameters! config) + { + const int ARGS_START = 1; + + if (config.doSetTest) return DoSelectSet(); + return DoSelect(); + } + } +} diff --git a/base/Applications/Tests/SharedHeapTest/SharedHeapTest.cs b/base/Applications/Tests/SharedHeapTest/SharedHeapTest.cs new file mode 100644 index 0000000..b58b396 --- /dev/null +++ b/base/Applications/Tests/SharedHeapTest/SharedHeapTest.cs @@ -0,0 +1,347 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: SharedHeapTest.cs +// +// Note: User-mode test program for calling shared heap through the ABI. +// +using Microsoft.Singularity.V1.Services; +using System; +using System.Runtime.CompilerServices; +using System.Threading; + +using Microsoft.Singularity.Channels; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications { + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal Parameters(); + + internal int AppMain() { + SharedHeapTest.AppMain(this); + return 0; + } + } + + unsafe public class SharedHeapTest + { + // + // Note: The integrity check relies on there being one bit in each byte + // to represent the owning concurrent allocation slot, so the number of + // concurrent allocations can't exceed 8. + // + private const uint ConcurrentAllocations = 8; + private SharedHeapService.Allocation*[]! mem; + + Random! random = new Random(); + + internal static void AppMain(Parameters! config) + { + SharedHeapTest test = new SharedHeapTest(); + + uint Iterations = 10; + + Console.WriteLine("Starting Shared Heap Test\n"); + test.StartUp(); + for (uint loop = 0; loop < Iterations; loop++) { + test.Perturb(); + if (test.Check() == false) { + break; + } + } + } + + private SharedHeapTest() { + // + // Create an array to hold our concurrent allocations. + // + this.mem = new SharedHeapService.Allocation*[ConcurrentAllocations]; + } + + public static void Usage() + { + Console.WriteLine("Usage: sharedheap [Iterations]\n"); + } + + public void StartUp() + { + // + // Allocating a bunch of randomly sized things. + // + for (uint loop = 0; loop < ConcurrentAllocations; loop++) { + AllocRandomSizedThingy(loop); + if (CheckForValue(loop, 0) == true) { + Console.WriteLine("Passed zero-fill test.\n"); + } else { + Console.WriteLine("Failed zero-fill test.\n"); + } + FillWithValue(loop, (byte)(1 << (int)loop)); + } + } + + public bool Check() + { + // + // Check all allocations for expected bit settings. + // + Console.WriteLine("--------\n"); + Console.WriteLine("Integrity Check\n"); + + for (uint loop = 0; loop < ConcurrentAllocations; loop++) { + if (CheckBits(loop, (byte)(1 << (int)loop)) == false) { + return false; + } + } + + Console.WriteLine("--------\n"); + return true; + } + + public void Perturb() + { + // + // Pick an element slot to use and an action to take. + // + uint which = (uint)random.Next(ConcurrentAllocations); + uint action = (uint)random.Next(3); + + // + // Free up the slot. + // + Console.WriteLine("--------\n"); + Console.WriteLine( + "Freeing region: Data = {0}, Size = {1}.\n", + SharedHeapService.GetData(this.mem[which]), + SharedHeapService.GetSize(this.mem[which])); + + ClearBits(which, (byte)(1 << (int)which)); + SharedHeapService.Free(this.mem[which]); + + Console.WriteLine("--------\n"); + + // + // Play around. + // + switch(action) { + case 0: + // + // Allocate something new. + // + Console.WriteLine("Allocation Test\n"); + AllocRandomSizedThingy(which); + if (CheckForValue(which, 0) == true) { + Console.WriteLine("Passed zero-fill test.\n"); + } else { + Console.WriteLine("Failed zero-fill test.\n"); + } + + // + // Store bit corresponding to slot number in each + // data byte. Used to check integrity later. + // + FillWithValue(which, (byte)(1 << (int)which)); + break; + + case 1: + // + // Split an element in two. Use the slot we freed + // up above to hold the split-off piece. + // + Console.WriteLine("Split Test\n"); + + // + // Pick a region to split. + // + uint split; + do { + split = (uint)random.Next(ConcurrentAllocations); + } while (split == which); + + Console.Write( + "Splitting region: Data = {0}, Size = {1}", + SharedHeapService.GetData(this.mem[split]), + SharedHeapService.GetSize(this.mem[split])); + UIntPtr offset = (UIntPtr)random.Next( + 1, + (int)SharedHeapService.GetSize(this.mem[split])); + Console.WriteLine(" in two at offset {0}.\n", offset); + + this.mem[which] = SharedHeapService.Split( + this.mem[split], + offset); + + Console.WriteLine( + "Revised region: Data = {0}, Size = {1}.\n", + SharedHeapService.GetData(this.mem[split]), + SharedHeapService.GetSize(this.mem[split])); + + Console.WriteLine( + "New region: Data = {0}, Size = {1}.\n", + SharedHeapService.GetData(this.mem[which]), + SharedHeapService.GetSize(this.mem[which])); + + // + // Remove bit corresponding to the slot of the original + // region from the split-off data. Likewise, add the + // bit corresponding to the slot number of the split-off + // region to the split-off data. + // + ClearBits(which, (byte)(1 << (int)split)); + SetBits(which, (byte)(1 << (int)which)); + + break; + + case 2: + // + // Share part of a region. Use the slot we freed + // up above to hold the shared piece. + // + Console.WriteLine("Share Test\n"); + + // + // Pick a region to share. + // + uint share; + do { + share = (uint)random.Next(ConcurrentAllocations); + } while (share == which); + + Console.Write( + "Sharing region: Data = {0}, Size = {1}", + SharedHeapService.GetData(this.mem[share]), + SharedHeapService.GetSize(this.mem[share])); + UIntPtr start = (UIntPtr)random.Next( + 1, + (int)SharedHeapService.GetSize(this.mem[share])); + Console.WriteLine(" starting at offset {0}.\n", start); + + this.mem[which] = SharedHeapService.Share( + this.mem[share], + start, SharedHeapService.GetSize(this.mem[share])); + + Console.WriteLine( + "Original region: Data = {0}, Size = {1}.\n", + SharedHeapService.GetData(this.mem[share]), + SharedHeapService.GetSize(this.mem[share])); + + Console.WriteLine( + "New region: Data = {0}, Size = {1}.\n", + SharedHeapService.GetData(this.mem[which]), + SharedHeapService.GetSize(this.mem[which])); + + // + // Modify each data byte in the shared region to include + // the bit corresponding to the slot number of the new + // shared allocation handle. + // + SetBits(which, (byte)(1 << (int)which)); + + break; + } + } + + private void AllocRandomSizedThingy(uint index) + { + // REVIEW: We can't ask the system for the PageSize? + // Hardcoded to 2 * Pages.PageSize. + UIntPtr size = (UIntPtr)random.Next(1, 8192); + + this.mem[index] = SharedHeapService.Allocate(size, typeof(byte).GetSystemType(), 0); + + Console.WriteLine("Allocated region: Data = {0}, Size = {1}.\n", + SharedHeapService.GetData(this.mem[index]), + SharedHeapService.GetSize(this.mem[index])); + } + + private void FillWithValue(uint index, byte value) + { + UIntPtr data = SharedHeapService.GetData(this.mem[index]); + UIntPtr size = SharedHeapService.GetSize(this.mem[index]); + + for (UIntPtr address = data; address < data + size; address++) { + *(byte *)address = value; + } + + return; + } + + private bool CheckForValue(uint index, byte value) + { + UIntPtr data = SharedHeapService.GetData(this.mem[index]); + UIntPtr size = SharedHeapService.GetSize(this.mem[index]); + bool status = true; + + for (UIntPtr address = data; address < data + size; address++) { + if (*(byte *)address != value) { + status = false; + Console.Write("Wrong value {0} at address {1}.\n", + *(byte *)address, address); + Console.Write("Should be {0}.\n", value); + } + } + + return status; + } + + private void SetBits(uint index, byte bit) + { + UIntPtr data = SharedHeapService.GetData(this.mem[index]); + UIntPtr size = SharedHeapService.GetSize(this.mem[index]); + + for (UIntPtr address = data; address < data + size; address++) { + *(byte *)address |= bit; + } + + return; + } + + private void ClearBits(uint index, byte bit) + { + UIntPtr data = SharedHeapService.GetData(this.mem[index]); + UIntPtr size = SharedHeapService.GetSize(this.mem[index]); + + for (UIntPtr address = data; address < data + size; address++) { + *(byte *)address &= (byte)~bit; + } + + return; + } + + private bool CheckBits(uint index, byte bit) + { + UIntPtr data = SharedHeapService.GetData(this.mem[index]); + UIntPtr size = SharedHeapService.GetSize(this.mem[index]); + bool status = true; + + for (UIntPtr address = data; address < data + size; address++) { + if ((*(byte *)address & bit) != bit) { + status = false; + Console.WriteLine("Bad value {0} at address {1}.\n", + *(byte *)address, address); + // + // Stop at one to prevent huge output. + // + break; + } + } + + return status; + } + } +} + diff --git a/base/Applications/Tests/SharedHeapTest/SharedHeapTest.csproj b/base/Applications/Tests/SharedHeapTest/SharedHeapTest.csproj new file mode 100644 index 0000000..152f994 --- /dev/null +++ b/base/Applications/Tests/SharedHeapTest/SharedHeapTest.csproj @@ -0,0 +1,26 @@ + + + + + + + Exe + SharedHeapTest + true + + + + + + + + + diff --git a/base/Applications/Tests/SmpTest/ForkTest.sg b/base/Applications/Tests/SmpTest/ForkTest.sg new file mode 100644 index 0000000..773bc11 --- /dev/null +++ b/base/Applications/Tests/SmpTest/ForkTest.sg @@ -0,0 +1,64 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: HeapTest.cs +// +// Note: Allocate strings and encourage GCs +// + +using System; +using System.Collections; +using System.Threading; + +using Microsoft.Singularity.UnitTest; + +namespace Microsoft.Singularity.Applications +{ + public class ForkTest + { + static readonly string []! ProcessArgs = new string[] { "testpe.x86" }; + static readonly TimeSpan ProcessTimeout = TimeSpan.FromSeconds(10); + const int IterationsPerThread = 64; + + static object! monitor = new object(); + static AutoResetEvent! exitEvent = new AutoResetEvent(false); + static int threadCount; + + private static void ThreadMain() + { + lock (ForkTest.monitor) { + ForkTest.threadCount++; + } + + for (int i = 0; i < IterationsPerThread; i++) { + Process process = new Process(ForkTest.ProcessArgs); + process.Start(); + Assert.True(process.Join(ProcessTimeout), + "Failed to join process."); + } + + lock (ForkTest.monitor) { + ForkTest.threadCount--; + if (ForkTest.threadCount == 0) { + ForkTest.exitEvent.Set(); + } + } + } + + public static void Run() + { + ForkTest.monitor = new object(); + ForkTest.exitEvent = new AutoResetEvent(false); + ForkTest.threadCount = 0; + + for (int i = 0; i < Settings.MaxThreads; i++) { + Thread t = new Thread(new ThreadStart(ThreadMain)); + t.Start(); + } + ForkTest.exitEvent.WaitOne(); + } + } +} diff --git a/base/Applications/Tests/SmpTest/HeapTest.sg b/base/Applications/Tests/SmpTest/HeapTest.sg new file mode 100644 index 0000000..0bf3177 --- /dev/null +++ b/base/Applications/Tests/SmpTest/HeapTest.sg @@ -0,0 +1,74 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: HeapTest.sg +// +// Note: +// + +using System; +using System.Collections; +using System.Threading; + +namespace Microsoft.Singularity.Applications +{ + public class HeapTest + { + // GC threshold is around 8MB. + private const long TotalToAllocate = 8L * 1024 * 1024 * 1024; + private const int LargeStringLength = 1023; + private const int SmallStringLength = 64; + + private static object! monitor; + private static int threadCount = 0; + private static AutoResetEvent! exitEvent; + private static int stringLength; + private static int allocationsPerThread = 0; + + private static void ThreadMain() + { + lock (HeapTest.monitor) { + HeapTest.threadCount++; + } + + for (int i = 0; i < HeapTest.allocationsPerThread; i++) { + new String('a', HeapTest.stringLength); + } + + lock (HeapTest.monitor) { + HeapTest.threadCount--; + if (HeapTest.threadCount == 0) { + HeapTest.exitEvent.Set(); + } + } + } + + private static void Test(int stringLength) + { + HeapTest.monitor = new object(); + HeapTest.exitEvent = new AutoResetEvent(false); + HeapTest.threadCount = 0; + HeapTest.stringLength = stringLength; + HeapTest.allocationsPerThread = unchecked((int)(TotalToAllocate / (Settings.MaxThreads * stringLength))); + + for (int i = 0; i < Settings.MaxThreads; i++) { + Thread t = new Thread(new ThreadStart(ThreadMain)); + t.Start(); + } + HeapTest.exitEvent.WaitOne(); + } + + public static void TestLargeAllocs() + { + Test(LargeStringLength); + } + + public static void TestSmallAllocs() + { + Test(SmallStringLength); + } + } +} diff --git a/base/Applications/Tests/SmpTest/Settings.sg b/base/Applications/Tests/SmpTest/Settings.sg new file mode 100644 index 0000000..183ec15 --- /dev/null +++ b/base/Applications/Tests/SmpTest/Settings.sg @@ -0,0 +1,18 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Settings.sg +// +// Note: +// + +namespace Microsoft.Singularity.Applications +{ + class Settings + { + public const int MaxThreads = 8; + } +} diff --git a/base/Applications/Tests/SmpTest/SmpTest.csproj b/base/Applications/Tests/SmpTest/SmpTest.csproj new file mode 100644 index 0000000..e505a9a --- /dev/null +++ b/base/Applications/Tests/SmpTest/SmpTest.csproj @@ -0,0 +1,32 @@ + + + + + + + Exe + SmpTest + + + + + + + + + + + + + + + + diff --git a/base/Applications/Tests/SmpTest/SmpTest.sg b/base/Applications/Tests/SmpTest/SmpTest.sg new file mode 100644 index 0000000..fd35956 --- /dev/null +++ b/base/Applications/Tests/SmpTest/SmpTest.sg @@ -0,0 +1,62 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: SmpTest.cs +// +// Note: Some basic tests of system code on SMP. +// + +using System; +using System.Threading; + +using Microsoft.Singularity.UnitTest; + +using Microsoft.Singularity.Channels; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications +{ + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal Parameters(); + + internal int AppMain() { + return SmpTest.AppMain(this); + } + } + + public class SmpTest + { + internal static int AppMain(Parameters! config) + { + UnitTest.Add("process creation", + new UnitTest.TestDelegate(ForkTest.Run)); + + UnitTest.Add("heap and GC (large allocations)", + new UnitTest.TestDelegate(HeapTest.TestLargeAllocs)); + + UnitTest.Add("heap and GC (small allocations)", + new UnitTest.TestDelegate(HeapTest.TestSmallAllocs)); + + UnitTest.Add("process creation", + new UnitTest.TestDelegate(ForkTest.Run)); + + return ((UnitTest.Run(true) == UnitTest.Result.Passed) && + Assert.Failures == 0) ? 0 : 1; + } + } +} diff --git a/base/Applications/Tests/Sync/Sync.cs b/base/Applications/Tests/Sync/Sync.cs new file mode 100644 index 0000000..e08b986 --- /dev/null +++ b/base/Applications/Tests/Sync/Sync.cs @@ -0,0 +1,144 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Sync.cs +// +// Note: Simple Singularity test program. +// +using System; +using System.Threading; + +using Microsoft.Singularity.Channels; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications { + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal Parameters(); + + internal int AppMain() { + return Sync.AppMain(this); + } + } + + public class Sync + { + private static Mutex! mutex; + private static AutoResetEvent! autoResetEvent; + private static ManualResetEvent! manualResetEvent; + private static AutoResetEvent! syncEvent; + + public static void SyncThread() + { + Console.WriteLine("[2] Acquiring mutex..."); + mutex.WaitOne(); + Console.WriteLine("[2] Mutex acquired!"); + mutex.ReleaseMutex(); + Console.WriteLine("[2] Mutex released."); + + Thread.Yield(); + Thread.Yield(); + Thread.Yield(); + Thread.Yield(); + Thread.Yield(); + + Console.WriteLine("[2] Setting event."); + autoResetEvent.Set(); + + Thread.Yield(); + Thread.Yield(); + Thread.Yield(); + Thread.Yield(); + Thread.Yield(); + + Console.WriteLine("[2] Waiting for notification..."); + syncEvent.WaitOne(); + + Console.WriteLine("[2] Setting event."); + autoResetEvent.Set(); + + Console.WriteLine("[2] Waiting for notification..."); + syncEvent.WaitOne(); + + Console.WriteLine("[2] Setting manual event."); + manualResetEvent.Set(); + } + + //[ShellCommand("sync", "Run synchronization test")] + internal static int AppMain(Parameters! config) + { + mutex = new Mutex(); + autoResetEvent = new AutoResetEvent(false); + manualResetEvent = new ManualResetEvent(true); + syncEvent = new AutoResetEvent(false); + + Thread t1 = new Thread(new ThreadStart(SyncThread)); + t1.Start(); + + Console.WriteLine("[1] Acquiring mutex..."); + mutex.WaitOne(); + Console.WriteLine("[1] Mutex acquired!"); + Console.WriteLine("[1] Releasing mutex..."); + mutex.ReleaseMutex(); + Console.WriteLine("[1] Mutex released."); + + Console.WriteLine("[1] Acquiring mutex..."); + mutex.WaitOne(); + Console.WriteLine("[1] Mutex acquired!"); + Console.WriteLine("[1] Yielding (1/3)."); + Thread.Yield(); + Console.WriteLine("[1] Yielding (2/3)."); + Thread.Yield(); + Console.WriteLine("[1] Yielding (3/3)."); + Thread.Yield(); + Console.WriteLine("[1] Releasing mutex..."); + mutex.ReleaseMutex(); + Console.WriteLine("[1] Mutex released."); + + Console.WriteLine("[1] Waiting on event."); + autoResetEvent.WaitOne(); + Console.WriteLine("[1] Event set!"); + + Console.WriteLine("[1] Setting sync event."); + syncEvent.Set(); + + Console.WriteLine("[1] Waiting on event."); + autoResetEvent.WaitOne(); + Console.WriteLine("[1] Event set!"); + + Console.WriteLine("[1] Waiting on manual event."); + manualResetEvent.WaitOne(); + Console.WriteLine("[1] Event set!"); + + Console.WriteLine("[1] Resetting manual event."); + manualResetEvent.Reset(); + + Console.WriteLine("[1] Setting sync event."); + syncEvent.Set(); + + Console.WriteLine("[1] Waiting on manual event."); + manualResetEvent.WaitOne(); + Console.WriteLine("[1] Event set!"); + + Console.WriteLine("[1] Waiting on manual event."); + manualResetEvent.WaitOne(); + Console.WriteLine("[1] Event set!"); + + return 0; + } + } +} diff --git a/base/Applications/Tests/Sync/Sync.csproj b/base/Applications/Tests/Sync/Sync.csproj new file mode 100644 index 0000000..792e275 --- /dev/null +++ b/base/Applications/Tests/Sync/Sync.csproj @@ -0,0 +1,25 @@ + + + + + + + Exe + Sync + + + + + + + + + diff --git a/base/Applications/Tests/ThreadTest/ThreadTest.cs b/base/Applications/Tests/ThreadTest/ThreadTest.cs new file mode 100644 index 0000000..6bc837a --- /dev/null +++ b/base/Applications/Tests/ThreadTest/ThreadTest.cs @@ -0,0 +1,90 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: ThreadTest.cs +// +// Note: Simple Singularity test program. +// +using System; +using System.Threading; +using Microsoft.Singularity.V1.Services; + +using Microsoft.Singularity.Channels; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications { + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal Parameters(); + + internal int AppMain() { + return ThreadTest.AppMain(this); + } + } + + public class ThreadTest + { + public static void FirstThreadMethod() + { + Console.WriteLine("First thread!"); + DebugStub.Print("First thread!\n"); + + for (int i = 0; i < 10; i++) { + Console.WriteLine("[0] ... "); + Thread.Yield(); + } + + Console.WriteLine("First thread done!"); + DebugStub.Print("First thread done!\n"); + } + + public static void SecondThreadMethod() + { + Console.WriteLine("Second thread!"); + DebugStub.Print("Second thread!\n"); + + for (int i = 0; i < 10; i++) + { + Console.WriteLine(" ... [1]"); + Thread.Yield(); + } + + Console.WriteLine("Second thread done!"); + DebugStub.Print("Second thread done!\n"); + } + + internal static int AppMain(Parameters! config) + { + Thread t1 = new Thread(new ThreadStart(FirstThreadMethod)); + Thread t2 = new Thread(new ThreadStart(SecondThreadMethod)); + + Console.WriteLine("Starting first thread."); + t1.Start(); + Console.WriteLine("Started first thread."); + + Console.WriteLine("Starting second thread."); + t2.Start(); + Console.WriteLine("Started second thread."); + + for (int i = 0; i < 30; i++) + { + Thread.Yield(); + } + return 0; + } + } +} diff --git a/base/Applications/Tests/ThreadTest/ThreadTest.csproj b/base/Applications/Tests/ThreadTest/ThreadTest.csproj new file mode 100644 index 0000000..72547ff --- /dev/null +++ b/base/Applications/Tests/ThreadTest/ThreadTest.csproj @@ -0,0 +1,28 @@ + + + + + + + ThreadTest + Exe + + + + + + + + diff --git a/base/Applications/Tests/Throw/Throw.cs b/base/Applications/Tests/Throw/Throw.cs new file mode 100644 index 0000000..8b12881 --- /dev/null +++ b/base/Applications/Tests/Throw/Throw.cs @@ -0,0 +1,61 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Throw.cs +// +// Note: Simple Singularity test program. +// +using System; +using Microsoft.Singularity.V1.Services; + +using Microsoft.Singularity.Channels; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications { + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal Parameters(); + + internal int AppMain() { + return Throw.AppMain(this); + } + } + + public class Throw + { + //[ShellCommand("throw", "Throw an exception")] + internal static int AppMain(Parameters! config) + { + string args = "something"; + + try + { + DebugStub.Print("About to throw exception\n"); + if (args == null) + { + throw new ArgumentNullException("ArgNullException"); + } + throw new ApplicationException("AppException"); + } + catch (Exception e) + { + Console.WriteLine("Caught exception {0}", e); + } + return 0; + } + } +} diff --git a/base/Applications/Tests/Throw/Throw.csproj b/base/Applications/Tests/Throw/Throw.csproj new file mode 100644 index 0000000..35a18eb --- /dev/null +++ b/base/Applications/Tests/Throw/Throw.csproj @@ -0,0 +1,28 @@ + + + + + + + Throw + Exe + + + + + + + + diff --git a/base/Applications/Tests/ThrowWithLinkStack/ThrowWithLinkStack.cs b/base/Applications/Tests/ThrowWithLinkStack/ThrowWithLinkStack.cs new file mode 100644 index 0000000..65d7281 --- /dev/null +++ b/base/Applications/Tests/ThrowWithLinkStack/ThrowWithLinkStack.cs @@ -0,0 +1,61 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: ThrowWithLinkStack.cs +// +// Note: Simple Singularity test program. +// +using System; +using Microsoft.Singularity.V1.Services; +using System.Runtime.CompilerServices; + +using Microsoft.Singularity.Channels; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications { + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal Parameters(); + + internal int AppMain() { + return ThrowWithLinkStack.AppMain(this); + } + } + + public class ThrowWithLinkStack + { + //[ShellCommand("throwWithLinkStack", "Throw an exception with link stack")] + internal static int AppMain(Parameters! config) + { + try + { + DebugStub.Print("About to throw exception\n"); + Throw(); + } + catch (Exception e) + { + Console.WriteLine("Throw with Link Stack Caught exception {0}", e); + } + return 0; + } + + [RequireStackLink] + public static int Throw() { + throw new ApplicationException("AppException"); + } + } +} diff --git a/base/Applications/Tests/ThrowWithLinkStack/ThrowWithLinkStack.csproj b/base/Applications/Tests/ThrowWithLinkStack/ThrowWithLinkStack.csproj new file mode 100644 index 0000000..636987f --- /dev/null +++ b/base/Applications/Tests/ThrowWithLinkStack/ThrowWithLinkStack.csproj @@ -0,0 +1,28 @@ + + + + + + + ThrowWithLinkStack + Exe + + + + + + + + diff --git a/base/Applications/Tests/UnitTestTest/UnitTestTest.cs b/base/Applications/Tests/UnitTestTest/UnitTestTest.cs new file mode 100644 index 0000000..70a0651 --- /dev/null +++ b/base/Applications/Tests/UnitTestTest/UnitTestTest.cs @@ -0,0 +1,216 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: UnitTestTest.cs +// +// Note: A test of the Unit testing code. +// + +using System; +using System.Collections; +using System.Threading; +using Microsoft.Singularity.UnitTest; + +using Microsoft.Singularity.Channels; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications { + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal Parameters(); + + internal int AppMain() { + return Test.AppMain(this); + } + } + public class Test + { + private static void SimpleChecks() + { + Assert.True(true, "Expected true"); + Assert.False(false, "Expected false"); + Assert.Null(null, "Expected null"); + + object low = (object)0; + object high = (object)1; + Assert.NonNull(low, "Expected non-null value"); + Assert.SameObject(low, low, "Expected same object"); + Assert.NotSameObject(low, new object(), + "Expected different objects"); + Assert.Equal(low, low, + "Expected equal objects"); + Assert.NotEqual(low, high, "Expected unequal objects."); + + } + + // ------------------------------------------------------------------- + // Byte tests + // + // Generics would be handy here, + // but are not crucial as the overloads for binary + // operators are script generated so we expect them to work + // irrespective of type. + + internal delegate void BinaryOp(byte a, byte b, string msg); + + internal class WrappedBinaryOp + { + byte first; + byte second; + string! message; + BinaryOp! op; + + internal WrappedBinaryOp(byte first, + byte second, + string! message, + BinaryOp! op) + { + this.first = first; + this.second = second; + this.message = message; + this.op = op; + } + + public void Dispatch() + { + op(first, second, message); + } + } + + private static void TestBadByteOperations() + { + ArrayList ops = new ArrayList(); + + int oldPasses = Assert.Passes; + int oldFailures = Assert.Failures; + + ops.Add(new WrappedBinaryOp(0, 1, "Equal", + new BinaryOp(Assert.Equal))); + ops.Add(new WrappedBinaryOp(0, 1, "Greater", + new BinaryOp(Assert.Greater))); + ops.Add(new WrappedBinaryOp(0, 0, "Greater", + new BinaryOp(Assert.Greater))); + ops.Add(new WrappedBinaryOp(0, 1, "GreaterOrEqual", + new BinaryOp(Assert.GreaterOrEqual))); + ops.Add(new WrappedBinaryOp(1, 0, "Less", + new BinaryOp(Assert.Less))); + ops.Add(new WrappedBinaryOp(0, 0, "Less", + new BinaryOp(Assert.Less))); + ops.Add(new WrappedBinaryOp(1, 0, "LessOrEqual", + new BinaryOp(Assert.LessOrEqual))); + + foreach (WrappedBinaryOp! op in ops) { + bool missedException = false; + try { + op.Dispatch(); + missedException = true; + } + catch (FailedAssertionException) { + missedException = false; + } + if (missedException) { + throw new + FailedAssertionException("Unexpected test pass."); + } + } + Assert.Equal(oldPasses, Assert.Passes, "Assert Passes"); + Assert.Equal(oldFailures + 7, Assert.Failures, "Assert Failures"); + } + + private static void TestByteOperations() + { + int oldPasses = Assert.Passes; + Assert.Equal((byte)0, (byte)0, "byte Equal Test"); + Assert.Greater((byte)1, (byte)0, "byte Greater Test"); + Assert.GreaterOrEqual((byte)1, (byte)0, + "byte GreaterOrEqual Test"); + Assert.GreaterOrEqual((byte)0, (byte)0, + "byte GreaterOrEqual Test 2"); + Assert.Less((byte)0, (byte)1, "byte Less Test"); + Assert.LessOrEqual((byte)0, (byte)1, + "byte LessOrEqual Test"); + Assert.LessOrEqual((byte)0, (byte)0, + "byte LessOrEqual Test 2"); + Assert.Equal(oldPasses + 7, Assert.Passes, "Assert Passes"); + } + + private static void TestWatchDog() + { + const int deferrals = 20; + TimeSpan deferPeriod = TimeSpan.FromMilliseconds(250); + TimeSpan halfDeferPeriod = + TimeSpan.FromTicks(deferPeriod.Ticks / 2); + + WatchDogTimer wd = new WatchDogTimer(deferPeriod); + + wd.Start(); + Assert.True(wd.Running, "Watch dog failed to start"); + + wd.Stop(); + Assert.False(wd.Running, "Watch dog failed to stop"); + + wd.Start(); + Assert.True(wd.Running, "Watch dog failed to restart"); + + Thread.Sleep(halfDeferPeriod); + + for (int i = 0; i < deferrals; i++) { + wd.Defer(); + Thread.Sleep(halfDeferPeriod); + Assert.True(wd.Running, + "Watch dog timer stopped unexpectedly."); + } + + // About to deliberately timeout watchdog + // so announce upcoming assertion failure from watchdog. + UnitTest.ExpectNextAssertionFails(); + Thread.Sleep(deferPeriod); + Thread.Sleep(deferPeriod); + UnitTest.ExpectNextAssertionPasses(); + + Assert.False(wd.Running, "Watch dog timer did not timeout."); + + wd.Start(); + wd.Start(); + wd.Start(); + wd.Stop(); + wd.Stop(); + } + + internal static int AppMain(Parameters! config) + { + UnitTest.Add("SimpleChecks", + new UnitTest.TestDelegate(SimpleChecks)); + UnitTest.Add("TestByteOperations", + new UnitTest.TestDelegate(TestByteOperations)); + UnitTest.Add("TestBadByteOperations", + new UnitTest.TestDelegate(TestBadByteOperations)); + if (UnitTest.Run(true) != UnitTest.Result.Passed) + return -1; + + UnitTest.Clear(); + + // The following test "fails" because + // it needs to see the watchdog timeout. + UnitTest.Add("TestWatchDog", + new UnitTest.TestDelegate(TestWatchDog)); + UnitTest.Run(true); + + return 0; + } + } +} diff --git a/base/Applications/Tests/UnitTestTest/UnitTestTest.csproj b/base/Applications/Tests/UnitTestTest/UnitTestTest.csproj new file mode 100644 index 0000000..70b8670 --- /dev/null +++ b/base/Applications/Tests/UnitTestTest/UnitTestTest.csproj @@ -0,0 +1,34 @@ + + + + + + + UnitTestTest + Exe + true + true + + + + + + + + + + + + diff --git a/base/Applications/Tests/VQTest/VQTest.csproj b/base/Applications/Tests/VQTest/VQTest.csproj new file mode 100644 index 0000000..d591489 --- /dev/null +++ b/base/Applications/Tests/VQTest/VQTest.csproj @@ -0,0 +1,25 @@ + + + + + + + Exe + VQTest + + + + + + + + + diff --git a/base/Applications/Tests/VQTest/VQTest.sg b/base/Applications/Tests/VQTest/VQTest.sg new file mode 100644 index 0000000..cb529ab --- /dev/null +++ b/base/Applications/Tests/VQTest/VQTest.sg @@ -0,0 +1,96 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// + +using System; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Channels; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications { + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal Parameters(); + + internal int AppMain() { + Test.AppMain(this); + return 0; + } + } + + class Test { + + const int NUM = 21; + + internal static void AppMain(Parameters! config) { + + VectorQueue vq1 = new VectorQueue(); + VectorQueue vq2 = new VectorQueue(); + + for (int i=0; i<=Test.NUM; i++) { + int[] in ExHeap v = new[ExHeap] int[i]; + vq1.AddTail(v); + } + + Console.WriteLine("0..{0}", Test.NUM); + + while (!vq1.Empty) { + int[] in ExHeap v = (!)vq1.ExtractHead(); + Console.Write(" {0}", v.Length); + vq2.AddHead(v); + } + + Console.WriteLine(); + Console.WriteLine("{0}..0", Test.NUM); + + while (!vq2.Empty) { + int[] in ExHeap v = (!)vq2.ExtractHead(); + Console.Write(" {0}", v.Length); + vq1.AddTail(v); + } + + Console.WriteLine(); + Console.WriteLine("0..{0}", Test.NUM); + + while (!vq1.Empty) { + int[] in ExHeap v = (!)vq1.ExtractTail(); + Console.Write(" {0}", v.Length); + vq2.AddHead(v); + } + + Console.WriteLine(); + Console.WriteLine("0..{0}", Test.NUM); + + while (!vq2.Empty) { + int[] in ExHeap v = (!)vq2.ExtractTail(); + Console.Write(" {0}", v.Length); + delete v; + } + + TContainer> tc1 = new TContainer>(vq1); + + vq2.Dispose(); + + ThrowAway(tc1); + } + + private static void ThrowAway(TContainer>! tc) { + + VectorQueue vq = tc.Acquire(); + + vq.Dispose(); + } + } +} diff --git a/base/Applications/Tests/Varargs/Varargs.csproj b/base/Applications/Tests/Varargs/Varargs.csproj new file mode 100644 index 0000000..fb263b6 --- /dev/null +++ b/base/Applications/Tests/Varargs/Varargs.csproj @@ -0,0 +1,25 @@ + + + + + + + Exe + Varargs + + + + + + + + + diff --git a/base/Applications/Tests/Varargs/Varargs.sg b/base/Applications/Tests/Varargs/Varargs.sg new file mode 100644 index 0000000..d7f566a --- /dev/null +++ b/base/Applications/Tests/Varargs/Varargs.sg @@ -0,0 +1,105 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Varargs.sg +// +// Note: Test __arglist parameters +// +using System; +using System.Text; + +namespace Microsoft.Singularity.Applications +{ + public class Varargs + { + public static int Main(String[]! args) + { + string name = "VarArgs.x86"; + int len = 1; + int code = Printf("Invoked command with name '%s' and %d arguments", __arglist(name, len)); + Console.WriteLine("Varargs exiting."); + return code; + } + + public static int Printf(string! fmt, __arglist) { + return Decode(fmt, __arglist); + } + + public static int Decode(string! fmt, RuntimeArgumentHandle art) { + + StringBuilder sb = new StringBuilder(); + ArgIterator ai = new ArgIterator(art); + + int length = fmt.Length; + for (int index = 0; index < length; index++) { + + char c = fmt[index]; + + if (c == '%') { + index++; + if (index < length) { + c = fmt[index]; + switch (c) { + case '%': + sb.Append('%'); + break; + case 's': + if (ai.GetRemainingCount() > 0) { + TypedReference tr = ai.GetNextArg(); + Type t = __reftype(tr); + if (t == typeof(string)) { + string s = __refvalue(tr, string); + sb.Append(s); + } + else { + Console.WriteLine("Invalid argument for %s: {0}", t.ToString()); + return 1; + } + } + else { + Console.WriteLine("Insufficient number of arguments for %s"); + return 1; + } + break; + + case 'd': + if (ai.GetRemainingCount() > 0) { + TypedReference tr = ai.GetNextArg(); + Type t = __reftype(tr); + if (t == typeof(int)) { + int i = __refvalue(tr, int); + sb.Append(i.ToString()); + } + else { + Console.WriteLine("Invalid argument for %i: {0}", t.ToString()); + return 1; + } + } + else { + Console.WriteLine("Insufficient number of arguments for %i"); + return 1; + } + break; + + default: + Console.WriteLine("Unknown format directive %{0}", c); + return 1; + } + } + else { + Console.WriteLine("Error in format: end of string after %"); + return -1; + } + } + else { + sb.Append(c); + } + } + Console.WriteLine(sb.ToString()); + return 0; + } + } +} diff --git a/base/Applications/Tests/Verify/Verify.cs b/base/Applications/Tests/Verify/Verify.cs new file mode 100644 index 0000000..d676e45 --- /dev/null +++ b/base/Applications/Tests/Verify/Verify.cs @@ -0,0 +1,47 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Verify.cs +// +// Note: Simple Singularity test program. +// +using System; + +using Microsoft.Singularity.Channels; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications { + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal Parameters(); + + internal int AppMain() { + return Verify.AppMain(this); + } + } + + public class Verify + { + //[ShellCommand("verify", "Run heap verification test")] + internal static int AppMain(Parameters! config) + { + GC.Verify(); + Console.WriteLine("Verification finished.\n"); + return 0; + } + } +} diff --git a/base/Applications/Tests/Verify/Verify.csproj b/base/Applications/Tests/Verify/Verify.csproj new file mode 100644 index 0000000..daee4e4 --- /dev/null +++ b/base/Applications/Tests/Verify/Verify.csproj @@ -0,0 +1,25 @@ + + + + + + + Exe + Verify + + + + + + + + + diff --git a/base/Applications/Tests/Wait/Wait.cs b/base/Applications/Tests/Wait/Wait.cs new file mode 100644 index 0000000..c7ecb18 --- /dev/null +++ b/base/Applications/Tests/Wait/Wait.cs @@ -0,0 +1,141 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Wait.cs +// +// Note: Simple Singularity test program. +// +using System; +using System.Threading; + +using Microsoft.Singularity.Channels; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications { + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal Parameters(); + + internal int AppMain() { + return Wait.AppMain(this); + } + } + + public class Wait + { + private static WaitHandle[]! handles; + private static AutoResetEvent! syncEvent1; + private static AutoResetEvent! syncEvent2; + + public static void WaitThread() + { + Console.WriteLine("[2] Waiting for [1]."); + syncEvent1.WaitOne(); + + syncEvent2.Set(); + + Console.WriteLine("[2] Acquiring mutex."); + ((!)handles[2]).WaitOne(); + + Console.WriteLine("[2] Releasing mutex."); + ((Mutex!) handles[2]).ReleaseMutex(); + + syncEvent2.Set(); + + Console.WriteLine("[2] Waiting for [1]."); + syncEvent1.WaitOne(); + + Console.WriteLine("[2] Setting 0."); + ((AutoResetEvent!) handles[0]).Set(); + + Console.WriteLine("[2] Waiting for [1]."); + syncEvent1.WaitOne(); + + Console.WriteLine("[2] Setting 1."); + ((ManualResetEvent!) handles[1]).Set(); + + Console.WriteLine("[2] Waiting for [1]."); + syncEvent1.WaitOne(); + + Console.WriteLine("[2] Setting 0."); + ((AutoResetEvent!) handles[0]).Set(); + + Console.WriteLine("[2] Yielding."); + + Console.WriteLine("[2] Setting 1."); + ((ManualResetEvent!) handles[1]).Set(); + + Console.WriteLine("[2] Done."); + } + + //[ShellCommand("wait", "Run wait any/all test")] + internal static int AppMain(Parameters! config) + { + AutoResetEvent auto = new AutoResetEvent(false); + ManualResetEvent manual = new ManualResetEvent(false); + Mutex mutex = new Mutex(); + + handles = new WaitHandle [3] { auto, manual, mutex }; + syncEvent1 = new AutoResetEvent(false); + syncEvent2 = new AutoResetEvent(false); + + Thread t1 = new Thread(new ThreadStart(WaitThread)); + t1.Start(); + + Console.WriteLine("[1] Waiting..."); + int i1 = WaitHandle.WaitAny(handles); + Console.WriteLine("[1] Got {0}! (Expected 2.)", i1); + + syncEvent1.Set(); + + Console.WriteLine("[1] Waiting for [2]."); + syncEvent2.WaitOne(); + + Console.WriteLine("[1] Releasing mutex."); + mutex.ReleaseMutex(); + + Console.WriteLine("[1] Waiting for [2]."); + syncEvent2.WaitOne(); + + handles = new WaitHandle [2] { auto, manual }; + + syncEvent1.Set(); + + Console.WriteLine("[1] Wait any..."); + int i2 = WaitHandle.WaitAny(handles); + Console.WriteLine("[1] Got {0}! (Expected 0.)", i2); + + syncEvent1.Set(); + + Console.WriteLine("[1] Wait any..."); + int i3 = WaitHandle.WaitAny(handles); + Console.WriteLine("[1] Got {0}! (Expected 1.)", i3); + + syncEvent1.Set(); + + Console.WriteLine("[1] Wait all..."); + foreach (WaitHandle! handle in handles) { + handle.WaitOne(); + } + Console.WriteLine("[1] Got all!"); + + Console.WriteLine("[1] Done!"); + return 0; + + } + } +} diff --git a/base/Applications/Tests/Wait/Wait.csproj b/base/Applications/Tests/Wait/Wait.csproj new file mode 100644 index 0000000..74c6707 --- /dev/null +++ b/base/Applications/Tests/Wait/Wait.csproj @@ -0,0 +1,25 @@ + + + + + + + Exe + Wait + + + + + + + + + diff --git a/base/Applications/Tests/WaitTest/WaitTest.cs b/base/Applications/Tests/WaitTest/WaitTest.cs new file mode 100644 index 0000000..4045917 --- /dev/null +++ b/base/Applications/Tests/WaitTest/WaitTest.cs @@ -0,0 +1,125 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: WaitTest.cs +// +// Note: Simple Singularity test program. +// +using System; +using System.Threading; +using Microsoft.Singularity.V1.Services; + +using Microsoft.Singularity.Channels; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications { + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + reflective internal Parameters(); + + internal int AppMain() { + return WaitTest.AppMain(this); + } + } + + public class WaitTest + { + //[ShellCommand("waittest", "Execute demo for non-infinite waiting")] + internal static int AppMain(Parameters! config) { + Console.WriteLine("Testing float and threads."); + Console.Write("Still testing float and threads."); + Console.WriteLine(); + TestFloat(); + Thread t1 = new Thread(new ThreadStart(WaitThreadOne)); + Thread t2 = new Thread(new ThreadStart(WaitThreadTwo)); + + t1.Start(); + t2.Start(); + + Console.WriteLine("Main Thread sleeping 6 seconds for test completion"); +#if DEBUG_SLEEP + ulong u1 = Processor.CycleCount; +#endif + Thread.Sleep(TimeSpan.FromMilliseconds(6000)); +#if DEBUG_SLEEP + ulong u2 = Processor.CycleCount; +#endif + Console.WriteLine("Main Thread waking and exiting"); +#if DEBUG_SLEEP + Console.WriteLine(" u1 = {0,14}", u1); + Console.WriteLine(" u2 = {0,14}", u2); + Console.WriteLine(" u2-u1 = {0,14}", u2 - u1); + Console.WriteLine(" u2-u1 = {0,14} ms", ((u2 - u1) * 1000) / Processor.CyclesPerSecond); +#endif + + return 0; + } + + public static void TestFloat() + { + ulong v; + float f = (float)2.0; + v = BitConverter.SingleToUInt32Bits((float)1.0); + Console.WriteLine(" 1.0 {0:x16}", v); + v = BitConverter.SingleToUInt32Bits(f); + Console.WriteLine(" 2.0 {0:x16}", v); + v = BitConverter.SingleToUInt32Bits((float)10.0); + Console.WriteLine(" 10.0 {0:x16}", v); + v = BitConverter.DoubleToUInt64Bits(1.0); + Console.WriteLine(" 1.0 {0:x16}", v); + v = BitConverter.DoubleToUInt64Bits(f); + Console.WriteLine(" 2.0 {0:x16}", v); + v = BitConverter.DoubleToUInt64Bits(10.0); + Console.WriteLine(" 10.0 {0:x16}", v); + + if (f >= 1.0) { + Console.WriteLine(" f >= 1.0"); + } + if (f <= 10.0) { + Console.WriteLine(" f <= 10.0"); + } + } + + public static void WaitThreadOne() { + Console.WriteLine("Starting Wait Thread One"); + TestFloat(); + +#if DONT + Queue q = new Queue(); + Console.WriteLine("Queue: {0}\n", q); +#endif + + for(int i=0; i < 5; i++) { + Console.WriteLine("Thread One About To Sleep " + ProcessService.GetUpTime().Ticks); + Thread.Sleep(TimeSpan.FromMilliseconds(1000)); + Console.WriteLine("Thread One Waking Up " + ProcessService.GetUpTime().Ticks); + + } + Console.WriteLine("Wait Thread One Exiting"); + } + public static void WaitThreadTwo() { + Console.WriteLine("Starting Wait Thread Two"); + for(int i=0; i < 10; i++) { + Console.WriteLine("Thread Two About To Sleep " + ProcessService.GetUpTime().Ticks); + Thread.Sleep(TimeSpan.FromMilliseconds(30)); + Console.WriteLine("Thread Two Waking Up " + ProcessService.GetUpTime().Ticks); + + } + Console.WriteLine("Wait Thread Two Exiting"); + } + } +} diff --git a/base/Applications/Tests/WaitTest/WaitTest.csproj b/base/Applications/Tests/WaitTest/WaitTest.csproj new file mode 100644 index 0000000..210a00d --- /dev/null +++ b/base/Applications/Tests/WaitTest/WaitTest.csproj @@ -0,0 +1,25 @@ + + + + + + + Exe + WaitTest + + + + + + + + + diff --git a/base/Applications/TftpClient/TftpClient.csproj b/base/Applications/TftpClient/TftpClient.csproj new file mode 100644 index 0000000..63c607d --- /dev/null +++ b/base/Applications/TftpClient/TftpClient.csproj @@ -0,0 +1,33 @@ + + + + + + + + tftp + Exe + + + + + + + + + + + + + + + + + + + diff --git a/base/Applications/TftpClient/tftp.cs b/base/Applications/TftpClient/tftp.cs new file mode 100644 index 0000000..80d7210 --- /dev/null +++ b/base/Applications/TftpClient/tftp.cs @@ -0,0 +1,424 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: TftpClient.cs +// +// Note: +// + +using System; +using System.Net.Sockets; +using System.Net; +using System.Text; +using System.Threading; + +using Microsoft.Singularity; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.FileSystem; +using Microsoft.Singularity.V1.Services; + +using FileSystem.Utils; + +namespace Microsoft.Singularity.Applications +{ + internal enum TftpOpcode : ushort + { + RRQ=1, WRQ=2, DATA=3, ACK=4, ERROR=5 + }; + + internal struct TftpHdr + { + public TftpOpcode Opcode; + public ushort Arg; + + public TftpHdr(byte[]! buffer, int offset) + { + Opcode = (TftpOpcode)((ushort)buffer[offset+0] << 8 | buffer[offset+1]); + Arg = (ushort)((ushort)buffer[offset+2] << 8 | buffer[offset+3]); + // UnMarshal(buffer, offset); + } + public void Marshal(byte[]! buffer, int offset) + { + buffer[offset+0] = (byte)((ushort)Opcode>>8 & 0xff); + buffer[offset+1] = (byte)((ushort)Opcode>>0 & 0xff); + buffer[offset+2] = (byte)(Arg>>8 & 0xff); + buffer[offset+3] = (byte)(Arg>>0 & 0xff); + } + public void UnMarshal(byte[]! buffer, int offset) + { + Opcode = (TftpOpcode)((ushort)buffer[offset+0] << 8 | buffer[offset+1]); + Arg = (ushort)((ushort)buffer[offset+2] << 8 | buffer[offset+3]); + } + }; + + public class TftpClient + { + Socket! s; + + public TftpClient(IPAddress! server) + { + Socket s = this.s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + IPEndPoint ep = new System.Net.IPEndPoint(server, 69); + Console.Write("EP= {0}\n", ep); + // Connect here + s.Connect(ep); + } + + static int BuildRequest(byte[]! packet, TftpOpcode op, string! filename) + { + TftpHdr hdr = new TftpHdr(); + byte[] tmp; + + hdr.Opcode = op; + hdr.Marshal(packet, 0); + int off = 2; + tmp = Encoding.ASCII.GetBytes(filename); + tmp.CopyTo(packet, off); + off += tmp.Length; + packet[off++] = 0; + tmp = Encoding.ASCII.GetBytes("octet"); + tmp.CopyTo(packet, off); + off += tmp.Length; + packet[off++] = 0; + Console.WriteLine("Done"); + return off; + } + + public string Get(string! filename, string localName, bool verboseMode) + { + TftpHdr hdr = new TftpHdr(); + byte[] request; + byte[] reply = new byte[8192]; + int success; + FileContract.Imp persistHandle = null ; + long curPos = 0 ; + int len; + int rc; + + if (null != localName) + { + Console.WriteLine ("Creating file "+localName); + success = FileUtils.CreateFile(localName); + if (0 == success) { + persistHandle = FileUtils.OpenFile(localName); + if (null == persistHandle){ + Console.WriteLine("unable to open file " + localName); + return ""; + } + } + else { + Console.WriteLine("unable to create file " + localName); + return ""; + } + } + + request = new byte[4 + 512]; + + len = BuildRequest(request, TftpOpcode.RRQ, filename); + bool done = false; + hdr.UnMarshal(request, 0); + rc = s.Send(request, len, SocketFlags.None); + if (verboseMode) Console.WriteLine("Sent RRQ rc={0}", rc); + + byte []! in ExHeap buf = new[ExHeap] byte[512]; + //string str = null; + int count = 0; + int lastBlock = -1; + while (!done) + { + //Socket.Select(listenList, null, null, 1000); + if (s.Poll(1000000, SelectMode.SelectRead)) + { + rc = s.Receive(reply); + if (verboseMode) Console.WriteLine("Receive rc={0}", rc); + if (rc >= 4) + { + TftpHdr rh = new TftpHdr(reply, 0); + //Console.WriteLine("Opcode {0} Arg {1} rc={2} curPos={3}", rh.Opcode, rh.Arg, rc, curPos); + if (rh.Arg == lastBlock) + Console.WriteLine(" duplicate block? block ="+rh.Arg); + lastBlock = rh.Arg; + if (rh.Opcode == TftpOpcode.DATA) + { + if (!verboseMode) + { + Console.Write("."); + if (count++ > 50) + { + count = 0; + Console.Write("\n"); + } + } + else + { + //str = Encoding.ASCII.GetString(reply, 4, rc-4); + //Console.WriteLine("pos="+curPos+" str="+str); + //str = null; + } + if (persistHandle != null) + { + Bitter.FromByteArray(buf,0,rc-4,reply,4); + persistHandle.SendWrite(buf,0,curPos,rc-4); + switch receive + { + case persistHandle.AckWrite( _buf, bytesWritten, error) : + buf = _buf; + curPos = rh.Arg * 512; + break; + case persistHandle.ChannelClosed() : + Console.WriteLine("File handle closed. Quitting"); + delete persistHandle; + return null; + break; + case unsatisfiable: + Console.WriteLine("receive is unsatisfiable. Quitting"); + delete persistHandle; + return null; + break; + } + } + } + // Build new ack packet - acts as REQ for next block + hdr.Opcode = TftpOpcode.ACK; + hdr.Arg = rh.Arg; + hdr.Marshal(request, 0); + len = 4; + } + if (rc < 512+4) done = true; + } + else + { + //Console.WriteLine("poll for data failed!"); + //return null; + } + rc = s.Send(request, len, SocketFlags.None); + if (verboseMode)Console.WriteLine("Sent {0} {1} rc {2}", hdr.Opcode, hdr.Arg, rc); + //Thread.Sleep(1000); + } + if (persistHandle != null) + { + Console.WriteLine("Closing EP handle via delete"); + delete persistHandle; + } + delete buf; + return null; + } + + public string Put(string! filename, string localName) + { + TftpHdr hdr = new TftpHdr(); + byte[] request; + byte[] reply = new byte[8192]; + byte []! in ExHeap buf; + FileContract.Imp fileHandle = null ; + + int len; + int rc; + long fileLength =0; + NodeType nodeType; + ErrorCode errorOut; + + if (null != localName) + { + DirectoryServiceContract.Imp! rootNS = DirectoryService.NewClientEndpoint(); + bool ok = FileUtils.GetAttributes(localName, rootNS, out fileLength, out nodeType, out errorOut); + delete rootNS; + + if (!ok) + { + Console.WriteLine("Unable to open file ({0}) for send. reason:{1}", + localName, SdsUtils.ErrorCodeToString(errorOut) + ); + return null; + } + + fileHandle = FileUtils.OpenFile(localName); + if (null == fileHandle) + { + Console.WriteLine("Unable to open file "+localName+" for send"); + return null; + } + } + request = new byte[4 + 512]; + + len = BuildRequest(request, TftpOpcode.WRQ, filename); + int pos = 0; + bool done = false; + + rc = s.Send(request, len, SocketFlags.None); + Console.WriteLine("Sent WRQ rc={0}", rc); + + buf = new[ExHeap] byte[512]; + int threshold = 20; + int waitCount = 0; + Console.WriteLine(" file size =" + fileLength); + while (!done) + { + //Socket.Select(listenList, null, null, 1000); + if (s.Poll(100000, SelectMode.SelectRead)) + { + rc = s.Receive(reply); + Console.WriteLine("Receive rc={0}", rc); + if (rc >= 4) + { + TftpHdr rh = new TftpHdr(reply, 0); + Console.WriteLine("PUT: Opcode {0} Arg {1}", rh.Opcode, rh.Arg); + + if (rh.Opcode == TftpOpcode.ACK) + { + int datalen; + int error; + long bytesRead; + Console.WriteLine("ACK for block {0}, pos={1}", rh.Arg,pos); + waitCount = 0; + if (pos >= fileLength) + { + Console.WriteLine(" here"); + bytesRead = 0; + } + else + { + if (fileHandle == null) + throw new Exception("fileHandle is null when I want to SendRead"); + fileHandle.SendRead(buf, 0, pos, 512); + fileHandle.RecvAckRead(out buf, out bytesRead, out error); + if (error != 0) DebugStub.Break(); + + // If we get an ack we can send the next block + pos = (rh.Arg+1) * 512; + } + // Build new DATA packet + hdr.Opcode = TftpOpcode.DATA; + hdr.Arg = rh.Arg; + hdr.Arg++; + hdr.Marshal(request, 0); + datalen = Math.Min(512, (int)bytesRead); + if (datalen < 512) done = true; + //Encoding.ASCII.GetBytes(contents, pos, datalen, request, 4); + Bitter.ToByteArray(buf,0,datalen,request,4); + len = 4 + datalen; + } + else + { + Console.WriteLine("NOT AN ACK!\n"); + DebugStub.Break(); + } + } + rc = s.Send(request, len, SocketFlags.None); + Console.WriteLine("Sent {0} {1} rc {2}", hdr.Opcode, hdr.Arg, rc); + } + else + { + Console.WriteLine("Waiting."); + waitCount++; + if (waitCount > threshold) + { + Console.WriteLine (" exceeded timeout threshold"); + done = true; + break; + } + } + //Thread.Sleep(1000); + } + Console.WriteLine("Done"); + delete buf; + if (fileHandle != null) + delete fileHandle; + return null; + } + + private static IPAddress GetServerAddress(string server) + { + try + { + return IPAddress.Parse(server); + } + catch + {} + + try { + IPHostEntry he = Dns.GetHostByName(server); + return he.AddressList[0]; + } + catch + {} + return null; + } + + private static void Usage() + { + Console.WriteLine("Usage: tftpclient [-i] [ ]"); + } + + /// + /// The main entry point for the application. + /// + public static int Main(string[]! args) + { + bool verboseMode = false; + String localName, remoteName; + if (args.Length < 4 || args.Length > 6) + { + Usage(); + return 1; + } + + IPAddress server = GetServerAddress(args[1]); + if (server == null) + { + Console.WriteLine("Could not find server : {0}", args[1]); + return 2; + } + + int pos =2; + if (args[pos] == "-v") + { + verboseMode = true; + pos++; + } + + bool doGet; + switch (args[pos]) + { + case "get": + doGet = true; + break; + case "put": + doGet = false; + break; + default: + Usage(); + return -1; + } + pos++; + remoteName = (!)args[pos]; + pos++; + localName = null; + if (pos >= args.Length) + { + Console.WriteLine("no destination given"); + } + else + { + localName = args[pos]; + } + Console.WriteLine("doGet="+doGet+" src="+remoteName+" dest="+localName); + TftpClient tftpClient = new TftpClient(server); + if (doGet) + { + string contents = tftpClient.Get(remoteName,localName,verboseMode); + if (verboseMode) Console.WriteLine("Contents:\n{0}", contents); + } + else + { + //put + tftpClient.Put(remoteName,localName); + } + return 0; + } // end Main + } // end class TftpClient +} // end namespace Microsoft.Singularity.Shell diff --git a/base/Applications/Transforms/AppTransforms.csproj b/base/Applications/Transforms/AppTransforms.csproj new file mode 100644 index 0000000..be09bfa --- /dev/null +++ b/base/Applications/Transforms/AppTransforms.csproj @@ -0,0 +1,27 @@ + + + + + + + Library + ConsoleTransform + + + + + + + + + + + diff --git a/base/Applications/Transforms/ConsoleTransform.sg b/base/Applications/Transforms/ConsoleTransform.sg new file mode 100644 index 0000000..61355eb --- /dev/null +++ b/base/Applications/Transforms/ConsoleTransform.sg @@ -0,0 +1,167 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: DriverResourceTransform.sg +// +// Creates startup boilerplate code from Resource descriptions. +// + +using Microsoft.SingSharp; +using Microsoft.Contracts; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Extending; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Configuration; +using Microsoft.Singularity.V1.Services; +using System; + +namespace Microsoft.Singularity.Applications{ + + transform ApplicationResourceTransform + where $EndpointType : unmanaged struct, Endpoint, ITracked + where $EpAttr : EndpointAttribute + { + [ConsoleCategory(*, DefaultAction=true)] + internal class $DefaultCategory + { + // only match, don't implement + internal $DefaultCategory(); + + internal int AppMain(); + + // Single entry point + generate public static int Main(string[] args) { +#if SHOW_ARGS + if (args != null) { + foreach(string arg in args) { + DebugStub.WriteLine("startup argument '{0}'", __arglist(arg)); + } + } +#endif + if (args == null || args.Length < 2) { + $DefaultCategory config = new $DefaultCategory(); + return config.AppMain(); + } + + string action = args[1]; + forall (; $Action in $$NamedCategories ;) { + if ($Action.$name == action) { + $Action config = new $Action(); + return config.AppMain(); + } + } + throw new Exception(String.Format("Unrecognized action {0}", action)); + } + } + + [ConsoleCategory(*, Action=$name)] + internal class $$NamedCategories { + // only match, don't implement + internal $$NamedCategories(); + + internal int AppMain(); + } + + [ConsoleCategory(*)] + internal class $$Categories { + + [$EpAttr(*)] + TRef<$EndpointType,$State> $$endpoints; + + [StringParameter(*)] + string $$strings; + + [StringArrayParameter(*)] + string[] $$stringArrays; + + [LongParameter(*)] + long $$longs; + + [BoolParameter(*)] + bool $$bools; + + // [NotDelayed] + implement internal $$Categories() { + //DebugStub.WriteLine("ConsoleCategory action '{0}' applied", __arglist(this.GetType().ToString())); + + int index; + ParameterCode code; + + index = 0; + forall ( ; $s in $$strings ; ) { + string stringParam; + code = Process.GetStartupStringArg(index, out stringParam); + if (code != ParameterCode.Success) { + throw new ArgumentException(String.Format("error acquiring startup string array {0}. code={1}", index, code)); + } + this.$s = stringParam; + //DebugStub.WriteLine("got string {0}=({1})",__arglist(index, $s)); + ++index; + } + + index = 0; + forall ( ; $sa in $$stringArrays ; ) { + string[] stringArrayParam; + code = Process.GetStartupStringArrayArg(index, out stringArrayParam ); + if (code != ParameterCode.Success) { + throw new ArgumentException(String.Format("error acquiring startup string {0}. code={1}", index, code)); + } + this.$sa = stringArrayParam; + //DebugStub.WriteLine("got string {0}=({1})",__arglist(index, $s)); + ++index; + } + + index = 0; + forall ( ; $l in $$longs ; ) { + long longArg; + code = ProcessService.GetStartupLongArg(index, out longArg); + if (code != ParameterCode.Success) { + throw new ArgumentException(String.Format("error acquiring startup integer {0}. code={1}", index, code)); + } + this.$l = longArg; + //DebugStub.WriteLine("got long {0}=({1})",__arglist(index, $l)); + ++index; + } + + index = 0; + forall ( ; $b in $$bools ; ) { + bool b; + code = ProcessService.GetStartupBoolArg(index, out b); + if (code != ParameterCode.Success) { + throw new ArgumentException(String.Format("error acquiring startup bool {0}. code={1}", index, code)); + } + this.$b = b; + //DebugStub.WriteLine("got bool {0}=({1})",__arglist(index, b)); + ++index; + } + index = 0; + forall ( ; $e in $$endpoints; ){ + if ( index == 0 || index == 1) { + //DebugStub.WriteLine("transform skipping pipe at {0}",__arglist(index)); + } + else { + $e.$EndpointType* in ExHeap opt($e.$State) ep = Process.GetStartupEndpoint(index) + as $e.$EndpointType* in ExHeap opt($e.$State); + if (ep == null) { + throw new ArgumentException(String.Format("missing startup endpoint {0}", index)); + } + $e = new TRef<$e.$EndpointType, $e.$State> (ep); + //DebugStub.WriteLine("getting endpoint at {0}",__arglist(index)); + } + ++index; + + } + + } + + // Category specific entry point + internal int AppMain(); + + } + + } +} diff --git a/base/Applications/Transforms/WebAppTransform.sg b/base/Applications/Transforms/WebAppTransform.sg new file mode 100644 index 0000000..f2de8fe --- /dev/null +++ b/base/Applications/Transforms/WebAppTransform.sg @@ -0,0 +1,129 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: WebAppTransform.sg +// +// Creates startup boilerplate code from Resource descriptions for processes started by cassini. +// + +using Microsoft.SingSharp; +using Microsoft.Contracts; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Extending; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Configuration; +using Microsoft.Singularity.V1.Services; +using System; + +namespace Microsoft.Singularity.Applications{ + + transform WebAppResourceTransform + where $EndpointType : unmanaged struct, Endpoint, ITracked + { + [Category(*)] + class $Arguments { + + [Endpoint(*)] + TRef<$EndpointType,$State> $$endpoints; + + [StringParameter(_, _, _)] + string $$strings; + + [StringArrayParameter(_, _, _)] + string[] $$stringArrays; + + [LongParameter(_, _, _)] + long $$longs; + + [BoolParameter(_, _, _)] + bool $$bools; + + implement private $Arguments() { +#if DEBUG + DebugStub.WriteLine("WebAppTransform applied"); +#endif + + int index; + ParameterCode code; + + index = 0; + forall ( ; $s in $$strings ; ) { + string stringArg; + code = Process.GetStartupStringArg(index, out stringArg); + if (code != ParameterCode.Success) { + throw new ArgumentException(String.Format("error acquiring startup string array {0}. code={1}", index, code)); + } + this.$s = stringArg; + //DebugStub.WriteLine("got string {0}=({1})",__arglist(index, $s)); + ++index; + } + + index = 0; + forall ( ; $sa in $$stringArrays ; ) { + string[] stringArrayArg; + code = Process.GetStartupStringArrayArg(index, out stringArrayArg ); + if (code != ParameterCode.Success) { + throw new ArgumentException(String.Format("error acquiring startup string {0}. code={1}", index, code)); + } + this.$sa = stringArrayArg; + //DebugStub.WriteLine("got string {0}=({1})",__arglist(index, $s)); + ++index; + } + + index = 0; + forall ( ; $l in $$longs ; ) { + long longArg; + code = ProcessService.GetStartupLongArg(index, out longArg); + if (code != ParameterCode.Success) { + throw new ArgumentException(String.Format("error acquiring startup integer {0}. code={1}", index, code)); + } + this.$l = longArg; + //DebugStub.WriteLine("got long {0}=({1})",__arglist(index, $l)); + ++index; + } + + index = 0; + forall ( ; $b in $$bools ; ) { + bool b; + code = ProcessService.GetStartupBoolArg(index, out b); + if (code != ParameterCode.Success) { + throw new ArgumentException(String.Format("error acquiring startup bool {0}. code={1}", index, code)); + } + this.$b = b; + //DebugStub.WriteLine("got bool {0}=({1})",__arglist(index, b)); + ++index; + } + index = 0; + forall ( ; $e in $$endpoints; ){ + $e.$EndpointType* in ExHeap opt($e.$State) ep = Process.GetStartupEndpoint(index) + as $e.$EndpointType* in ExHeap opt($e.$State); + if (ep == null) { + throw new ArgumentException(String.Format("missing startup endpoint {0}", index)); + } + $e = new TRef<$e.$EndpointType, $e.$State> (ep); +#if DEBUG + DebugStub.WriteLine("getting endpoint at {0}",__arglist(index)); +#endif + ++index; + } + } + + generate public static int Main() { + $Arguments args = new $Arguments(); + + return $Application.AppMain(args); + } + + } + + class $Application { + + internal static int AppMain($Arguments! args); + + } + } +} diff --git a/base/Applications/TypeTest/TypeTest.cs b/base/Applications/TypeTest/TypeTest.cs new file mode 100644 index 0000000..20c668a --- /dev/null +++ b/base/Applications/TypeTest/TypeTest.cs @@ -0,0 +1,214 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: TypeTest.cs +// +// Note: Simple Singularity test program. +// +using Microsoft.Singularity.V1.Services; +using System; +using System.Runtime.CompilerServices; +using System.Threading; + +using Microsoft.SingSharp; + +using System.Reflection; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.Channels; + +using Microsoft.Singularity.Channels; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications { + [ConsoleCategory(DefaultAction=true)] + internal class Parameters { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [BoolParameter( "help", Default=false, HelpMessage="Display Extended help message.")] + internal bool doHelp; + + [StringParameter( "path", Position=0, Mandatory=true)] + internal string nsPath; + + [LongParameter( "contract", Position=1, Mandatory=true)] + internal long contractNum; + + reflective internal Parameters(); + + internal int AppMain() { + return TypeTest.AppMain(this); + } + } + + contract DummyContract : ServiceContract { + } + + rep struct TestStruct { + int x; + int y; + + public TestStruct(int a, int b) { x = a; y = b; } + } + + public class NS : ITracked { + + DirectoryServiceContract.Imp:Ready! ns; + + public NS() { + this.ns = DirectoryService.NewClientEndpoint(); + base(); + } + + public ServiceContract.Exp Bind(string! path, [Claims] ServiceContract.Exp! ep) + { + char[] in ExHeap p = Bitter.FromString2(path); + + expose (this) { + ns.SendBind(p, ep); + switch receive { + case ns.AckBind(): + return null; + + case ns.NakBind(reject, error): + return reject; + + case ns.ChannelClosed(): + throw new Exception("ns channel closed"); + } + } + } + + public void Dispose() { + delete this.ns; + } + + void ITracked.Expose() {} + void ITracked.UnExpose() {} + void ITracked.Acquire() {} + void ITracked.Release() {} + } + + public class TypeTest + { + internal static int AppMain(Parameters! config) + { + if (config.doHelp) { + Console.WriteLine("typetest contract-num"); + Console.WriteLine(" where contract-nums are:"); + Console.WriteLine(" 0 SoundDeviceContract"); + Console.WriteLine(" 1 DiskDeviceContract"); + Console.WriteLine(" 2 DummyContract"); + Console.WriteLine(" 3 Downcast Imp contract"); + return 1; + } + + int contractNum = (int) config.contractNum; + + NS ns = new NS(); + + string path = (!)config.nsPath; + Console.WriteLine("Trying to lookup {0} with contract {1}", path, contractNum); + + ServiceContract.Exp reject; + + switch (contractNum) { + case 0: + { + Console.WriteLine("Allocating SoundDevice Channel"); + SoundDeviceContract.Exp! exp; + SoundDeviceContract.Imp! imp; + SoundDeviceContract.NewChannel(out imp, out exp); + reject = ns.Bind(path, exp); + delete imp; + break; + } + case 1: + { + Console.WriteLine("Allocating DiskDevice Channel"); + DiskDeviceContract.Exp! exp; + DiskDeviceContract.Imp! imp; + DiskDeviceContract.NewChannel(out imp, out exp); + reject = ns.Bind(path, exp); + delete imp; + break; + } + case 2: + { + Console.WriteLine("Allocating Channel"); + DummyContract.Exp! exp; + DummyContract.Imp! imp; + DummyContract.NewChannel(out imp, out exp); + reject = ns.Bind(path, exp); + delete imp; + break; + } + case 3: + { + Console.WriteLine("Doing Imp cast test"); + DummyContract.Exp! exp; + DummyContract.Imp! imp; + DummyContract.NewChannel(out imp, out exp); + Endpoint! upcast = imp; + + DummyContract.Imp imp2 = upcast as DummyContract.Imp; + if (imp2 == null) { + Console.WriteLine("Downcast to Imp failed"); + } + else { + Console.WriteLine("Downcast to Imp succeeded"); + } + DiskDeviceContract.Imp imp3 = upcast as DiskDeviceContract.Imp; + if (imp3 == null) { + Console.WriteLine("Downcast to bad Imp failed (GOOD)"); + } + else { + Console.WriteLine("Downcast to bad Imp succeeded (BAD)"); + } + + DummyContract.Exp exp4 = upcast as DummyContract.Exp; + if (exp4 == null) { + Console.WriteLine("Downcast to Exp failed (GOOD)"); + } + else { + Console.WriteLine("Downcast to Exp succeeded (BAD)"); + } + delete exp; + delete imp; + reject = null; + break; + + } + default: + Console.WriteLine("Unsupported contract {0}", contractNum); + reject = null; + break; + } + + if (reject == null) { + Console.WriteLine("Bind succeeded!"); + } + else { + Console.WriteLine("Bind failed!"); + delete reject; + } + + ns.Dispose(); + + Console.WriteLine("TypeTest exiting."); + return 0; + } + } +} diff --git a/base/Applications/TypeTest/TypeTest.csproj b/base/Applications/TypeTest/TypeTest.csproj new file mode 100644 index 0000000..473bf0e --- /dev/null +++ b/base/Applications/TypeTest/TypeTest.csproj @@ -0,0 +1,22 @@ + + + + + + + + TypeTest + Exe + + + + + + + + diff --git a/base/Applications/Upfgen99/upfgen99.csproj b/base/Applications/Upfgen99/upfgen99.csproj new file mode 100644 index 0000000..5cf1946 --- /dev/null +++ b/base/Applications/Upfgen99/upfgen99.csproj @@ -0,0 +1,27 @@ + + + + + + + Exe + Upfgen99 + + + + + + + + + + + diff --git a/base/Applications/Upfgen99/upfgen99.sg b/base/Applications/Upfgen99/upfgen99.sg new file mode 100644 index 0000000..f7ed5aa --- /dev/null +++ b/base/Applications/Upfgen99/upfgen99.sg @@ -0,0 +1,467 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: upfgen.sg +// +// Note: +// Ported literally SpecWeb99 source code. +// +// Strongly avoid writing programs like this. +// +// This file compiles under CSC for testing on Windows and SGC +// on Singularity. + + +using System; +using System.IO; + +#if SINGULARITY + +using FileSystem.Utils; +using Microsoft.SingSharp; +using Microsoft.SingSharp.Runtime; +using Microsoft.Singularity; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using System.Text; +using Microsoft.Contracts; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +[assembly: Transform(typeof(ApplicationResourceTransform))] + +namespace Microsoft.Singularity.Applications +{ + [ConsoleCategory(HelpMessage="Generate files for Specweb. Output goes to directory/user.Personality", DefaultAction=true)] + internal class Parameters + { + [InputEndpoint("data")] + public readonly TRef Stdin; + + [OutputEndpoint("data")] + public readonly TRef Stdout; + + [LongParameter( "n", Mandatory=true, HelpMessage="Max Load")] + internal long maxLoad; + + [LongParameter( "t", Mandatory=true, HelpMessage="Number of Threads")] + internal long threads; + + [StringParameter( "c", Mandatory=true, HelpMessage="directory.")] + internal string directory; + + reflective internal Parameters(); + + internal int AppMain() { + UpfGen99.AppMain(this); + return 0; + } + } + + /////////////////////////////////////// + // Quick and dirty abstraction of file operations + ////////////////////////////////////// + + public class FILE + { + private TRef! connRef; + private long filePos; + private string! path; + + public static FILE CreateFile(string! path) + { + if (FileUtils.CreateFile(path) != 0) { + return null; + } + + return OpenFile(path); + } + + public static FILE OpenFile(string! path) + { + FileContract.Imp conn = FileUtils.OpenFile(path); + + if (conn != null) { + return new FILE(conn, path); + } + else { + return null; + } + } + + private FILE([Claims] FileContract.Imp:Ready! conn, string! thePath) + { + connRef = new TRef(conn); + filePos = 0; + path = thePath; + base(); + } + + public int Write(string! str) + { + byte[] bytes = Encoding.ASCII.GetBytes(str); + return Write(bytes, 0, bytes.Length); + } + + public int Write(byte[]! buf, int offset, int length) + { + FileContract.Imp conn = connRef.Acquire(); + byte[]! in ExHeap bytes = Bitter.FromByteArray(buf, offset, length); + + try { + long bytesWritten; + int error; + conn.SendWrite(bytes, 0, filePos, bytes.Length); + conn.RecvAckWrite(out bytes, out bytesWritten, out error); + delete bytes; + filePos += bytesWritten; + + if (error != 0) { + return 0; + } + } + finally { + connRef.Release(conn); + } + + return buf.Length; + } + + public int Read(byte[]! buf, int offset, int maxLength) + { + FileContract.Imp conn = connRef.Acquire(); + byte[]! in ExHeap bytes = new[ExHeap] byte[maxLength]; + + try { + long bytesRead; + int error; + conn.SendRead(bytes, 0, filePos, bytes.Length); + conn.RecvAckRead(out bytes, out bytesRead, out error); + + filePos += bytesRead; + + if (error != 0) { + delete bytes; + return 0; + } + + Bitter.ToByteArray(bytes, 0, maxLength, buf, offset); + delete bytes; + } + finally { + connRef.Release(conn); + } + + return buf.Length; + } + + public int Size + { + // TODO + get { + long size; + NodeType nodeType; + ErrorCode error; + + DirectoryServiceContract.Imp! rootNS = DirectoryService.NewClientEndpoint(); + bool ok = FileUtils.GetAttributes(path, rootNS, out size, out nodeType, out error); + delete rootNS; + + if (!ok) { + throw new Exception("Failed to get attributes"); + } else { + return unchecked((int)size); + } + } + } + + public void Close() + { + FileContract.Imp conn = connRef.Acquire(); + + try { + conn.SendClose(); + } + finally { + connRef.Release(conn); + } + } + } + + #else +namespace Microsoft.Singularity.Applications +{ + public class FILE + { + public static FILE CreateFile(string filename) + { + return (filename != null) ? new FILE() : null; + } + + public void Write(string msg) + { + Console.Write(msg); + } + + public void Close() + { + } + } + + #endif // SINGULARITY + + public class UpfGen99 + { + // Constants from client.h + private const int CADFILE_ENTRIES = 360; + private const string UserFile = "User.Personality"; + + private static void Usage() + { + Console.WriteLine("upfgen99 -C -n maxload -t "); + Console.WriteLine("All arguments are mandatory."); + Console.WriteLine("Output written to: /{0}", UserFile); + Console.WriteLine("NB better exist."); + } + +#if SINGULARITY + internal static void AppMain(Parameters! config) + { + + string /*!*/ directory = (!)config.directory; + int maxload = (int) config.maxLoad; // Unsigned in upfgen99.c + int maxthread = (int) config.threads; // Unsigned in upfgen99.c + + + if (maxthread <= 0) { + Usage(); + return; + } + + if (maxthread > maxload) { + maxload = maxthread; + } + + string path; + if (directory == "") { + path = UserFile; + } + else if (directory[directory.Length - 1] == '/') { + path = directory + UserFile; + } + else { + path = directory + "/" + UserFile; + } + + FILE file = FILE.CreateFile(path); + if (file == null) { + Console.WriteLine("Can't create file \"" + path + "\""); + return; + } + + // Cut-and-pasted from upfgen99.c + + for (int j = 0; j < maxload; j++ ) { + int k = ((j % CADFILE_ENTRIES) * 10000)%12301; + if ( k == 0) k = 12300; + int c4 = k & 0xf; + int c3 = (k >> 4) & 0xf; + int c2 = (k >> 8) & 0xf; + // int c1 = (k >> 12) & 0xf; // XXX: not used + + int gender = (k) % 2; + if ( gender == 1 ) gender = 0x20000000; + else gender = 0x10000000; + + int age = (k) % 4; + if ( age == 0 ) age = 0x08000000; + else if ( age == 1 ) age = 0x04000000; + else if ( age == 2 ) age = 0x02000000; + else if ( age == 3 ) age = 0x01000000; + + int area = (c4 + c2) % 4; + if ( area == 0 ) area = 0x00800000; + else if ( area == 1 ) area = 0x00400000; + else if ( area == 2 ) area = 0x00200000; + else if ( area == 3 ) area = 0x00100000; + + int interest1 = (c4 + c3) % 10; + if (interest1 == 0) interest1 = 0x00080000; + if (interest1 == 1) interest1 = 0x00040000; + if (interest1 == 2) interest1 = 0x00020000; + if (interest1 == 3) interest1 = 0x00010000; + if (interest1 == 4) interest1 = 0x00008000; + if (interest1 == 5) interest1 = 0x00004000; + if (interest1 == 6) interest1 = 0x00002000; + if (interest1 == 7) interest1 = 0x00001000; + if (interest1 == 8) interest1 = 0x00000800; + if (interest1 == 9) interest1 = 0x00000400; + + int interest2 = c4 % 10; + if (interest2 == 0) interest2 = 0x00000200; + else if (interest2 == 1) interest2 = 0x00000100; + else if (interest2 == 2) interest2 = 0x00000080; + else if (interest2 == 3) interest2 = 0x00000040; + else if (interest2 == 4) interest2 = 0x00000020; + else if (interest2 == 5) interest2 = 0x00000010; + else if (interest2 == 6) interest2 = 0x00000008; + else if (interest2 == 7) interest2 = 0x00000004; + else if (interest2 == 8) interest2 = 0x00000002; + else if (interest2 == 9) interest2 = 0x00000001; + + int combined = gender | age | area | interest1 | interest2; + + file.Write(String.Format("{0,5:d} {1,8:X}\n", j, combined)); + } + file.Close(); + } +#else + public static void Main(string[] /*!*/ args) + { + #if SINGULARITY + const int ArgsStart = 1; + #else + const int ArgsStart = 0; + #endif + + if (args == null || args.Length < (ArgsStart + 6)) { + Console.WriteLine("Expecting 6 arguments, got {0}.", + args.Length - ArgsStart); + Usage(); + return; + } + + string /*!*/ directory = ""; + int maxload = 0; // Unsigned in upfgen99.c + int maxthread = 0; // Unsigned in upfgen99.c + bool needHelp = false; + + int i; + for (i = ArgsStart; i < args.Length; i++) { + string /*!*/ arg = /*^ (!)^*/ args[i]; + if (arg.Length < 2 || (arg[0] != '-' && arg[0] != '/')) { + break; + } + + if (args.Length - i >= 2) { + string /*!*/ optArg = /*^ (!)^*/ args[++i]; + // Parameterized arguments + switch (Char.ToLower(arg[1])) { + case 'c': + directory = optArg; + break; + case 'n': + try { + maxload = Int32.Parse(optArg); + } + catch (Exception) { + Console.WriteLine("Invalid maxload: ", optArg); + return; + } + break; + case 't': + try { + maxthread = Int32.Parse(optArg); + } + catch (Exception) { + Console.WriteLine("Invalid maxthread: ", optArg); + return; + } + break; + } + } else { + // Flag arguments + needHelp = true; + } + } + + if (maxthread == 0 || needHelp == true) { + Usage(); + return; + } + + if (maxthread > maxload) { + maxload = maxthread; + } + + string path; + if (directory == "") { + path = UserFile; + } + else if (directory[directory.Length - 1] == '/') { + path = directory + UserFile; + } + else { + path = directory + "/" + UserFile; + } + + FILE file = FILE.CreateFile(path); + if (file == null) { + Console.WriteLine("Can't create file \"" + path + "\""); + return; + } + + // Cut-and-pasted from upfgen99.c + + for (int j = 0; j < maxload; j++ ) { + int k = ((j % CADFILE_ENTRIES) * 10000)%12301; + if ( k == 0) k = 12300; + int c4 = k & 0xf; + int c3 = (k >> 4) & 0xf; + int c2 = (k >> 8) & 0xf; + // int c1 = (k >> 12) & 0xf; // XXX: not used + + int gender = (k) % 2; + if ( gender == 1 ) gender = 0x20000000; + else gender = 0x10000000; + + int age = (k) % 4; + if ( age == 0 ) age = 0x08000000; + else if ( age == 1 ) age = 0x04000000; + else if ( age == 2 ) age = 0x02000000; + else if ( age == 3 ) age = 0x01000000; + + int area = (c4 + c2) % 4; + if ( area == 0 ) area = 0x00800000; + else if ( area == 1 ) area = 0x00400000; + else if ( area == 2 ) area = 0x00200000; + else if ( area == 3 ) area = 0x00100000; + + int interest1 = (c4 + c3) % 10; + if (interest1 == 0) interest1 = 0x00080000; + if (interest1 == 1) interest1 = 0x00040000; + if (interest1 == 2) interest1 = 0x00020000; + if (interest1 == 3) interest1 = 0x00010000; + if (interest1 == 4) interest1 = 0x00008000; + if (interest1 == 5) interest1 = 0x00004000; + if (interest1 == 6) interest1 = 0x00002000; + if (interest1 == 7) interest1 = 0x00001000; + if (interest1 == 8) interest1 = 0x00000800; + if (interest1 == 9) interest1 = 0x00000400; + + int interest2 = c4 % 10; + if (interest2 == 0) interest2 = 0x00000200; + else if (interest2 == 1) interest2 = 0x00000100; + else if (interest2 == 2) interest2 = 0x00000080; + else if (interest2 == 3) interest2 = 0x00000040; + else if (interest2 == 4) interest2 = 0x00000020; + else if (interest2 == 5) interest2 = 0x00000010; + else if (interest2 == 6) interest2 = 0x00000008; + else if (interest2 == 7) interest2 = 0x00000004; + else if (interest2 == 8) interest2 = 0x00000002; + else if (interest2 == 9) interest2 = 0x00000001; + + int combined = gender | age | area | interest1 | interest2; + + file.Write(String.Format("{0,5:d} {1,8:X}\n", j, combined)); + } + file.Close(); + } + +#endif + } +} diff --git a/base/Applications/WebApps/Browser/Browser.csproj b/base/Applications/WebApps/Browser/Browser.csproj new file mode 100644 index 0000000..ea65e15 --- /dev/null +++ b/base/Applications/WebApps/Browser/Browser.csproj @@ -0,0 +1,32 @@ + + + + + + + Exe + BrowserWebApp + true + + + + + + + + + + + + + + + diff --git a/base/Applications/WebApps/Browser/Browser.sg b/base/Applications/WebApps/Browser/Browser.sg new file mode 100644 index 0000000..5b01537 --- /dev/null +++ b/base/Applications/WebApps/Browser/Browser.sg @@ -0,0 +1,106 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Browser.sg +// +// Note: The Browser web app (serves files and supports browsing) +// + +using System; +using System.Collections; +using System.Diagnostics; +using Microsoft.SingSharp; +using Microsoft.SingSharp.Runtime; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.WebApps; +using Microsoft.Singularity.WebApps.Contracts; +using System.Text; +using System.Web; +using FileSystem.Utils; + +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +[assembly: Transform(typeof(WebAppResourceTransform))] + +namespace Microsoft.Singularity.WebApps +{ + [Category("WebApp")] + internal sealed class Parameters + { + [Endpoint] + public readonly TRef webAppRef; + + [StringParameter( "prefix", Position=0, Default=null, HelpMessage="prefix")] + internal string prefix; + + reflective private Parameters(); + } + + public class BrowserWebApp : IWebApp + { + private string pathPrefix = null; + private TRef! epNS; + + public BrowserWebApp(string prefix) + { + pathPrefix = prefix; + epNS = new TRef(DirectoryService.NewClientEndpoint()); + } + + public void ProcessRequest(IHttpRequest! request) + { + // The Singularity WebServer uses QueryStrings to express the file to be + // browsed. But Cassini uses the UriPath. (In the Singularity WebServer, + // the UriPath indicates which application should service the request). + // Try to support both conventions: + string uri = request.GetQueryString(); + + if ((uri == null) || (uri.Length == 0)) { + uri = request.GetUriPath(); + if ((uri == null) || (uri.Length == 0)) { + uri = "/"; + } + } + + if (pathPrefix != null) { + uri = pathPrefix + uri; + } + + DirectoryServiceContract.Imp:Ready! nsImp = epNS.Acquire(); + + try { + WebAppFSUtils.ServeFSPath(uri, request, nsImp); + } + finally { + epNS.Release(nsImp); + } + } + + // ====================================================== + // The code below gets used when this webapp is compiled + // to a stand-alone executable + internal static int AppMain(Parameters! config) + { + WebAppContract.Exp conn = (config.webAppRef).Acquire(); + if (conn == null) { + // Wrong contract type! + return -1; + } + + conn.SendWebAppReady(); + + string prefix = config.prefix; + + BrowserWebApp webApp = new BrowserWebApp(prefix); + Driver.ServiceChannel(webApp, conn); + delete conn; + return 0; + } + } +} diff --git a/base/Applications/WebApps/Diagnostics/Diagnostics.sg b/base/Applications/WebApps/Diagnostics/Diagnostics.sg new file mode 100644 index 0000000..094900a --- /dev/null +++ b/base/Applications/WebApps/Diagnostics/Diagnostics.sg @@ -0,0 +1,579 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// Microsoft Research Singularity +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// File: Diagnostics.sg +// +// Note: The Singularity Diagnostics web application +// + +using Microsoft.SingSharp; +using Microsoft.SingSharp.Runtime; +using Microsoft.Singularity.Diagnostics.Contracts; +using Microsoft.Singularity.Channels; +using Microsoft.Singularity.Directory; +using Microsoft.Singularity.WebApps; +using Microsoft.Singularity.WebApps.Contracts; +using Microsoft.Singularity.PingPong.Contracts; +using System; +using System.Collections; +using System.Diagnostics; +using System.Text; +using System.Web; + +using Microsoft.Singularity.Io; +using Microsoft.Singularity.Configuration; +using Microsoft.SingSharp.Reflection; +using Microsoft.Singularity.Applications; +[assembly: Transform(typeof(WebAppResourceTransform))] + +namespace Microsoft.Singularity.WebApps +{ + [Category("WebApp")] + internal sealed class Parameters + { + [Endpoint] + public readonly TRef webAppRef; + +#if false + [Endpoint] + public readonly TRef nsRef; +#endif + reflective private Parameters(); + } + + public class DiagnosticsWebApp : IWebApp + { + private TRef m_ChanConn; + private TRef m_ProcConn; + private TRef m_MemConn; + private TRef m_PingConn; + + private class ProcPairInfo + { + public int numChannels; + public int numMessages; + } + + private Hashtable m_ProcPairInfoTable; // State from the last snapshot + + public DiagnosticsWebApp() + { + ChannelContract.Imp! impChanConn; + ChannelContract.Exp! expChanConn; + ChannelContract.NewChannel(out impChanConn, out expChanConn); + + ProcessContract.Imp! impProcConn; + ProcessContract.Exp! expProcConn; + ProcessContract.NewChannel(out impProcConn, out expProcConn); + + MemoryContract.Imp! impMemConn; + MemoryContract.Exp! expMemConn; + MemoryContract.NewChannel(out impMemConn, out expMemConn); + + DirectoryServiceContract.Imp epNS = DirectoryService.NewClientEndpoint(); + + try + { + // Look up the general Diagnostics contract (this will go away!) + epNS.SendBind(Bitter.FromString2(ChannelContract.ModuleName), expChanConn); + switch receive + { + case epNS.NakBind(ServiceContract.Exp:Start rejectedEP, error) : + delete impChanConn; + delete rejectedEP; + break; + + case epNS.AckBind() : + impChanConn.RecvReady(); + m_ChanConn = new TRef(impChanConn); + // success + break; + + case epNS.ChannelClosed() : + throw new Exception("epNS channel closed"); + } + + // Look up the specific diagnostic modules we need + epNS.SendBind(Bitter.FromString2(ProcessContract.ModuleName), expProcConn); + + switch receive + { + case epNS.NakBind(ServiceContract.Exp:Start rejectedEP, error) : + delete impProcConn; + delete rejectedEP; + break; + + case epNS.AckBind() : + impProcConn.RecvReady(); + m_ProcConn = new TRef(impProcConn); + // success + break; + + case epNS.ChannelClosed() : + throw new Exception("epNS channel closed"); + } + + epNS.SendBind(Bitter.FromString2(MemoryContract.ModuleName), expMemConn); + + switch receive + { + case epNS.NakBind(ServiceContract.Exp:Start rejectedEP, error) : + delete impMemConn; + delete rejectedEP; + break; + + case epNS.AckBind() : + impMemConn.RecvReady(); + m_MemConn = new TRef(impMemConn); + // success + break; + + case epNS.ChannelClosed() : + throw new Exception("epNS channel closed"); + } + } + finally + { + delete epNS; + } + + // Spawn the Ping child process so we can do simulated IPC bursts + PingContract.Imp! childImp; + PingContract.Exp! childExp; + PingContract.NewChannel(out childImp, out childExp); + + string[] args = new string[1]; + args[0] = "ChildPing.x86"; + Process child = new Process(args, (Endpoint * in ExHeap)childExp); + child.Start(); + + childImp.RecvPingReady(); + childImp.SendStartPingPong(1); + m_PingConn = new TRef(childImp); + } + + public void ProcessRequest(IHttpRequest! request) + { + if (m_ChanConn == null) + { + ReportInternalError(request, "No channel to the channel diagnostic module"); + } + else if (m_ProcConn == null) + { + ReportInternalError(request, "No channel to the process diagnostic module"); + } + else if (m_MemConn == null) + { + ReportInternalError(request, "No channel to the memory diagnostic module"); + } + else if (m_PingConn == null) + { + ReportInternalError(request, "No channel to the pingpong child apps"); + } + else + { + ChannelContract.Imp impChanConn = m_ChanConn.Acquire(); + ProcessContract.Imp impProcConn = m_ProcConn.Acquire(); + MemoryContract.Imp impMemConn = m_MemConn.Acquire(); + PingContract.Imp impPingConn = m_PingConn.Acquire(); + + Console.Write("1"); + + try + { + string uri = request.GetUriPath(); + + if (uri.EndsWith("diagram.png")) + { + // Serve the image + request.SendStatus(200, "OK"); + request.SendHeader("Content-type", "image/jpeg"); + request.SendBodyData(DiagnosticImage.ImageData); + } + else if (uri.IndexOf("pingpong") > 0) + { + Console.Write("2"); + + string queryString = request.GetQueryString(); + int numReps = 10000; + + if (queryString != null) + { + string paramPreamble = "numreps="; + int preambleIndex = queryString.IndexOf(paramPreamble); + + if (preambleIndex != -1) + { + int nextParamIndex = queryString.IndexOf(';', preambleIndex); + string numRepsStr; + int start = preambleIndex + paramPreamble.Length; + + if (nextParamIndex == -1) + { + numRepsStr = queryString.Substring(start); + } + else + { + numRepsStr = queryString.Substring(start, nextParamIndex - start); + } + + numReps = Int32.Parse(numRepsStr); + } + } + + // Start the ping-pong exchange + impPingConn.RecvDone(); + impPingConn.SendStartPingPong(numReps); + + // Serve the reply + request.SendStatus(200, "OK"); + request.SendHeader("Content-type", "text/plain"); + request.SendBodyData(Encoding.ASCII.GetBytes("Started " + numReps + " ping-pong exchanges.")); + } + else if (uri.IndexOf("dumpheap") > 0) + { + Console.Write("4"); + ServeHeapDump(impMemConn, request); + } + else + { + Console.Write("<"); + ServeMasterPage(impChanConn, impProcConn, impMemConn, request); + Console.Write(">"); + } + + } + catch(Exception e) + { + ReportInternalError(request, "Caught an exception: " + e); + } + finally + { + m_PingConn.Release(impPingConn); + m_MemConn.Release(impMemConn); + m_ProcConn.Release(impProcConn); + m_ChanConn.Release(impChanConn); + } + } + + request.Done(); + } + + + private void ServeMasterPage(ChannelContract.Imp:ReadyState! impChanConn, + ProcessContract.Imp:ReadyState! impProcConn, + MemoryContract.Imp:ReadyState! impMemConn, + IHttpRequest! request) + { + // Serve the master page + + // ----------------------------------------------- + // First, get all our data in order. + long maxMemory, usedMemory, freeMemory; + long totalCommBlocks, totalCommBytes; + + Console.Write("3"); + impMemConn.SendGetFreeMemory(); + Console.Write("a"); + impMemConn.RecvMemory(out freeMemory); + Console.Write("b"); + impMemConn.SendGetUsedMemory(); + Console.Write("c"); + impMemConn.RecvMemory(out usedMemory); + Console.Write("d"); + impMemConn.SendGetMaxMemory(); + Console.Write("e"); + impMemConn.RecvMemory(out maxMemory); + Console.Write("f"); + impMemConn.SendTotalUsedCommunicationHeap(); + Console.Write("g"); + impMemConn.RecvBlocksAndTotal(out totalCommBlocks, out totalCommBytes); + Console.Write("4"); + + // This structure hashes process 2-tuples to the + // ProcPairInfo structure. The key + // is "procA:procB", using the process names, + // with the lower-ID process on the left. + Hashtable procPairTable = new Hashtable(); + + // This table lets us look up process names + Hashtable procNames = new Hashtable(); + + // Fill in the name table + int[]! in ExHeap procIDs; + impProcConn.SendGetProcessIDs(); + impProcConn.RecvProcessIDs(out procIDs); + Console.Write("5"); + + try + { + for (int i = 0; i < procIDs.Length; ++i) + { + impProcConn.SendGetProcessName(procIDs[i]); + + switch receive + { + case impProcConn.NotFound() : + // Do nothing; go to the next ID + break; + + case impProcConn.ProcessName(char[]! in ExHeap procName) : + // Drop the name into the table + int procID = procIDs[i]; + string valCopy = Bitter.ToString(procName); + delete procName; + procNames[procID] = valCopy; + break; + + case impProcConn.ChannelClosed(): + throw new Exception("impProcConn channel closed"); + } + } + } + finally + { + delete procIDs; + } + Console.Write("6"); + + // Now fill in the table of channels + ChannelInfo[]! in ExHeap channels; + impChanConn.SendGetChannels(); + impChanConn.RecvChannels(out channels); + Console.Write("7"); + + try + { + for (int i = 0; i < channels.Length; i++) + { + int leftProcID, rightProcID; + string leftProcName, rightProcName; + + // Ignore loop channels for now + if (channels[i].ImpProcessId != channels[i].ExpProcessId) + { + if (channels[i].ImpProcessId < channels[i].ExpProcessId) + { + leftProcID = channels[i].ImpProcessId; + rightProcID = channels[i].ExpProcessId; + } + else + { + leftProcID = channels[i].ExpProcessId; + rightProcID = channels[i].ImpProcessId; + } + + leftProcName = procNames[leftProcID] as string; + rightProcName = procNames[rightProcID] as string; + + if ((leftProcName != null) && (rightProcName != null)) + { + string compoundName = leftProcName + ":" + rightProcName; + ProcPairInfo pairInfo = procPairTable[compoundName] as ProcPairInfo; + + if (pairInfo == null) + { + pairInfo = new ProcPairInfo(); + } + + // Add to the list of channels between these processes + pairInfo.numChannels++; + pairInfo.numMessages += channels[i].MessagesDeliveredToExp + channels[i].MessagesDeliveredToImp; + procPairTable[compoundName] = pairInfo; + } + } + } + } + finally + { + // This is done below, where we dump the channels; uncomment this if we get rid of that HTML. + //delete channels; + } + Console.Write("8"); + + // ----------------------------------------------- + // Now generate the page. + request.SendStatus(200, "OK"); + request.SendHeader("Content-type", "text/html"); + request.SendHeader("charset", "utf-8"); + + Console.Write("9"); + + // Serve up the canned page preamble. This leaves us in a ")); + + // + // Preserve some of the old-style HTML tables for now... + // + + // Send total amount of communication heap blocks and memory + request.SendBodyData(Encoding.ASCII.GetBytes("

Communication heap used

")); + request.SendBodyData(Encoding.ASCII.GetBytes("")); + request.SendBodyData(Encoding.ASCII.GetBytes("")); + + request.SendBodyData(Encoding.ASCII.GetBytes("
Total blocks" + totalCommBlocks + "
Total bytes" + totalCommBytes + "
")); + + // Dump the table of processes with their names + request.SendBodyData(Encoding.ASCII.GetBytes("

Processes

")); + request.SendBodyData(Encoding.ASCII.GetBytes("")); + foreach (int procId in procNames.Keys) + { + string procName = (string)procNames[procId]; + request.SendBodyData(Encoding.ASCII.GetBytes("")); + } + request.SendBodyData(Encoding.ASCII.GetBytes("
PIDImage
" + procId + "" + procName + "
")); + + + // Dump the table of channels that exist at the moment + request.SendBodyData(Encoding.ASCII.GetBytes("

Channels

")); + request.SendBodyData(Encoding.ASCII.GetBytes("")); + + for (int i = 0; i < channels.Length; i++) + { + request.SendBodyData(Encoding.ASCII.GetBytes("")); + } + + // Don't forget this... + delete channels; + + request.SendBodyData(Encoding.ASCII.GetBytes("
CIDExp PIDImp PIDExp BytesImp Bytes
"+ + channels[i].ChannelId+ + ""+ + channels[i].ExpProcessId+ + ""+ + channels[i].ImpProcessId+ + ""+ + channels[i].MessagesDeliveredToExp+ + ""+ + channels[i].MessagesDeliveredToImp+ + "
")); + } + + private void ServeHeapDump(MemoryContract.Imp:ReadyState! impMemConn, + IHttpRequest! request) + { + request.SendStatus(200, "OK"); + request.SendHeader("Content-type", "text/html"); + request.SendHeader("charset", "utf-8"); + + request.SendBodyData(Encoding.ASCII.GetBytes("ExHeap dump

ExHeap Dump

")); + + Hashtable procCounts = new Hashtable(); + MemoryContract.BlockInfo[]! in ExHeap dump; + + impMemConn.SendDumpExHeap(); + impMemConn.RecvExHeapDump(out dump); + + for (int i = 0; i < dump.Length; i++) + { + string text = String.Format("", dump[i].ptrVal, dump[i].ownerProcID, dump[i].type, dump[i].size); + request.SendBodyData(Encoding.ASCII.GetBytes(text)); + object count = procCounts[dump[i].ownerProcID]; + + if (count == null) + { + procCounts[dump[i].ownerProcID] = 1; + } + else + { + procCounts[dump[i].ownerProcID] = ((int)count) + 1; + } + } + + delete dump; + + request.SendBodyData(Encoding.ASCII.GetBytes("
PtrPIDTypeSize
{0:x}{1}{2:x}{3}

Totals by ProcID

")); + + foreach (DictionaryEntry entry in procCounts) + { + request.SendBodyData(Encoding.ASCII.GetBytes("")); + } + + request.SendBodyData(Encoding.ASCII.GetBytes("
ProcIDTotal Blocks
" + entry.Key + "" + entry.Value + "
")); + } + + // ====================================================== + // The code below gets used when this webapp is compiled + // to a stand-alone executable + internal static int AppMain(Parameters! config) + { + //Endpoint * in ExHeap ep = Process.GetStartupEndpoint(0); + WebAppContract.Exp conn = (config.webAppRef).Acquire(); + if (conn == null) { + // Wrong contract type! + return -1; + } + + conn.SendWebAppReady(); + DiagnosticsWebApp webApp = new DiagnosticsWebApp(); + Driver.ServiceChannel(webApp, conn); + delete conn; + return 0; + } + + private void ReportInternalError(IHttpRequest! request, string! description) + { + request.SendStatus(500, "Internal Error"); + request.SendHeader("Content-type", "text/plain"); + request.SendHeader("charset", "utf-8"); + request.SendBodyData(Encoding.ASCII.GetBytes(description)); + } + + } +} diff --git a/base/Applications/WebApps/Diagnostics/DiagnosticsWebApp.csproj b/base/Applications/WebApps/Diagnostics/DiagnosticsWebApp.csproj new file mode 100644 index 0000000..6593ced --- /dev/null +++ b/base/Applications/WebApps/Diagnostics/DiagnosticsWebApp.csproj @@ -0,0 +1,44 @@ + + + + + + + Exe + DiagnosticsWebApp + true + + + + + + + DiagnosticImage + Microsoft.Singularity.WebApps + ImageData + + + + MasterPage + Microsoft.Singularity.WebApps + HTMLData + + + + + + + + + + + + diff --git a/base/Applications/WebApps/Diagnostics/MasterPage.htm b/base/Applications/WebApps/Diagnostics/MasterPage.htm new file mode 100644 index 0000000..476540a --- /dev/null +++ b/base/Applications/WebApps/Diagnostics/MasterPage.htm @@ -0,0 +1,161 @@ + + +Singularity Diagnostics + + + + + + + + +

IPC State

+
+ + + +
+ +
+ +

Memory State

+ + + + + + +