//////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: SingleAddrSpaceDelivery.cs // // Note: Standard single address space implementation of channel delivery // mechanism. // using System; using System.Threading; using System.Runtime.CompilerServices; using Microsoft.Singularity; using Microsoft.Singularity.V1.Threads; using Microsoft.Singularity.V1.Security; using Microsoft.Singularity.V1.Services; using Microsoft.Singularity.V1.Types; using Allocation = Microsoft.Singularity.Memory.SharedHeap.Allocation; using SharedHeap = Microsoft.Singularity.Memory.SharedHeap; using DelegationState = Microsoft.Singularity.Channels.EndpointCore.DelegationState; namespace Microsoft.Singularity.Channels { [CLSCompliant(false)] public unsafe sealed class SingleAddrSpaceDelivery: DeliveryImpl { public const string ImplName = "SingleAddrSpaceChannels"; private Allocation * /* EndpointCore */ peerEp; internal SingleAddrSpaceDelivery( Allocation* /*EndpointCore* opt(ExHeap)!*/ endpoint): base(endpoint) { } internal override void Initialize(DeliveryImpl peerDi) { peerEp = SharedHeap.CurrentProcessSharedHeap.Share(peerDi.EndpointAlloc, SharedHeap.CurrentProcessSharedHeap.EndpointPeerOwnerId, (UIntPtr)0, Allocation.GetSize(peerDi.EndpointAlloc)); this.endpoint->SetCachedPeer(peerEp); this.endpoint->SetPeerStateValid(true); } internal override void Connect(DeliveryImpl expDi, Allocation* /*EndpointCore* opt(ExHeap)!*/ securityEp) { base.Connect(expDi, securityEp); this.Initialize(expDi); expDi.Initialize(this); } public override void Close() { this.Closed = true; // clear the collectionEvent. // Needed in case we are called from the cleanup thread. this.endpoint->CollectionEvent = new AutoResetEventHandle(); } /// /// Explicitly frees this end of the channel. If other end is also /// freed, the channel is deallocated, meaning we have to deallocate /// the kernel handles for the auto reset events. /// Since both threads on the channel could try to do this simultaneously, /// we use the ref counting on the underlying endpoints to let the last /// free operation (the one pulling the ref count to 0) to free the associated /// event. /// internal static bool Free(SingleAddrSpaceDelivery dm) { Tracing.Log(Tracing.Debug, "Freeing endpoint {0:x8} of deliveryImpl type:" + ImplName, (UIntPtr)dm.endpointAlloc); bool isExp = (dm.endpoint->ChannelId > 0); bool peerFreed = false; bool meFreed = false; if (dm.Peer() != null) { // release our ref count on the peer peerFreed = TryFreeResources(dm.Peer(), SharedHeap.CurrentProcessSharedHeap.EndpointPeerOwnerId); } // release our endpoint meFreed = TryFreeResources(dm.endpointAlloc, SharedHeap.CurrentProcessSharedHeap.EndpointOwnerId); // our definition of freeing the channel is if we freed the exp // side return ((isExp && meFreed) || (!isExp && peerFreed)); } /// /// The peer thread might try this too, so we use the ref count of the /// underlying memory to allow only the last freeer to also free the /// associated auto-reset event handle. Make sure to grab the handle /// before freeing the endpoint. /// unsafe private static bool TryFreeResources( Allocation* /*EndpointCore*/ endpoint, SharedHeap.AllocationOwnerId ownerId) { EndpointCore* epData = (EndpointCore*)Allocation.GetDataUnchecked(endpoint); AutoResetEventHandle areHandle = epData->GetAreHandle(); DeliveryHandle dh = epData->dImpHandle; int channelId = epData->ChannelId; bool lastRefGone = SharedHeap.KernelSharedHeap.Free(endpoint, ownerId); if (lastRefGone) { if (dh != DeliveryHandle.Zero) { DeliveryHandle.Dispose(dh); } if (areHandle.id != UIntPtr.Zero) { Process.kernelProcess.ReleaseHandle(areHandle.id); } } return lastRefGone; } internal override Allocation* MoveEndpoint(SharedHeap fromHeap, SharedHeap toHeap, Process newOwner) { DebugStub.Assert(fromHeap == toHeap); // Careful about the order. // Since we don't know if this is a release (current process owns it) // or an acquire (current process does not necessarily own it), we // have to bypass the owner check here. int processId = newOwner.ProcessId; this.ProcessId = processId; this.OwnerPrincipalHandle = new PrincipalHandle(newOwner.Principal.Val); // Don't check for delegation here since this is for kernel calls on // moving endpoints to SIPs. Delegation should not be involved. // The following should not be necessary, but just in case: this.OwnerDelegationState = DelegationState.None; Allocation.SetOwnerProcessId(this.endpointAlloc, processId); Allocation.SetOwnerProcessId(this.peerEp, processId); Monitoring.Log(Monitoring.Provider.EndpointCore, (ushort)EndpointCoreEvent.TransferToProcess, 0, (uint)ChannelId, (uint)processId, 0, 0, 0); return this.endpointAlloc; } /// /// Notify the peer that a message is ready. /// internal override void NotifyPeer() { PeerImpl().Notify(); #if CHANNEL_COUNT //Interlocked.Increment(ref messageCount); PerfCounters.IncrementMsgsSent(); #endif } [NoHeapAllocation] public override Allocation* Peer() { return this.peerEp; } [NoHeapAllocation] private DeliveryImpl PeerImpl() { return EndpointCore.AllocationEndpointDeliveryImpl(Peer()); } /// /// Close peer endpoint. /// internal override bool ClosePeer() { PeerImpl().Close(); return true; } /// /// Is peer endpoint closed. /// internal override bool PeerClosed() { return PeerImpl().Closed; } internal override int PeerProcessId { [NoHeapAllocation] get { return PeerImpl().ProcessId; } } internal override int PeerReceiveCount { [NoHeapAllocation] get { return PeerImpl().ReceiveCount; } } internal override PrincipalHandle PeerPrincipalHandle { [NoHeapAllocation] get { return PeerImpl().OwnerPrincipalHandle; } set { PeerImpl().OwnerPrincipalHandle = value; } } internal override bool IsMechanismInitialized() { // is initialized at kernel start time return true; } //new versions for deep pointers internal override void BeginUpdate(byte* basep, byte* source, int* tagAddress, int msgSize) { return; } unsafe internal override void MarshallPointer(byte* basep, byte** target, SystemType type, byte* targetParent, int offset) { return; } internal override string GetImplName() { return ImplName; } } }