//////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity - Singularity ABI Shim // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: ChannelService.cs // // Note: // using System; using System.Runtime.CompilerServices; using Microsoft.Singularity; using Microsoft.Singularity.V1.Security; using Microsoft.Singularity.V1.Types; using Microsoft.Singularity.V1.Threads; namespace Microsoft.Singularity.V1.Services { using Allocation = SharedHeapService.Allocation; [CLSCompliant(false)] unsafe public struct EndpointCore { //////////////////////////////////////////////////////////////////// // Fields //////////////////////////////////////////////////////////////////// // // NOTE: The fields specified here must match those in: // Kernel/Singularity/Channels/EndpointCore.cs // Kernel/Singularity/V1/Services/ChannelServices.cs // Libraries/Singuarity.V1/Services/ChannelServices.cs /// /// Handle to the actual message delivery mechanism /// private DeliveryHandle deliveryHandle; /// /// Event handle in case this endpoint is part of a collection /// private AutoResetEventHandle collectionEvent; // // These "cached" fields are directly accessable by user programs, // but are not trusted by the kernel (as they could be modified by untrusted // code). The kernel relies on the trusted shadow copies held in the // deliveryImpl object, but updates these fields to reflect any changes to user // apps. // /// /// 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 cachedMessageEvent; /// /// Closed flag /// private bool cachedClosed; /// /// Contains the process id of the process currently owning this end of the /// channel. /// private int cachedOwnerProcessId; /// /// Contains the channelId (positive on the EXP endpoint, negative on the imp endpoint) /// private int cachedChannelId; /// /// Whether to marshall or not /// private bool cachedMarshall; /// /// Points to the peer endpoint /// private Allocation* /*EndpointCore* opt(ExHeap)*/ cachedPeer; /// /// If true then the peer state can be queried directly from cachedPeer /// private bool peerStateValid; //////////////////////////////////////////////////////////////////// // Methods //////////////////////////////////////////////////////////////////// /// /// Used to allocate a channel endpoint. The size must be correctly computed by /// the trusted caller (currently trusted code NewChannel) /// [OutsideGCDomain] [NoHeapAllocation] [StackBound(1024)] [MethodImpl(MethodImplOptions.InternalCall)] public static extern Allocation* //EndpointCore* opt(ExHeap)! Allocate(uint size, SystemType st); /// /// 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. /// Returns true for success, false for failure. /// [OutsideGCDomain] [NoHeapAllocation] [StackBound(1024)] [MethodImpl(MethodImplOptions.InternalCall)] public static extern bool Dispose(ref EndpointCore endpoint); /// /// Deallocates this end of the channel. If other end is also /// deallocated, the entire channel is deallocated. /// [OutsideGCDomain] [NoHeapAllocation] [StackBound(960)] [MethodImpl(MethodImplOptions.InternalCall)] public static extern void Free(Allocation* /* EndpointCore* opt(ExHeap) */ endpoint); /// /// Performs the initialization of the core part of each endpoint and cross links /// them to form a channel. /// public static void Connect( Allocation* /*EndpointCore* opt(ExHeap)!*/ imp, Allocation* /*EndpointCore* opt(ExHeap)!*/ exp) { Connect(imp, exp, null); } [OutsideGCDomain] [NoHeapAllocation] [StackBound(1024)] [MethodImpl(MethodImplOptions.InternalCall)] public static extern void Connect( Allocation* /*EndpointCore* opt(ExHeap)!*/ imp, Allocation* /*EndpointCore* opt(ExHeap)!*/ exp, Allocation* /*EndpointCore* opt(ExHeap) */ ep); /// /// Indicates if this endpoint is closed /// [NoHeapAllocation] public static bool Closed(ref EndpointCore ep) { return ep.cachedClosed; } [NoHeapAllocation] public static bool PeerClosed(ref EndpointCore ep) { if (ep.cachedPeer != null) { EndpointCore * peer = (EndpointCore*)SharedHeapService.GetData(ep.cachedPeer); return peer->cachedClosed; } else { return PeerClosedABI(ref ep); } } [OutsideGCDomain] [NoHeapAllocation] [StackBound(1024)] [MethodImpl(MethodImplOptions.InternalCall)] public static extern bool PeerClosedABI(ref EndpointCore ep); /// /// Set this end to closed /// [OutsideGCDomain] [NoHeapAllocation] [StackBound(1024)] [MethodImpl(MethodImplOptions.InternalCall)] public static extern void Close(ref EndpointCore ep); /// /// The endpoint to which this endpoint is connected. (non ABI call version) /// [NoHeapAllocation] public static Allocation* /*EndpointCore* opt(ExHeap) */ GetPeer(ref EndpointCore ep, out bool marshall) { if (ep.cachedPeer != null) { marshall = ep.cachedMarshall; return ep.cachedPeer; } else { return GetPeerABI(ref ep, out marshall); } } /// /// The endpoint to which this endpoint is connected. (ABI version if cached peer is /// not valid) /// [OutsideGCDomain] [NoHeapAllocation] [StackBound(1174)] [MethodImpl(MethodImplOptions.InternalCall)] public static extern Allocation* GetPeerABI(ref EndpointCore ep, out bool marshall); /// /// The event to wait for messages on this endpoint. Used by Select. /// [NoHeapAllocation] public static SyncHandle GetWaitHandle(ref EndpointCore ep) { return ep.cachedMessageEvent; } /// /// Notify the owner of this endpoint that a message is ready. /// Notifies the set owner if this endpoint is part of a set. /// [OutsideGCDomain] [NoHeapAllocation] [StackBound(1024)] [MethodImpl(MethodImplOptions.InternalCall)] public static extern void NotifyPeer(ref EndpointCore ep); /// /// Wait for a message to arrive on this endpoint. /// [NoHeapAllocation] public static void Wait(ref EndpointCore ep) { SyncHandle.WaitOne(ep.cachedMessageEvent); } /// /// Transfer the given Allocation block to the target endpoint /// [OutsideGCDomain] [NoHeapAllocation] [StackBound(128)] [MethodImpl(MethodImplOptions.InternalCall)] public static extern void TransferBlockOwnership(Allocation* ptr, ref EndpointCore target); /// /// Transfer any contents that needs to be adjusted from the transferee to the target /// endpoint. /// [OutsideGCDomain] [NoHeapAllocation] [StackBound(896)] [MethodImpl(MethodImplOptions.InternalCall)] public static extern void TransferContentOwnership( ref EndpointCore transferee, ref EndpointCore target); [NoHeapAllocation] public static int GetOwnerProcessID(ref EndpointCore ep) { return ep.cachedOwnerProcessId; } [NoHeapAllocation] public static int GetChannelID(ref EndpointCore ep) { return ep.cachedChannelId; } [NoHeapAllocation] public static int GetPeerProcessID(ref EndpointCore ep) { if (ep.peerStateValid) { EndpointCore * peer = (EndpointCore*)SharedHeapService.GetData(ep.cachedPeer); return peer->cachedOwnerProcessId; } else { return GetPeerProcessIDABI(ref ep); } } [OutsideGCDomain] [NoHeapAllocation] [StackBound(1024)] [MethodImpl(MethodImplOptions.InternalCall)] public static extern int GetPeerProcessIDABI(ref EndpointCore ep); [OutsideGCDomain] [NoHeapAllocation] [StackBound(1024)] [MethodImpl(MethodImplOptions.InternalCall)] public static extern void AcceptDelegation(Allocation* /*EndpointCore* opt(ExHeap)!*/ imp, Allocation* /*EndpointCore* opt(ExHeap)!*/ exp, Allocation* /*EndpointCore* opt(ExHeap)!*/ ep); [OutsideGCDomain] [NoHeapAllocation] [StackBound(1024)] [MethodImpl(MethodImplOptions.InternalCall)] public static extern void EnableDelegation(ref EndpointCore ep, bool allowMediation); [OutsideGCDomain] [NoHeapAllocation] [StackBound(1024)] [MethodImpl(MethodImplOptions.InternalCall)] public static extern PrincipalHandle GetOwnerPrincipalHandle(ref EndpointCore ep); [OutsideGCDomain] [NoHeapAllocation] [StackBound(1024)] [MethodImpl(MethodImplOptions.InternalCall)] public static extern PrincipalHandle GetPeerPrincipalHandle(ref EndpointCore ep); /// /// Instruct the selectable object to signal events on the given AutoResetEvent /// rather than its normal event in order to aggregate signalling into a set. /// A selectable object need only support being part of a single collection at /// any point in time. /// public static void LinkIntoCollection(ref EndpointCore ep, AutoResetEventHandle ev) { ep.collectionEvent = ev; } /// /// Instruct the selectable object to stop signalling events on the given /// AutoResetEvent. /// public static void UnlinkFromCollection(ref EndpointCore ep, AutoResetEventHandle ev) { ep.collectionEvent = new AutoResetEventHandle(); } /// /// Called when sending a message across domains. Instructs the kernel /// to prepare an update record to push into the peer when the peer /// is running. /// /// This call starts a sequence of MarshallPointer calls that will /// end with a call to NotifyPeer. /// [OutsideGCDomain] [NoHeapAllocation] [StackBound(1024)] [MethodImpl(MethodImplOptions.InternalCall)] unsafe public static extern void MarshallMessage(ref EndpointCore ep, byte* basep, byte* source, int* tagAddress, int size); [OutsideGCDomain] [NoHeapAllocation] [StackBound(1024)] [MethodImpl(MethodImplOptions.InternalCall)] unsafe public static extern void MarshallPointer(ref EndpointCore ep, byte* basep, byte** target, SystemType type, byte* parent, int offset); } }