////////////////////////////////////////////////////////////////////////////////
//
// 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
}
}