//////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity - Singularity ABI Implementation // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: EndpointCore.cs // // Note: // using System; using System.Threading; using System.Runtime.CompilerServices; using Microsoft.Singularity; using Microsoft.Singularity.Channels; using Microsoft.Singularity.Security; using Microsoft.Singularity.Memory; using Microsoft.Singularity.V1.Security; using Microsoft.Singularity.V1.Threads; using Microsoft.Singularity.V1.Types; namespace Microsoft.Singularity.V1.Services { using Allocation = SharedHeapService.Allocation; using EndpointCoreImplementation = Microsoft.Singularity.Channels.EndpointCore; [CLSCompliant(false)] public enum ChannelServiceEvent : ushort { TransferBlockOwnership = 1, TransferContentOwnership = 2, } [CLSCompliant(false)] unsafe public struct EndpointCore { #if !PAGING /// /// Flag indicating that the endpoint is closed. /// This gets set either by an explicit close, or when /// the kernel determines that the endpoint is not reachable. /// NOTE: A channel only goes away entirely, once both ends are closed! /// private volatile bool closed; /// /// The endpoint to which this endpoint is connected. /// private Allocation* /*EndpointCore* opt(ExHeap)*/ peer; /// /// 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 messageEvent; /// /// Event handle in case this endpoint is part of a collection /// private AutoResetEventHandle collectionEvent; /// /// Contains the process id of the process currently owning this end of the /// channel. /// private int ownerProcessId; /// /// Contains the principal handle of the process currently owning this end of the /// channel. /// private PrincipalHandle ownerPrincipalHandle; /// /// Contains the number of sends to this endpoint. /// private int receiveCount; /// /// Contains the channelId (positive on the EXP endpoint, negative on the imp endpoint) /// private int channelId; #else internal EndpointTrusted* id; #endif //PAGING /// /// Used to allocate a channel endpoint. The size must be correctly computed by /// the trusted caller (currently trusted code NewChannel) /// [ExternalEntryPoint] public static Allocation* /*EndpointCore* opt(ExHeap)!*/ Allocate(uint size, SystemType st) { Allocation* ep = (Allocation*) SharedHeap.CurrentProcessSharedHeap.Allocate( size, st.id, 0, SharedHeap.CurrentProcessSharedHeap.EndpointOwnerId); if (ep == null) { throw new ApplicationException("SharedHeap.Allocate returned null"); } return ep; } /// /// 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. /// [ExternalEntryPoint] public static bool Dispose(ref EndpointCore endpoint) { #if !PAGING fixed (EndpointCore* ep = &endpoint) { EndpointCoreImplementation* epimp = (EndpointCoreImplementation*)ep; return epimp->Dispose(); } #else try { EndpointCoreImplementation ep = new EndpointCoreImplementation(endpoint.id); EndpointCoreImplementation.Dispose(ref ep); return true; } catch(ApplicationException) { return false; } #endif //PAGING } /// /// Deallocates this end of the channel. If other end is also /// deallocated, the entire channel is deallocated. /// [ExternalEntryPoint] public static void Free(Allocation* /* EndpointCore* opt(ExHeap) */ endpoint) { EndpointCoreImplementation.Free((SharedHeap.Allocation*)endpoint); } /// /// Performs the initialization of the core part of each endpoint and cross links /// them to form a channel. /// [ExternalEntryPoint] public static void Connect( Allocation* /*EndpointCore* opt(ExHeap)!*/ imp, Allocation* /*EndpointCore* opt(ExHeap)!*/ exp) { EndpointCoreImplementation.Connect((SharedHeap.Allocation*)imp, (SharedHeap.Allocation*)exp); } /// /// Indicates if this endpoint is closed /// #if !PAGING [NoHeapAllocation] public static bool Closed(ref EndpointCore ep) { return ep.closed; } [NoHeapAllocation] public static bool PeerClosed(ref EndpointCore ep) { EndpointCore * peer = (EndpointCore*)SharedHeapService.GetData(ep.peer); return peer->closed; } #else [ExternalEntryPoint] public static bool Closed(ref EndpointCore ep) { return new EndpointCoreImplementation(ep.id).Closed(); } [ExternalEntryPoint] public static bool PeerClosed(ref EndpointCore ep) { return new EndpointCoreImplementation(ep.id).PeerClosed(); } #endif //PAGING /// /// Set this end to closed /// #if !PAGING public static void Close(ref EndpointCore ep) { ep.closed = true; } #else [ExternalEntryPoint] public static void Close(ref EndpointCore ep) { new EndpointCoreImplementation(ep.id).Close(); } #endif //PAGING /// /// The endpoint to which this endpoint is connected. /// #if !PAGING public static Allocation* /*EndpointCore* opt(ExHeap) */ GetPeer(ref EndpointCore ep, out bool marshall) { marshall = false; return ep.peer; } #else [ExternalEntryPoint] public static Allocation* /*EndpointCore* opt(ExHeap) */ GetPeer(ref EndpointCore ep, out bool marshall) { return (Allocation*)new EndpointCoreImplementation(ep.id).Peer(out marshall); } #endif //PAGING /// /// The event to wait for messages on this endpoint. Used by Select. /// #if !PAGING public static SyncHandle GetWaitHandle(ref EndpointCore ep) { return ep.messageEvent; } #else [ExternalEntryPoint] public static SyncHandle GetWaitHandle(ref EndpointCore ep) { return new EndpointCoreImplementation(ep.id).GetWaitHandle(); } #endif //PAGING /// /// Notify the owner of this endpoint that a message is ready. /// Notifies the set owner if this endpoint is part of a set. /// [ExternalEntryPoint] public static void NotifyPeer(ref EndpointCore endpoint) { #if !PAGING fixed (EndpointCore* ep = &endpoint) { EndpointCoreImplementation* epimp = (EndpointCoreImplementation*)ep; epimp->NotifyPeer(); } #else new EndpointCoreImplementation(endpoint.id).NotifyPeer(); #endif //PAGING } /// /// Wait for a message to arrive on this endpoint. /// #if !PAGING public static void Wait(ref EndpointCore ep) { SyncHandle.WaitOne(ep.messageEvent); } #else [ExternalEntryPoint] public static void Wait(ref EndpointCore ep) { SyncHandle.WaitOne(GetWaitHandle(ref ep)); } #endif //PAGING /// /// Transfer the given Allocation block to the target endpoint /// #if !PAGING [ExternalEntryPoint] public static void TransferBlockOwnership(Allocation* ptr, ref EndpointCore target) { Monitoring.Log(Monitoring.Provider.ChannelService, (ushort)ChannelServiceEvent.TransferBlockOwnership, 0, (uint)target.channelId, (uint)target.ownerProcessId, 0, 0, 0); SharedHeapService.SetOwnerProcessId(ptr, target.ownerProcessId); #if CHANNEL_COUNT EndpointCoreImplementation.IncreaseBytesSentCount((long)SharedHeapService.GetSize(ptr)); #endif } #else [ExternalEntryPoint] // TODO: change "ref EndpointCore" to "EndpointCore" public static void TransferBlockOwnership(Allocation* ptr, ref EndpointCore target) { EndpointCoreImplementation ep = new EndpointCoreImplementation(target.id); EndpointCoreImplementation.TransferBlockOwnership((SharedHeap.Allocation*)ptr, ref ep); } #endif //PAGING /// /// Transfer any contents that needs to be adjusted from the transferee to the target /// endpoint. Currently, this means setting the ownerProcessId of the /// transferee to that of the target. /// #if !PAGING [ExternalEntryPoint] public static void TransferContentOwnership( ref EndpointCore transferee, ref EndpointCore target) { Monitoring.Log(Monitoring.Provider.ChannelService, (ushort)ChannelServiceEvent.TransferContentOwnership, 0, (uint)transferee.ownerProcessId, (uint)target.ownerProcessId, (uint)transferee.channelId, (uint)target.channelId, // Not allowed to look at target.peer. We don't own that! // (uint)((EndpointCore*)(SharedHeapService.GetData(target.peer)))->channelId); (uint)target.channelId); transferee.ownerProcessId = target.ownerProcessId; transferee.ownerPrincipalHandle = target.ownerPrincipalHandle; // also fix up ownership of peer allocation Allocation* transfereePeerAllocation = transferee.peer; TransferBlockOwnership(transfereePeerAllocation, ref target); } #else [ExternalEntryPoint] // TODO: change "ref EndpointCore" to "EndpointCore" public static void TransferContentOwnership( ref EndpointCore transferee, ref EndpointCore target) { EndpointCoreImplementation ep1 = new EndpointCoreImplementation(transferee.id); EndpointCoreImplementation ep2 = new EndpointCoreImplementation(target.id); EndpointCoreImplementation.TransferContentOwnership(ref ep1, ref ep2); } #endif //PAGING #if !PAGING [NoHeapAllocation] public static int GetChannelID(ref EndpointCore ep) { return ep.channelId; } #else [ExternalEntryPoint] [NoHeapAllocation] public static int GetChannelID(ref EndpointCore ep) { return new EndpointCoreImplementation(ep.id).ChannelId; } #endif //PAGING #if !PAGING [NoHeapAllocation] public static int GetOwnerProcessID(ref EndpointCore ep) { return ep.ownerProcessId; } #else [ExternalEntryPoint] [NoHeapAllocation] public static int GetOwnerProcessID(ref EndpointCore ep) { return new EndpointCoreImplementation(ep.id).ProcessId; } #endif //PAGING #if !PAGING [NoHeapAllocation] public static int GetPeerProcessID(ref EndpointCore ep) { EndpointCore * peer = (EndpointCore*)SharedHeapService.GetData(ep.peer); return peer->ownerProcessId; } #else [ExternalEntryPoint] [NoHeapAllocation] public static int GetPeerProcessID(ref EndpointCore ep) { return new EndpointCoreImplementation(ep.id).PeerProcessId; } #endif //PAGING // It is unfortunate that PrincipalHandle and Principal are not // compatible types. They are only distinct because ABI types are disfavored // for code that doesn't deal directly with the ABI. #if !PAGING [NoHeapAllocation] public static PrincipalHandle GetPeerPrincipalHandle(ref EndpointCore ep) { EndpointCore * peer = (EndpointCore*)SharedHeapService.GetData(ep.peer); return peer->ownerPrincipalHandle; } #else [ExternalEntryPoint] [NoHeapAllocation] public static PrincipalHandle GetPeerPrincipalHandle(ref EndpointCore ep) { return new EndpointCoreImplementation(ep.id).PeerPrincipalHandle; } #endif #if !PAGING [NoHeapAllocation] public static PrincipalHandle GetOwnerPrincipalHandle(ref EndpointCore ep) { return ep.ownerPrincipalHandle; } #else [ExternalEntryPoint] [NoHeapAllocation] public static PrincipalHandle GetOwnerPrincipalHandle(ref EndpointCore ep) { return new EndpointCoreImplementation(ep.id).OwnerPrincipalHandle; } #endif //PAGING /// /// 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. /// [ExternalEntryPoint] public static void LinkIntoCollection(ref EndpointCore ep, AutoResetEventHandle ev) { #if !PAGING // Debug.Assert(this.collectionEvent.id == UIntPtr.Zero); ep.collectionEvent = ev; #else new EndpointCoreImplementation(ep.id).LinkIntoCollection(ev); #endif Tracing.Log(Tracing.Debug, "Ev:{0:x}", ev.id); } /// /// Instruct the selectable object to stop signalling events on the given /// AutoResetEvent. /// [ExternalEntryPoint] public static void UnlinkFromCollection(ref EndpointCore ep, AutoResetEventHandle ev) { #if !PAGING // Debug.Assert(this.collectionEvent.id != UIntPtr.Zero); ep.collectionEvent = new AutoResetEventHandle(); #else new EndpointCoreImplementation(ep.id).UnlinkFromCollection(ev); #endif } #if PAGING [ExternalEntryPoint] unsafe public static void MarshallMessage(ref EndpointCore ep, byte* basep, byte* source, int* tagAddress, int size) { Tracing.Log(Tracing.Debug, "source offset:{0:x} tagLoc offset:{1:x} size {2:x}", (uint)source-(uint)basep, (uint)tagAddress-(uint)basep, (uint)size); new EndpointCoreImplementation(ep.id).BeginUpdate(basep, source, tagAddress, size); } [ExternalEntryPoint] unsafe public static void MarshallPointer(ref EndpointCore ep, byte* basep, byte** target, SystemType type) { Tracing.Log(Tracing.Debug, "source offset:{0:x} type:{1}", (uint)target-(uint)basep, type.id); new EndpointCoreImplementation(ep.id).MarshallPointer(basep, (void**)target, type); } #endif } }