411 lines
14 KiB
C#
411 lines
14 KiB
C#
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// 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
|
||
|
//
|
||
|
|
||
|
/// <summary>
|
||
|
/// Allocation which holds the endpoint core associated with this
|
||
|
/// delivery implementation
|
||
|
/// </summary>
|
||
|
protected Allocation* /*EndpointCore* opt(ExHeap)!*/ endpointAlloc;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Endpoint core associated with this delivery implementation
|
||
|
/// </summary>
|
||
|
protected EndpointCore* endpoint;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Handle to the owning Principal
|
||
|
/// </summary>
|
||
|
protected PrincipalHandle principalHandle;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Delegation state to control delegation through the principal
|
||
|
/// </summary>
|
||
|
protected DelegationState delegationState;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Contains the number of sends to this endpoint.
|
||
|
/// </summary>
|
||
|
protected int receiveCount;
|
||
|
|
||
|
//
|
||
|
// Shadow "trusted" shadow copies of the fields in endpointCore
|
||
|
//
|
||
|
|
||
|
/// <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 shadowMessageEvent;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Closed flag
|
||
|
/// </summary>
|
||
|
private bool shadowClosed;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Contains the process id of the process currently owning this end of the
|
||
|
/// channel.
|
||
|
/// </summary>
|
||
|
private int shadowProcessId;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Contains the channelId (positive on the EXP endpoint, negative on the imp endpoint)
|
||
|
/// </summary>
|
||
|
private int shadowChannelId;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Whether or not to marshall messages
|
||
|
/// </summary>
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
/// <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>
|
||
|
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;
|
||
|
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Set this end to closed
|
||
|
/// </summary>
|
||
|
public abstract void Close();
|
||
|
|
||
|
/// <summary>
|
||
|
/// Notify the owner of this endpoint that a message is ready.
|
||
|
/// Notifies the set owner if this endpoint is part of a set.
|
||
|
/// </summary>
|
||
|
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();
|
||
|
|
||
|
/// <summary>
|
||
|
/// Generic copy (either from kernel or to kernel)
|
||
|
/// Determines if the thing we are moving is an endpoint and copies it accordingly.
|
||
|
/// </summary>
|
||
|
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);
|
||
|
|
||
|
/// <summary>
|
||
|
/// Return the associated peer of this endpoint
|
||
|
/// </summary>
|
||
|
[NoHeapAllocation]
|
||
|
public abstract Allocation* Peer();
|
||
|
|
||
|
/// <summary>
|
||
|
/// Move endpoint data to a new process
|
||
|
/// </summary>
|
||
|
internal abstract Allocation* MoveEndpoint(SharedHeap fromHeap,
|
||
|
SharedHeap toHeap,
|
||
|
Process newOwner);
|
||
|
|
||
|
// <summary>
|
||
|
// Move non endpoint data to a new process
|
||
|
// </summary>
|
||
|
//internal abstract Allocation* MoveNonEndpoint(SharedHeap fromHeap,
|
||
|
// SharedHeap toHeap,
|
||
|
// Process newOwner);
|
||
|
|
||
|
/// <summary>
|
||
|
/// Returns true if this delivery mechanism has been initialised and
|
||
|
/// can be used for channel transport.
|
||
|
/// </summary>
|
||
|
internal abstract bool IsMechanismInitialized();
|
||
|
|
||
|
/// <summary>
|
||
|
/// Returns the name of the delivery implementation actually being used
|
||
|
/// </summary>
|
||
|
internal abstract string GetImplName();
|
||
|
|
||
|
/// <summary>
|
||
|
/// Notify the peer that a message is ready.
|
||
|
/// </summary>
|
||
|
internal abstract void NotifyPeer();
|
||
|
|
||
|
/// <summary>
|
||
|
/// Close peer endpoint.
|
||
|
/// </summary>
|
||
|
internal abstract bool ClosePeer();
|
||
|
|
||
|
/// <summary>
|
||
|
/// Is peer endpoint closed.
|
||
|
/// </summary>
|
||
|
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);
|
||
|
///////////////////////////////////////////////////////////////////
|
||
|
}
|
||
|
}
|