348 lines
12 KiB
C#
348 lines
12 KiB
C#
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// 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<UnicodePipeContract.Exp:READY> Stdin;
|
||
|
|
||
|
[OutputEndpoint("data")]
|
||
|
public readonly TRef<UnicodePipeContract.Imp:READY> 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;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|