201 lines
7.6 KiB
Plaintext
201 lines
7.6 KiB
Plaintext
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Microsoft Research Singularity
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
// File: ChannelModule.sg
|
||
|
// Note: Channel diagnostic module
|
||
|
//
|
||
|
|
||
|
using System.Threading;
|
||
|
using Microsoft.SingSharp;
|
||
|
using Microsoft.Contracts;
|
||
|
using Microsoft.Singularity;
|
||
|
using Microsoft.Singularity.Memory;
|
||
|
using Microsoft.Singularity.Channels;
|
||
|
using Microsoft.Singularity.Diagnostics.Contracts;
|
||
|
using Microsoft.Singularity.Directory;
|
||
|
using System;
|
||
|
|
||
|
namespace Microsoft.Singularity.Diagnostics
|
||
|
{
|
||
|
using SystemType = Microsoft.Singularity.V1.Types.SystemType;
|
||
|
|
||
|
public class ChannelModule
|
||
|
{
|
||
|
private void Run()
|
||
|
{
|
||
|
// Here is the channel we use to communicate with
|
||
|
// the NameServer
|
||
|
ServiceProviderContract.Imp! nsImp;
|
||
|
ServiceProviderContract.Exp! nsExp;
|
||
|
ServiceProviderContract.NewChannel(out nsImp, out nsExp);
|
||
|
|
||
|
// Here is our NameServer connection over which we
|
||
|
// receive new client channels.
|
||
|
DirectoryServiceContract.Imp! epNS = DirectoryService.NewClientEndpoint();
|
||
|
|
||
|
try
|
||
|
{
|
||
|
epNS.SendRegister(Bitter.FromString2(ChannelContract.ModuleName), nsImp);
|
||
|
|
||
|
switch receive
|
||
|
{
|
||
|
case epNS.AckRegister() :
|
||
|
// All is well.
|
||
|
break;
|
||
|
|
||
|
case epNS.NakRegister(ServiceProviderContract.Imp:Start rejectedEP, ErrorCode error) :
|
||
|
// All is very much not well; abort.
|
||
|
DebugStub.Print("Failed to register the Channel Diagnostic module.\n");
|
||
|
if (rejectedEP != null) {
|
||
|
delete rejectedEP;
|
||
|
}
|
||
|
delete nsExp;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
delete epNS;
|
||
|
}
|
||
|
|
||
|
// Here is the set of client channels we service
|
||
|
ESet<ChannelContract.Exp:ReadyState> epSet = new ESet<ChannelContract.Exp:ReadyState>();
|
||
|
while(true)
|
||
|
{
|
||
|
switch receive
|
||
|
{
|
||
|
// ------------------------------- Requests for new connections
|
||
|
|
||
|
case nsExp.Connect(ServiceContract.Exp:Start! newEp) :
|
||
|
{
|
||
|
// We expect people top give us ChannelContract.Exp instances
|
||
|
ChannelContract.Exp newDiagEp = newEp as ChannelContract.Exp;
|
||
|
|
||
|
if (newDiagEp == null)
|
||
|
{
|
||
|
// Invalid contract type. Fail.
|
||
|
nsExp.SendNackConnect(newEp);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Signal ready and start servicing this contract
|
||
|
nsExp.SendAckConnect();
|
||
|
newDiagEp.SendReady();
|
||
|
epSet.Add(newDiagEp);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
// ------------------------------- Requests on existing connections
|
||
|
//
|
||
|
|
||
|
/// TODO: Move this to the Channel specific contract once we get there.
|
||
|
case ep.GetChannels() in epSet :
|
||
|
{
|
||
|
ChannelInfo[]! in ExHeap channels = ChannelModule.GetChannelInfo();
|
||
|
ep.SendChannels(channels);
|
||
|
epSet.Add(ep);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case ep.GetChannelStats() in epSet :
|
||
|
{
|
||
|
long msgs = PerfCounters.MsgsSent;
|
||
|
long bytes = PerfCounters.BytesSent;
|
||
|
long chan = PerfCounters.ChannelsCreated;
|
||
|
ep.SendChannelStats(msgs, bytes, chan);
|
||
|
epSet.Add(ep);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case ep.ChannelClosed() in epSet :
|
||
|
{
|
||
|
delete ep;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case epSet.Empty() && nsExp.ChannelClosed():
|
||
|
// Exit this thread
|
||
|
delete nsExp;
|
||
|
epSet.Dispose();
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private class ChannelInfoAccumulator
|
||
|
{
|
||
|
unsafe private ChannelInfo[]! in ExHeap infoVector;
|
||
|
private int used = 0;
|
||
|
|
||
|
[NotDelayed]
|
||
|
private ChannelInfoAccumulator()
|
||
|
{
|
||
|
this.infoVector = new[ExHeap] ChannelInfo[EndpointCore.OpenChannelCount];
|
||
|
base();
|
||
|
((!)SharedHeap.KernelSharedHeap).EndpointOwnerId.Iterate(
|
||
|
new SharedHeap.AllocationVisitor(this.Accumulate));
|
||
|
|
||
|
}
|
||
|
|
||
|
public static ChannelInfo[]! in ExHeap GetChannels() {
|
||
|
ChannelInfoAccumulator acc = new ChannelInfoAccumulator();
|
||
|
return acc.infoVector;
|
||
|
}
|
||
|
|
||
|
private unsafe void Accumulate(SharedHeap.Allocation* alloc)
|
||
|
{
|
||
|
SystemType endpointType = typeof(Endpoint).GetSystemType();
|
||
|
|
||
|
ChannelInfo[]! in ExHeap infoVector = this.infoVector;
|
||
|
|
||
|
if (SystemType.IsSubtype(alloc, endpointType))
|
||
|
{
|
||
|
unsafe {
|
||
|
// Note that we use Unchecked access here, since we don't
|
||
|
// actually own this data.
|
||
|
//
|
||
|
UIntPtr data = SharedHeap.Allocation.GetDataUnchecked(alloc);
|
||
|
EndpointCore*! ep = (!)(EndpointCore*)data;
|
||
|
int id = ep->ChannelId;
|
||
|
if (id > 0) {
|
||
|
int index = this.used++;
|
||
|
if (index >= infoVector.Length) {
|
||
|
// more channels materialized after we allocated vector
|
||
|
// skip the remaining ones
|
||
|
|
||
|
// suck back ownership
|
||
|
this.infoVector = infoVector;
|
||
|
return;
|
||
|
}
|
||
|
infoVector[index].ChannelId = id;
|
||
|
infoVector[index].ExpProcessId = ep->ProcessId;
|
||
|
infoVector[index].ImpProcessId = ep->PeerProcessId;
|
||
|
infoVector[index].MessagesDeliveredToExp = ep->ReceiveCount;
|
||
|
infoVector[index].MessagesDeliveredToImp = ep->PeerReceiveCount;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
public static ChannelInfo[]! in ExHeap GetChannelInfo() {
|
||
|
return ChannelInfoAccumulator.GetChannels();
|
||
|
}
|
||
|
|
||
|
internal static void Initialize()
|
||
|
{
|
||
|
ChannelModule module = new ChannelModule();
|
||
|
Thread thread = Thread.CreateThread(Thread.CurrentProcess,
|
||
|
new ThreadStart(module.Run));
|
||
|
if (thread != null) {
|
||
|
thread.Start();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|