//////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: DeliveryImpl.cs // // Note: Abstract super-class of all channel delivery implementations // using System; using System.Runtime.CompilerServices; using Microsoft.Singularity; using Microsoft.Singularity.Memory; using Microsoft.Singularity.Security; namespace Microsoft.Singularity.Channels { using Microsoft.Singularity.V1.Types; using Microsoft.Singularity.V1.Security; using Microsoft.Singularity.V1.Services; using Microsoft.Singularity.V1.Threads; using Allocation = Microsoft.Singularity.Memory.SharedHeap.Allocation; using DelegationState = Microsoft.Singularity.Channels.EndpointCore.DelegationState; using System.Threading; [CLSCompliant(false)] public unsafe abstract class DeliveryImpl { //////////////////////////////////////////////////////////////////// // Class Fields // /// /// Allocation which holds the endpoint core associated with this /// delivery implementation /// protected Allocation* /*EndpointCore* opt(ExHeap)!*/ endpointAlloc; /// /// Endpoint core associated with this delivery implementation /// protected EndpointCore* endpoint; /// /// Handle to the owning Principal /// protected PrincipalHandle principalHandle; /// /// Delegation state to control delegation through the principal /// protected DelegationState delegationState; /// /// Contains the number of sends to this endpoint. /// protected int receiveCount; // // Shadow "trusted" shadow copies of the fields in endpointCore // /// /// Event on which sends are signaled to this endpoint. /// The handle is owned by the kernel, since the endpoint can move. /// The kernel deallocates the handle when the channel is deallocated. /// NOTE: stays valid until the entire channel gets collected. /// private AutoResetEventHandle shadowMessageEvent; /// /// Closed flag /// private bool shadowClosed; /// /// Contains the process id of the process currently owning this end of the /// channel. /// private int shadowProcessId; /// /// Contains the channelId (positive on the EXP endpoint, negative on the imp endpoint) /// private int shadowChannelId; /// /// Whether or not to marshall messages /// private bool shadowMarshall; //////////////////////////////////////////////////////////////////// // Class Methods // internal DeliveryImpl(Allocation* /*EndpointCore* opt(ExHeap)!*/ ep) { this.endpointAlloc = ep; this.endpoint = ((EndpointCore*)Allocation.GetData(ep)); // set default values (shadow cached values in EndpointCore if necessary) setMessageEvent(new AutoResetEventHandle( Process.kernelProcess.AllocateHandle(new AutoResetEvent(false)))); endpoint->CollectionEvent = new AutoResetEventHandle(); endpoint->SetCachedPeer(null); // set as null by default ProcessId = Thread.CurrentProcess.ProcessId; ChannelId = 0; // zero initially, corrected in connect Marshall = false; // false by default Closed = true; // opened in connect principalHandle = new PrincipalHandle(Thread.CurrentProcess.Principal.Val); delegationState = DelegationState.None; receiveCount = 0; } /// /// Closes this end of the channel and frees associated resources, /// EXCEPT the block of memory for this endpoint. It must be released /// by the caller. Sing# does this for the programmer. /// /// This runs in the kernel to avoid a race condition with Process.Stop /// internal bool Dispose() { if (this.Closed) { return false; } Close(); // mark our side closed before waking up peer NotifyPeer(); return true; } internal virtual void Connect(DeliveryImpl expDi, Allocation* /*EndpointCore* opt(ExHeap)!*/ securityEp) { // security principals are held in the delivery impl, not the endpoint core // since this allows them to be kept out of user memory in paging builds if (securityEp != null) { DeliveryImpl secImpl = EndpointCore.AllocationEndpointDeliveryImpl(securityEp); if (secImpl != null && secImpl.OwnerDelegationState == DelegationState.Mediated) { this.OwnerPrincipalHandle = secImpl.OwnerPrincipalHandle; } } int newChannelId = EndpointCore.GetNextChannelId(); this.ChannelId = -newChannelId; expDi.ChannelId = newChannelId; this.Closed = false; expDi.Closed = false; } /// /// Set this end to closed /// public abstract void Close(); /// /// Notify the owner of this endpoint that a message is ready. /// Notifies the set owner if this endpoint is part of a set. /// public void Notify() { this.receiveCount++; Tracing.Log(Tracing.Debug, "Endpoint Notify"); // NB: Cache the collection event to prevent // a race with the receiver. AutoResetEventHandle cached_collEvent = endpoint->CollectionEvent; if (cached_collEvent.id != UIntPtr.Zero) { AutoResetEventHandle.Set(cached_collEvent); } AutoResetEventHandle.Set(this.AreHandle); } private static SystemType EndpointCoreSystemType = typeof(Microsoft.Singularity.V1.Services.EndpointCore).GetSystemType(); /// /// Generic copy (either from kernel or to kernel) /// Determines if the thing we are moving is an endpoint and copies it accordingly. /// public static Allocation* MoveData(SharedHeap fromHeap, SharedHeap toHeap, Process newOwner, Allocation* data) { if (data == null) return data; if (!fromHeap.Validate(data)) { throw new ArgumentException("Bad argument. Not visible"); } // We can only transfer either into our out of the kernel's heap DebugStub.Assert(fromHeap == SharedHeap.KernelSharedHeap || toHeap == SharedHeap.KernelSharedHeap); if (SystemType.IsSubtype(data, EndpointCoreSystemType)) { // we have an endpoint DeliveryImpl di = EndpointCore.AllocationEndpointDeliveryImpl(data); return di.MoveEndpoint(fromHeap, toHeap, newOwner); } else { // we have a NON-endpoint // TODO FIX this! return null; // MoveNonEndpoint(fromHeap, toHeap, newOwner, data); } } internal void AcceptDelegation(DeliveryImpl expDi, DeliveryImpl epDi) { if (epDi.OwnerDelegationState == DelegationState.Mediated) { OwnerPrincipalHandle = epDi.OwnerPrincipalHandle; PeerPrincipalHandle = epDi.OwnerPrincipalHandle; } } internal void EnableDelegation(bool allowMediation) { if (allowMediation) OwnerDelegationState = DelegationState.ByMediation; else OwnerDelegationState = DelegationState.ByCapability; } // // Getters and setters for fields which are shadowed in EndpointCore // internal bool Closed { [NoHeapAllocation] get { return shadowClosed; } set { shadowClosed = value; endpoint->SetCachedClose(value); } } internal int ChannelId { [NoHeapAllocation] get { return shadowChannelId; } set { shadowChannelId = value; endpoint->SetCachedChannelId(value); } } internal int ProcessId { [NoHeapAllocation] get { return shadowProcessId; } set { shadowProcessId = value; endpoint->SetCachedProcessId(value); } } internal int ReceiveCount { [NoHeapAllocation] get { return receiveCount; } } internal bool Marshall { [NoHeapAllocation] get { return shadowMarshall; } set { shadowMarshall = value; endpoint->SetCachedMarshall(value); } } internal AutoResetEventHandle AreHandle { get { return shadowMessageEvent; } } internal SyncHandle MessageEvent { get { return shadowMessageEvent; } } public Allocation * /* EndpointCore */ EndpointAlloc { get { return endpointAlloc; } } private void setMessageEvent(AutoResetEventHandle value) { shadowMessageEvent = value; endpoint->SetCachedMessageEvent(value); } internal Allocation* Peer(out bool marshall) { marshall = Marshall; return Peer(); } internal EndpointCore.DelegationState OwnerDelegationState { [NoHeapAllocation] get { return delegationState; } set { delegationState = value; } } internal PrincipalHandle OwnerPrincipalHandle { [NoHeapAllocation] get { return principalHandle; } set { principalHandle = value; } } // // abstract methods which must be defined by actual delivery implementations // internal abstract void Initialize(DeliveryImpl peerDi); /// /// Return the associated peer of this endpoint /// [NoHeapAllocation] public abstract Allocation* Peer(); /// /// Move endpoint data to a new process /// internal abstract Allocation* MoveEndpoint(SharedHeap fromHeap, SharedHeap toHeap, Process newOwner); // // Move non endpoint data to a new process // //internal abstract Allocation* MoveNonEndpoint(SharedHeap fromHeap, // SharedHeap toHeap, // Process newOwner); /// /// Returns true if this delivery mechanism has been initialised and /// can be used for channel transport. /// internal abstract bool IsMechanismInitialized(); /// /// Returns the name of the delivery implementation actually being used /// internal abstract string GetImplName(); /// /// Notify the peer that a message is ready. /// internal abstract void NotifyPeer(); /// /// Close peer endpoint. /// internal abstract bool ClosePeer(); /// /// Is peer endpoint closed. /// internal abstract bool PeerClosed(); internal abstract int PeerProcessId { [NoHeapAllocation] get; } internal abstract int PeerReceiveCount { [NoHeapAllocation] get; } internal abstract PrincipalHandle PeerPrincipalHandle { [NoHeapAllocation] get; set; } //methods used for structures that contain pointers greater than one level deep internal abstract void BeginUpdate(byte* basep, byte* source, int* tagAddress, int msgSize); unsafe internal abstract void MarshallPointer(byte* basep, byte** target, SystemType type, byte* parent, int offset); /////////////////////////////////////////////////////////////////// } }