/////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // 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; } } }