/base/Kernel/Singularity/Channels/EndpointCore.cs
C# | 677 lines | 418 code | 82 blank | 177 comment | 68 complexity | c164c683ec7e7212e5229f8ca60c65e7 MD5 | raw file
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Microsoft Research Singularity
- //
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //
- // File: EndpointCore.cs
- //
-
- // HACK: Because we currently compile this file as part of the Kernel with C#, we can't
- // make EndpointCore a rep struct, which is necessary for inheriting from it.
- // The compiler and Bartok recognize EndpointCore as special and treat it as
- // unsealed.
- // This hack can be removed, once we compile it with Sing#.
- // DON'T change the name until then!
-
- using System;
- using System.Runtime.CompilerServices;
- using System.Runtime.InteropServices;
- using System.Diagnostics;
- using Microsoft.Singularity.Channels;
- using Microsoft.Singularity.Security;
- using Microsoft.Singularity.Memory;
-
- namespace Microsoft.Singularity.Channels
- {
- 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 System.Threading;
- using SharedHeap = Microsoft.Singularity.Memory.SharedHeap;
-
- [CLSCompliant(false)]
- public enum EndpointCoreEvent : ushort
- {
- Connect = 4,
- TransferToProcess = 5,
- }
-
-
- [CLSCompliant(false)]
- [CCtorIsRunDuringStartup]
- 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
-
- /// <summary>
- /// Handle to the actual message delivery mechanism
- /// </summary>
- private DeliveryHandle deliveryHandle;
-
- /// <summary>
- /// Event handle in case this endpoint is part of a collection
- /// </summary>
- 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.
- //
-
- /// <summary>
- /// 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.
- /// </summary>
- private AutoResetEventHandle cachedMessageEvent;
-
- /// <summary>
- /// Closed flag
- /// </summary>
- private bool cachedClosed;
-
- /// <summary>
- /// Contains the process id of the process currently owning this end of the
- /// channel.
- /// </summary>
- private int cachedOwnerProcessId;
-
- /// <summary>
- /// Contains the channelId (positive on the EXP endpoint, negative on the imp endpoint)
- /// </summary>
- private int cachedChannelId;
-
- /// <summary>
- /// Whether to marshall or not
- /// </summary>
- private bool cachedMarshall;
-
- /// <summary>
- /// Points to the peer endpoint
- /// </summary>
- private Allocation* /*EndpointCore* opt(ExHeap)*/ cachedPeer;
-
- /// <summary>
- /// If true then the peer state can be queried directly from cachedPeer
- /// </summary>
- private bool peerStateValid;
-
-
- ////////////////////////////////////////////////////////////////////
- // Static Fields
- ////////////////////////////////////////////////////////////////////
-
- /// <summary>
- /// Number of open channels (using any delivery mechanism)
- /// </summary>
- private static int openChannelCount; // TODO open channel count!!!
-
- /// <summary>
- /// Channel id generator used to create unique channel id's accross delivery
- /// mechanisms.
- /// </summary>
- private static int channelIdGenerator;
-
-
- ////////////////////////////////////////////////////////////////////
- // Types
- ////////////////////////////////////////////////////////////////////
- public enum DelegationState {None, ByCapability, ByMediation, Mediated};
-
-
-
- ////////////////////////////////////////////////////////////////////
- // Methods
- ////////////////////////////////////////////////////////////////////
-
- /// <summary>
- /// Retrieve underlying delivery mechanism for a given endpoint allocation pointer
- /// </summary>
- [NoHeapAllocation]
- internal static DeliveryImpl AllocationEndpointDeliveryImpl(
- Allocation* /*EndpointCore* opt(ExHeap)!*/ endpoint)
- {
- EndpointCore * ep = (EndpointCore *) Allocation.GetData(endpoint);
- if (ep == null) {
- return null;
- } else {
- return ep->EndpointDeliveryImpl;
- }
- }
-
- /// <summary>
- /// Retrieve underlying delivery mechanism for a given endpoint allocation pointer
- /// using GetDataUnchecked.
- /// </summary>
- [NoHeapAllocation]
- internal static DeliveryImpl AllocationEndpointDeliveryImplUnchecked(
- Allocation* /*EndpointCore* opt(ExHeap)!*/ endpoint)
- {
- EndpointCore * ep = (EndpointCore *) Allocation.GetDataUnchecked(endpoint);
- if (ep == null) {
- return null;
- } else {
- return ep->EndpointDeliveryImpl;
- }
- }
-
- /// <summary>
- /// Retrieve underlying delivery mechanism for this endpoint
- /// </summary>
- internal DeliveryImpl EndpointDeliveryImpl {
- [NoHeapAllocation]
- get {
- if (deliveryHandle != DeliveryHandle.Zero) {
- return DeliveryHandle.GetImpl(deliveryHandle);
- } else {
- unsafe {
- DebugStub.WriteLine("deliveryHandle value is {0,8:x}\n", __arglist((uint) deliveryHandle.id));
- }
- DebugStub.Break();
- return null;
- }
- }
- }
-
- /// <summary>
- /// Performs the initialization of the core part of each endpoint and cross links
- /// them to form a channel. Uses the standard shared address space delivery
- /// mechanism.
- /// </summary>
- public static void Connect(
- Allocation* /*EndpointCore* opt(ExHeap)!*/ imp,
- Allocation* /*EndpointCore* opt(ExHeap)!*/ exp,
- Allocation* /*EndpointCore* opt(ExHeap)!*/ securityEp)
- {
- Connect(imp, exp, securityEp, SingleAddrSpaceDelivery.ImplName);
- }
-
- /// <summary>
- /// Performs the initialization of the core part of each endpoint and cross links
- /// them to form a channel. Uses the given delivery mechanism.
- /// </summary>
- public static void Connect(
- Allocation* /*EndpointCore* opt(ExHeap)!*/ imp,
- Allocation* /*EndpointCore* opt(ExHeap)!*/ exp,
- Allocation* /*EndpointCore* opt(ExHeap)!*/ securityEp,
- string deliveryImplType)
- {
- if (imp == null || exp == null) {
- throw new ApplicationException("Connect called with null endpoints");
- }
- EndpointCore* impData = (EndpointCore*)Allocation.GetData(imp);
- EndpointCore* expData = (EndpointCore*)Allocation.GetData(exp);
- if (impData == null || expData == null) {
- throw new ApplicationException("SharedHeap.GetData return null");
- }
-
- Tracing.Log(Tracing.Debug, "connect {0:x8} and {1:x8}",
- (UIntPtr)imp, (UIntPtr)exp);
-
- if (!(DeliveryHandle.Create(deliveryImplType, imp, out impData->deliveryHandle) &&
- DeliveryHandle.Create(deliveryImplType, exp, out expData->deliveryHandle))) {
- throw new EndpointCoreException(
- "Error trying to create EndpointCore using \"" +
- deliveryImplType +
- "\" delivery implementation");
- }
- #if false
- DebugStub.Print("imp handle {0,8:x} exp handle {1,8:x}\n",
- __arglist((uint)impData->deliveryHandle.id, (uint)expData->deliveryHandle.id));
- #endif
- DeliveryImpl impDi = impData->EndpointDeliveryImpl;
- DeliveryImpl expDi = expData->EndpointDeliveryImpl;
-
- VTable.Assert(impDi != null && expDi != null);
-
- impDi.Connect(expDi, securityEp);
-
- // keep track of how many channels are open
- Interlocked.Increment(ref openChannelCount);
- #if CHANNEL_COUNT
- PerfCounters.IncrementChannelsCreated();
- #endif
- Monitoring.Log(Monitoring.Provider.EndpointCore,
- (ushort)EndpointCoreEvent.Connect, 0,
- (uint)expData->ChannelId, 0, 0, 0, 0);
- }
-
- /// <summary>
- /// Set this end to closed
- /// </summary>
- public void Close()
- {
- DeliveryImpl di = EndpointDeliveryImpl;
- if (di != null) {
- di.Close();
- }
- }
-
- [NoHeapAllocation]
- public bool Closed()
- {
- DeliveryImpl di = EndpointDeliveryImpl;
- if (di != null) {
- return di.Closed;
- } else {
- // endpoint has not yet been connected
- return true;
- }
- }
-
- /// <summary>
- /// 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.
- /// </summary>
- public bool Dispose()
- {
- DeliveryImpl di = EndpointDeliveryImpl;
- if (di != null) {
- return EndpointDeliveryImpl.Dispose();
- } else {
- return true; // endpoint was not yet connected
- }
- }
-
- /// <summary>
- /// Explicitly frees this end of the channel.
- ///
- /// 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.
- /// </summary>
- public unsafe static void Free(Allocation* /*EndpointCore* opt(ExHeap)!*/ endpoint)
- {
-
-
- // Use unchecked GetData here, since this may be called from the
- // cleanup threading running in the kernel.
- EndpointCore * ep = ((EndpointCore*)Allocation.GetDataUnchecked(endpoint));
- if (ep->deliveryHandle != DeliveryHandle.Zero) {
- if (DeliveryHandle.Free(ep->deliveryHandle)) {
- Interlocked.Decrement(ref openChannelCount);
- }
- } else {
- // was never connected, just free this endpoint
- AutoResetEventHandle areHandle = ep->cachedMessageEvent;
-
- SharedHeap.KernelSharedHeap.Free(endpoint,
- SharedHeap.CurrentProcessSharedHeap.EndpointPeerOwnerId);
- if (areHandle.id != UIntPtr.Zero) {
- Process.kernelProcess.ReleaseHandle(areHandle.id);
- }
- }
- }
-
- /// <summary>
- /// The event to wait for messages on this endpoint. Used by Select.
- /// </summary>
- public SyncHandle GetWaitHandle() {
- DeliveryImpl di = EndpointDeliveryImpl;
- VTable.Assert(di != null);
- return di.MessageEvent;
- }
-
- /// <summary>
- /// Get the AutoResetEventHandle
- /// </summary>
- public AutoResetEventHandle GetAreHandle() {
- DeliveryImpl di = EndpointDeliveryImpl;
- VTable.Assert(di != null);
- return di.AreHandle;
- }
-
- /// <summary>
- /// Notify the peer of this endpoint that a message is ready.
- /// Notifies the set owner if this endpoint is part of a set.
- /// </summary>
- public void NotifyPeer() {
- DeliveryImpl di = EndpointDeliveryImpl;
- VTable.Assert(di != null);
- di.NotifyPeer();
- }
-
- /// <summary>
- /// Used internally by the kernel to transfer an endpoint to a new owner
- ///
- /// Can be used to transfer ANY kind of shared heap data, not just endpoints.
- /// </summary>
- public static Allocation* MoveEndpoint(SharedHeap fromHeap,
- SharedHeap toHeap,
- Process newOwner,
- Allocation *ep)
- {
- return DeliveryImpl.MoveData(fromHeap, toHeap, newOwner, ep);
- }
-
-
- public static void AcceptDelegation(Allocation* /*EndpointCore* opt(ExHeap)!*/ imp,
- Allocation* /*EndpointCore* opt(ExHeap)!*/ exp,
- Allocation* /*EndpointCore* opt(ExHeap)!*/ ep)
- {
- DeliveryImpl impDi = AllocationEndpointDeliveryImpl(imp);
- DeliveryImpl expDi = AllocationEndpointDeliveryImpl(exp);
- DeliveryImpl epDi = AllocationEndpointDeliveryImpl(ep);
- VTable.Assert((impDi != null && expDi != null && epDi != null));
- VTable.Assert((impDi.GetType() == expDi.GetType()) &&
- (impDi.GetType() == epDi.GetType()));
- impDi.AcceptDelegation(expDi, epDi);
- }
-
- public void EnableDelegation(bool allowMediation)
- {
- EndpointDeliveryImpl.EnableDelegation(allowMediation);
- }
-
- public DelegationState OwnerDelegationState
- {
- [NoHeapAllocation]
- get { return EndpointDeliveryImpl.OwnerDelegationState; }
- }
-
- public PrincipalHandle OwnerPrincipalHandle
- {
- [NoHeapAllocation]
- get { return EndpointDeliveryImpl.OwnerPrincipalHandle; }
- }
-
- public PrincipalHandle PeerPrincipalHandle
- {
- [NoHeapAllocation]
- get { return EndpointDeliveryImpl.PeerPrincipalHandle; }
- }
-
- public int PeerReceiveCount
- {
- [NoHeapAllocation]
- get {
- DeliveryImpl di = EndpointDeliveryImpl;
- if (di != null) {
- return di.PeerReceiveCount;
- } else {
- // not yet connected, therefore no peer yet
- return 0;
- }
- }
- }
-
- //versions of begin update and marshallpointer that handle objects with pointers
- //greater than one level deep
-
- internal void BeginUpdate(byte* basep, byte* source, int* tagAddress, int msgSize)
- {
- DeliveryImpl di = EndpointDeliveryImpl;
- VTable.Assert(di != null);
- // DebugStub.Print("BeginUpdate delivery handle {0,8:x}\n", __arglist((uint)deliveryHandle.id));
- di.BeginUpdate(basep, source, tagAddress, msgSize);
- }
-
- public void MarshallPointer(byte* basep, byte** target, SystemType type, byte* parent, int offset)
- {
- if (target == null) return;
- DeliveryImpl di = EndpointDeliveryImpl;
- // DebugStub.Print("Marshall Pointer delivery handle {0,8:x}\n", __arglist((uint)deliveryHandle.id));
- VTable.Assert(di != null);
- di.MarshallPointer(basep, target, type, parent, offset);
- }
-
- public static PrincipalHandle TransferPrincipal(PrincipalHandle oldH,
- int processId,
- ref DelegationState delegationState)
- {
- Process p = Process.GetProcessByID(processId);
- if (p == null)
- throw new ApplicationException("Delegate endpoint process is null");
-
- DelegationState newstate;
- Principal pr;
- switch (delegationState) {
- case DelegationState.ByMediation:
- pr = PrincipalImpl.NewDelegation(
- PrincipalImpl.MakePrincipal(oldH.val), p.Principal);
- newstate = DelegationState.Mediated;
- break;
- case DelegationState.ByCapability:
- pr = PrincipalImpl.NewDelegation(
- PrincipalImpl.MakePrincipal(oldH.val), p.Principal);
- newstate = DelegationState.None;
- break;
- case DelegationState.Mediated:
- pr = p.Principal;
- newstate = DelegationState.None;
- break;
- case DelegationState.None:
- default:
- pr = p.Principal;
- newstate = DelegationState.None;
- break;
- }
-
- delegationState = newstate;
- return new PrincipalHandle(pr.Val);
- }
-
- #if SINGULARITY_KERNEL && CHANNEL_COUNT
-
- internal static void IncreaseBytesSentCount(long bytes)
- {
- PerfCounters.AddBytesSent(bytes);
-
- }
-
- #endif // SINGULARITY_KERNEL
-
- /// <summary>
- /// Transfer the given Allocation block to the target endpoint
- /// </summary>
- public static void TransferBlockOwnership(Allocation* ptr, ref EndpointCore target)
- {
- Allocation.SetOwnerProcessId(ptr, target.cachedOwnerProcessId);
- // TODO MAKE THIS APROPRIATE TO BOTH SINGLE AND PAGED IMPLS
- DeliveryImpl di = target.EndpointDeliveryImpl;
- VTable.Assert(di != null);
- //Monitoring.Log(Monitoring.Provider.ChannelService,
- // (ushort)ChannelServiceEvent.TransferBlockOwnership, 0,
- // (uint)di.ChannelId,
- // (uint)di.ProcessId,
- // 0, 0, 0);
- #if CHANNEL_COUNT
- IncreaseBytesSentCount((long) Allocation.GetSize(ptr));
- #endif
- Allocation.SetOwnerProcessId(ptr, di.ProcessId);
- }
-
- /// <summary>
- /// Transfer any contents that needs to be adjusted from the transferee to the target
- /// endpoint.
- /// </summary>
- // TODO: change "ref EndpointCore" to "EndpointCore"
- public static void TransferContentOwnership(
- ref EndpointCore transferee,
- ref EndpointCore target)
- {
- // TODO MAKE THIS APROPRIATE TO BOTH SINGLE AND PAGED IMPLS
- DeliveryImpl transfereeDi = transferee.EndpointDeliveryImpl;
-
- // XXX BUG? BUG? BUG?
- // targetDi = transferee.EndpointDeliveryImpl
- // should be:
- // targetDi = target.EndpointDeliveryImpl
- DeliveryImpl targetDi = transferee.EndpointDeliveryImpl;
- VTable.Assert((transfereeDi != null) && (targetDi != null));
- //Monitoring.Log(Monitoring.Provider.ChannelService,
- // (ushort)ChannelServiceEvent.TransferContentOwnership, 0,
- // (uint)transfereeDi.ProcessId,
- // (uint)targetDi.ProcessId,
- // (uint)transfereeDi.ChannelId,
- // (uint)targetDi.ChannelId,
- // (uint)targetDi.Peer.ChannelId);
- int toProcessId = targetDi.ProcessId;
- transfereeDi.ProcessId = toProcessId;
- DelegationState newstate = transfereeDi.OwnerDelegationState;
- transfereeDi.OwnerPrincipalHandle =
- TransferPrincipal(transfereeDi.OwnerPrincipalHandle, toProcessId, ref newstate);
- transfereeDi.OwnerDelegationState = newstate;
- Allocation* transfereePeerAllocation = transfereeDi.Peer();
- // also transfer the peer allocation
- Allocation.SetOwnerProcessId(transfereePeerAllocation, toProcessId);
- }
-
- public static int OpenChannelCount {
- [NoHeapAllocation]
- get { return openChannelCount; }
- }
-
- public static void IncOpenChannelCount () {
- Interlocked.Increment(ref openChannelCount);
- }
-
- public static void DecOpenChannelCount () {
- Interlocked.Decrement(ref openChannelCount);
- }
-
- //
- // These getter defer to the delivery implementation, as the kernel only
- // trusts the shadow versions held in Kernel memory space.
- //
- public bool PeerClosed()
- {
- DeliveryImpl di = EndpointDeliveryImpl;
- if (di != null) {
- return di.PeerClosed();
- } else {
- // endpoint has not yet been connected
- return true;
- }
- }
-
- /// <summary>
- /// Return a handle for the peer
- /// </summary>
- public Allocation* Peer(out bool marshall)
- {
- DeliveryImpl di = EndpointDeliveryImpl;
- VTable.Assert(di != null);
- return di.Peer(out marshall);
- }
-
- public int ChannelId
- {
- [NoHeapAllocation]
- get {
- DeliveryImpl di = EndpointDeliveryImpl;
- VTable.Assert(di != null);
- return di.ChannelId;
- }
- }
-
- public int ProcessId
- {
- [NoHeapAllocation]
- get {
- DeliveryImpl di = EndpointDeliveryImpl;
- VTable.Assert(di != null);
- return di.ProcessId;
- }
- }
-
- public int ReceiveCount
- {
- get {
- DeliveryImpl di = EndpointDeliveryImpl;
- VTable.Assert(di != null);
- return di.ReceiveCount;
- }
- }
-
- public int PeerProcessId
- {
- [NoHeapAllocation]
- get {
- DeliveryImpl di = EndpointDeliveryImpl;
- VTable.Assert(di != null);
- return di.PeerProcessId;
- }
- }
-
- public DeliveryHandle dImpHandle
- {
- get {
- return deliveryHandle;
- }
- set {
- deliveryHandle = value;
- }
- }
-
- public AutoResetEventHandle CollectionEvent
- {
- get {
- return collectionEvent;
- }
- set {
- collectionEvent = value;
- }
- }
-
- internal static int GetNextChannelId()
- {
- return Interlocked.Increment(ref channelIdGenerator);
- }
-
- //
- // These methods only set the user accessable cached copies, real changes should
- // be made to the delivery implementation copies.
- //
- [NoHeapAllocation]
- public void SetCachedClose(bool closed) { cachedClosed = closed; }
- [NoHeapAllocation]
- public void SetCachedProcessId(int pid) { cachedOwnerProcessId = pid; }
- [NoHeapAllocation]
- public void SetCachedChannelId(int cid) { cachedChannelId = cid; }
- [NoHeapAllocation]
- public void SetCachedMarshall(bool marshall) { cachedMarshall = marshall; }
- [NoHeapAllocation]
- public void SetCachedMessageEvent(AutoResetEventHandle mh)
- {
- cachedMessageEvent = mh;
- }
- [NoHeapAllocation]
- public void SetCachedPeer(Allocation * /* EndpointCore */ peer)
- {
- cachedPeer = peer;
- }
- [NoHeapAllocation]
- public void SetPeerStateValid(bool valid)
- {
- peerStateValid = valid;
- }
-
- }
-
- public class EndpointCoreException: Exception
- {
- public EndpointCoreException (string message) : base(message)
- {
- }
- }
- }
-