The Labs \ Source Viewer \ SSCLI \ System.Runtime.Remoting.Contexts \ CallBackHelper

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. /*============================================================
  16. **
  17. ** File:    Context.cs
  18. **
  19. **
  20. ** Purpose: Remoting Context core implementation.
  21. **
  22. **
  23. ===========================================================*/
  24. namespace System.Runtime.Remoting.Contexts
  25. {
  26.    
  27.     using System;
  28.     using System.Security;
  29.     using System.Security.Permissions;
  30.     using System.Threading;
  31.     using System.Runtime.InteropServices;
  32.     using System.Runtime.Remoting;
  33.     using System.Runtime.Remoting.Activation;
  34.     using System.Runtime.Remoting.Messaging;
  35.     using System.Runtime.Serialization;
  36.     using System.Runtime.CompilerServices;
  37.     using System.Globalization;
  38.     // CallBacks provide a facility to request execution of some code
  39.     // in another context.
  40.     // CrossContextDelegate type is defined for context call backs.
  41.     // Each context has a CallBackObject which can be used to perform
  42.     // callbacks on the context. The delegate used to request a callback
  43.     // through the CallBackObject must be of CrossContextDelegate type.
  44.     /// <internalonly/>
  45.     [System.Runtime.InteropServices.ComVisible(true)]
  46.     public delegate void CrossContextDelegate();
  47.    
  48.     /// <internalonly/>
  49.     // deliberately not [serializable]
  50.     //[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure)]
  51.     [System.Runtime.InteropServices.ComVisible(true)]
  52.     public class Context
  53.     {
  54.         // flags to mark the state of the context object
  55.         // marks the context as the default context
  56.         internal const int CTX_DEFAULT_CONTEXT = 1;
  57.        
  58.         // marks the context as frozen
  59.         internal const int CTX_FROZEN = 2;
  60.        
  61.         // Tells the context channel that the context has properties
  62.         // that use the threadPool themselves.
  63.         // In that case, the channel does not itself use threadPool.
  64.         // This is OFF by default
  65.         internal const int CTX_THREADPOOL_AWARE = 4;
  66.        
  67.         private const int GROW_BY = 8;
  68.         private const int STATICS_BUCKET_SIZE = 8;
  69.        
  70.         private IContextProperty[] _ctxProps;
  71.         // array of name-value pairs of properties
  72.         private DynamicPropertyHolder _dphCtx;
  73.         // Support for Dynamic Sinks
  74.         private LocalDataStore _localDataStore;
  75.         private IMessageSink _serverContextChain;
  76.         private IMessageSink _clientContextChain;
  77.         private AppDomain _appDomain;
  78.         // AppDomain property of the context
  79.         private object[] _ctxStatics;
  80.         // Holder for context statics
  81.         //**********************
  82.         // This needs to be the first NON-OBJECT field!
  83.         private IntPtr _internalContext;
  84.         // address of the VM context object!
  85.         //**********************
  86.         // at this point we just differentiate contexts based on context ID
  87.         private int _ctxID;
  88.         private int _ctxFlags;
  89.         private int _numCtxProps;
  90.         // current count of properties
  91.         // Context statics stuff
  92.         private int _ctxStaticsCurrentBucket;
  93.         private int _ctxStaticsFreeIndex;
  94.        
  95.         // Support for dynamic properties.
  96.         private static DynamicPropertyHolder _dphGlobal = new DynamicPropertyHolder();
  97.        
  98.         // Support for Context Local Storage
  99.         private static LocalDataStoreMgr _localDataStoreMgr = new LocalDataStoreMgr();
  100.        
  101.         // ContextID counter (for public context id)
  102.         private static int _ctxIDCounter = 0;
  103.        
  104.         /// <internalonly/>
  105.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  106.         public Context() : this(0)
  107.         {
  108.         }
  109.        
  110.         private Context(int flags)
  111.         {
  112.            
  113.             _ctxFlags = flags;
  114.             if ((_ctxFlags & CTX_DEFAULT_CONTEXT) != 0) {
  115.                 _ctxID = 0;
  116.                 // ID 0 == default context
  117.             }
  118.             else {
  119.                 _ctxID = Interlocked.Increment(ref _ctxIDCounter);
  120.             }
  121.            
  122.             // Every context inherits the appdomain level properties
  123.             // Get the properties for the appdomain and add it to
  124.             // this context.
  125.             DomainSpecificRemotingData data = Thread.GetDomain().RemotingData;
  126.             if (null != data) {
  127.                 IContextProperty[] ctxProps = data.AppDomainContextProperties;
  128.                 if (null != ctxProps) {
  129.                     for (int i = 0; i < ctxProps.Length; i++) {
  130.                         SetProperty(ctxProps[i]);
  131.                     }
  132.                 }
  133.             }
  134.            
  135.             // Freeze the default context now
  136.             if ((_ctxFlags & CTX_DEFAULT_CONTEXT) != 0) {
  137.                 this.Freeze();
  138.             }
  139.             // This call will set up the cycles between the VM & managed context
  140.             // It will also set the managed context's AppDomain property to
  141.             // the current AppDomain.Will also publish ifthe default ctx, so should be
  142.             // in the very end
  143.             SetupInternalContext((_ctxFlags & CTX_DEFAULT_CONTEXT) == CTX_DEFAULT_CONTEXT);
  144.            
  145.             Message.DebugOut("Creating Context with ID " + _ctxID + " and flags " + flags + " " + Environment.NewLine);
  146.         }
  147.        
  148.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  149.         private extern void SetupInternalContext(bool bDefault);
  150.        
  151.         /// <internalonly/>
  152.         ~Context()
  153.         {
  154.             // We clean up the backing objects only for the non-default
  155.             // contexts. For default contexts these are cleaned up during
  156.             // AppDomain shutdown.
  157.             if (_internalContext != IntPtr.Zero && (_ctxFlags & CTX_DEFAULT_CONTEXT) == 0) {
  158.                 CleanupInternalContext();
  159.             }
  160.         }
  161.        
  162.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  163.         private extern void CleanupInternalContext();
  164.        
  165.         /// <internalonly/>
  166.         public virtual Int32 ContextID {
  167.             [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  168.             get { return _ctxID; }
  169.         }
  170.        
  171.         internal virtual IntPtr InternalContextID {
  172.             get { return _internalContext; }
  173.         }
  174.        
  175.         internal virtual AppDomain AppDomain {
  176.             get { return _appDomain; }
  177.         }
  178.        
  179.         internal bool IsDefaultContext {
  180.             get { return _ctxID == 0; }
  181.         }
  182.        
  183.         /// <internalonly/>
  184.         public static Context DefaultContext {
  185.             [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  186.             get { return Thread.GetDomain().GetDefaultContext(); }
  187.         }
  188.        
  189.         static internal Context CreateDefaultContext()
  190.         {
  191.             return new Context(CTX_DEFAULT_CONTEXT);
  192.         }
  193.        
  194.         /// <internalonly/>
  195.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  196.         public virtual IContextProperty GetProperty(string name)
  197.         {
  198.             if (_ctxProps == null || name == null) {
  199.                 return null;
  200.             }
  201.             IContextProperty prop = null;
  202.             for (int i = 0; i < _numCtxProps; i++) {
  203.                 if (_ctxProps[i].Name.Equals(name)) {
  204.                     prop = _ctxProps[i];
  205.                     break;
  206.                 }
  207.             }
  208.             return prop;
  209.         }
  210.        
  211.         /// <internalonly/>
  212.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  213.         public virtual void SetProperty(IContextProperty prop)
  214.         {
  215.             // We do not let people add properties to the default context.
  216.             /* We allow appdomain level properties to be added to the default context
  217.             if ((_ctxFlags & CTX_DEFAULT_CONTEXT) != 0)
  218.             {
  219.                 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_AddContextFrozen"));
  220.             }
  221.             */           
  222.            
  223. if (prop == null || prop.Name == null) {
  224.                 throw new ArgumentNullException((prop == null) ? "prop" : "property name");
  225.             }
  226.            
  227.             if ((_ctxFlags & CTX_FROZEN) != 0) {
  228.                 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_AddContextFrozen"));
  229.             }
  230.            
  231.             lock (this) {
  232.                 // Check if we have a property by this name
  233.                 CheckPropertyNameClash(prop.Name, _ctxProps, _numCtxProps);
  234.                
  235.                 // check if we need to grow the array.
  236.                 if (_ctxProps == null || _numCtxProps == _ctxProps.Length) {
  237.                     _ctxProps = GrowPropertiesArray(_ctxProps);
  238.                 }
  239.                 // now add the property
  240.                 _ctxProps[_numCtxProps++] = prop;
  241.             }
  242.         }
  243.        
  244.         internal virtual void InternalFreeze()
  245.         {
  246.             _ctxFlags |= CTX_FROZEN;
  247.             // From this point on attempts to add properties will throw
  248.             // So we don't need to take a lock.
  249.             for (int i = 0; i < _numCtxProps; i++) {
  250.                 _ctxProps[i].Freeze(this);
  251.             }
  252.            
  253.         }
  254.         /// <internalonly/>
  255.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  256.         public virtual void Freeze()
  257.         {
  258.             lock (this) {
  259.                 if ((_ctxFlags & CTX_FROZEN) != 0) {
  260.                     throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ContextAlreadyFrozen"));
  261.                 }
  262.                 InternalFreeze();
  263.             }
  264.         }
  265.        
  266.         internal virtual void SetThreadPoolAware()
  267.         {
  268.             // Cannot turn off ThreadPool support for the default context
  269.             BCLDebug.Assert((_ctxFlags & CTX_DEFAULT_CONTEXT) == 0, "This operation is not allowed on the default context!");
  270.             _ctxFlags |= CTX_THREADPOOL_AWARE;
  271.         }
  272.        
  273.         internal virtual bool IsThreadPoolAware {
  274.             get { return (_ctxFlags & CTX_THREADPOOL_AWARE) == CTX_THREADPOOL_AWARE; }
  275.         }
  276.        
  277.         /// <internalonly/>
  278.         public virtual IContextProperty[] ContextProperties {
  279.             // we return a copy of the current set of properties
  280.             // the user may iterate from 0 to array.length on it.
  281.             [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  282.             get {
  283.                 if (_ctxProps == null) {
  284.                     return null;
  285.                 }
  286.                 lock (this) {
  287.                     IContextProperty[] retProps = new IContextProperty[_numCtxProps];
  288.                     Array.Copy(_ctxProps, retProps, _numCtxProps);
  289.                     return retProps;
  290.                 }
  291.             }
  292.         }
  293.        
  294.         static internal void CheckPropertyNameClash(string name, IContextProperty[] props, int count)
  295.         {
  296.             for (int i = 0; i < count; i++) {
  297.                 if (props[i].Name.Equals(name)) {
  298.                     throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_DuplicatePropertyName"));
  299.                 }
  300.             }
  301.         }
  302.        
  303.         static internal IContextProperty[] GrowPropertiesArray(IContextProperty[] props)
  304.         {
  305.             // grow the array of IContextProperty objects
  306.             int newSize = (props != null ? props.Length : 0) + GROW_BY;
  307.             IContextProperty[] newProps = new IContextProperty[newSize];
  308.             if (props != null) {
  309.                 // Copy existing properties over.
  310.                 Array.Copy(props, newProps, props.Length);
  311.             }
  312.             return newProps;
  313.         }
  314.        
  315.         internal virtual IMessageSink GetServerContextChain()
  316.         {
  317.             if (_serverContextChain == null) {
  318.                 // a bare chain would have just this one sink.
  319.                 IMessageSink newServerContextChain = ServerContextTerminatorSink.MessageSink;
  320.                
  321.                 // now loop over properties to add some real sinks.
  322.                 object prop = null;
  323.                 int iSink = _numCtxProps;
  324.                 while (iSink-- > 0) {
  325.                     // see if this property wants to contribute a ServerContextSink
  326.                     // we have to start chaining in the reverse order
  327.                     prop = _ctxProps[iSink];
  328.                     IContributeServerContextSink sink = prop as IContributeServerContextSink;
  329.                     if (null != sink) {
  330.                         // yes, chain the sink ahead of the chain of sinks constructed so far.
  331.                         newServerContextChain = sink.GetServerContextSink(newServerContextChain);
  332.                         if (newServerContextChain == null) {
  333.                             throw new RemotingException(Environment.GetResourceString("Remoting_Contexts_BadProperty"));
  334.                         }
  335.                     }
  336.                 }
  337.                 lock (this) {
  338.                     if (_serverContextChain == null) {
  339.                         _serverContextChain = newServerContextChain;
  340.                     }
  341.                 }
  342.             }
  343.             return _serverContextChain;
  344.         }
  345.        
  346.         internal virtual IMessageSink GetClientContextChain()
  347.         {
  348.             Message.DebugOut("Context::GetClientContextChain: IN _ctxID =" + _ctxID + Environment.NewLine);
  349.             if (_clientContextChain == null) {
  350.                 Message.DebugOut("Context::GetClientContextChain: _clientContextChain == null, creating chain" + Environment.NewLine);
  351.                 // a bare chain would have just this one sink.
  352.                 IMessageSink newClientContextChain = ClientContextTerminatorSink.MessageSink;
  353.                
  354.                 // now loop over properties to add some real sinks.
  355.                 // Note that for the client chain we go through the properties
  356.                 // in the reverse order as compared to the server chain.
  357.                 // Thus if a lock was taken as the last action of an incoming
  358.                 // call, it is released as the first action of an outgoing call.
  359.                 object prop = null;
  360.                 int iSink = 0;
  361.                 while (iSink < _numCtxProps) {
  362.                     Message.DebugOut("Context::GetClientContextChain: checking property " + _ctxProps[iSink].Name + Environment.NewLine);
  363.                     // see if this property wants to contribute a ClientContextSink
  364.                     // we have to start chaining in the reverse order
  365.                     prop = _ctxProps[iSink];
  366.                     IContributeClientContextSink sink = prop as IContributeClientContextSink;
  367.                     if (null != sink) {
  368.                         Message.DebugOut("Context::GetClientContextChain: calling GetClientContextSink on " + _ctxProps[iSink].Name + Environment.NewLine);
  369.                         // yes, chain the sink ahead of the chain of sinks constructed so far.
  370.                         newClientContextChain = sink.GetClientContextSink(newClientContextChain);
  371.                         if (newClientContextChain == null) {
  372.                             throw new RemotingException(Environment.GetResourceString("Remoting_Contexts_BadProperty"));
  373.                         }
  374.                     }
  375.                     iSink++;
  376.                 }
  377.                 // now check if we raced and set appropriately
  378.                 lock (this) {
  379.                     if (_clientContextChain == null) {
  380.                         _clientContextChain = newClientContextChain;
  381.                     }
  382.                     // else the chain we created should get GC-ed.
  383.                 }
  384.             }
  385.             return _clientContextChain;
  386.         }
  387.        
  388.         internal virtual IMessageSink CreateServerObjectChain(MarshalByRefObject serverObj)
  389.         {
  390.             // a bare chain would just be the dispatcher sink
  391.             IMessageSink serverObjectChain = new ServerObjectTerminatorSink(serverObj);
  392.            
  393.             // now loop over properties to add some real sinks.
  394.             object prop = null;
  395.             int iSink = _numCtxProps;
  396.             while (iSink-- > 0) {
  397.                 // see if this property wants to contribute a ServerObjectSink
  398.                 // we have to start chaining in the reverse order
  399.                 prop = _ctxProps[iSink];
  400.                 IContributeObjectSink sink = prop as IContributeObjectSink;
  401.                 if (null != sink) {
  402.                     // yes, chain the sink ahead of the chain of sinks constructed so far.
  403.                     serverObjectChain = sink.GetObjectSink(serverObj, serverObjectChain);
  404.                     if (serverObjectChain == null) {
  405.                         throw new RemotingException(Environment.GetResourceString("Remoting_Contexts_BadProperty"));
  406.                     }
  407.                 }
  408.             }
  409.             return serverObjectChain;
  410.         }
  411.        
  412.         internal virtual IMessageSink CreateEnvoyChain(MarshalByRefObject objectOrProxy)
  413.         {
  414.             // a bare chain would just be the dispatcher sink
  415.             IMessageSink envoyChain = EnvoyTerminatorSink.MessageSink;
  416.            
  417.             // now loop over properties to add some real sinks.
  418.             // Note: the sinks in the envoy chain should be in mirror image
  419.             // order relative to sinks on the server side
  420.             object prop = null;
  421.             int iSink = 0;
  422.            
  423.             MarshalByRefObject exposedObj = objectOrProxy;
  424.            
  425.             while (iSink < _numCtxProps) {
  426.                 // see if this property wants to contribute a ClientContextSink
  427.                 // we have to start chaining in the reverse order
  428.                 prop = _ctxProps[iSink];
  429.                 IContributeEnvoySink sink = prop as IContributeEnvoySink;
  430.                 if (null != sink) {
  431.                     // yes, chain the sink ahead of the chain of sinks constructed so far.
  432.                     envoyChain = sink.GetEnvoySink(exposedObj, envoyChain);
  433.                     if (envoyChain == null) {
  434.                         throw new RemotingException(Environment.GetResourceString("Remoting_Contexts_BadProperty"));
  435.                     }
  436.                 }
  437.                 iSink++;
  438.             }
  439.             return envoyChain;
  440.         }
  441.        
  442.        
  443.         //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  444.         //~~~~~~~~~~~~~~~~~~~ Activation Support ~~~~~~~~~~~~~~~~~~~~~~~~
  445.         //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  446.         internal IMessage NotifyActivatorProperties(IMessage msg, bool bServerSide)
  447.         {
  448.             BCLDebug.Assert((msg is IConstructionCallMessage) || (msg is IConstructionReturnMessage), "Bad activation msg type");
  449.             BCLDebug.Assert(!((msg is IConstructionCallMessage) && (msg is IConstructionReturnMessage)), "Activation message cannot be both call & return type");
  450.            
  451.             BCLDebug.Assert((_ctxFlags & CTX_FROZEN) == CTX_FROZEN, "ServerContext not frozen during activation!");
  452.            
  453.            
  454.             // Any exception thrown by the notifications is caught and
  455.             // folded into a return message to return to the caller.
  456.             IMessage errMsg = null;
  457.            
  458.             try {
  459.                 // Since the context is frozen the properties array is in
  460.                 // effect read-only!
  461.                 int iProp = _numCtxProps;
  462.                 object prop = null;
  463.                
  464.                 while (iProp-- != 0) {
  465.                     // see if this property is interested in Activation
  466.                     prop = _ctxProps[iProp];
  467.                     IContextPropertyActivator activator = prop as IContextPropertyActivator;
  468.                     if (null != activator) {
  469.                         // yes, notify as appropriate
  470.                         IConstructionCallMessage ccm = msg as IConstructionCallMessage;
  471.                         if (null != ccm) {
  472.                             // IConsructionCallMessage on its way forward
  473.                             if (!bServerSide) {
  474.                                 // activation starting at client side
  475.                                 activator.CollectFromClientContext(ccm);
  476.                             }
  477.                             else {
  478.                                 activator.DeliverClientContextToServerContext(ccm);
  479.                             }
  480.                         }
  481.                         else {
  482.                             // IConstructionReturnMessage on its way back
  483.                             if (bServerSide) {
  484.                                 // activation returning from server side
  485.                                 activator.CollectFromServerContext((IConstructionReturnMessage)msg);
  486.                             }
  487.                             else {
  488.                                 // activation back at client side
  489.                                 activator.DeliverServerContextToClientContext((IConstructionReturnMessage)msg);
  490.                             }
  491.                         }
  492.                     }
  493.                 }
  494.             }
  495.             catch (Exception e) {
  496.                 IMethodCallMessage mcm = null;
  497.                 if (msg is IConstructionCallMessage) {
  498.                     mcm = (IMethodCallMessage)msg;
  499.                 }
  500.                 else {
  501.                     mcm = new ErrorMessage();
  502.                 }
  503.                 errMsg = new ReturnMessage(e, mcm);
  504.                 if (msg != null) {
  505.                     ((ReturnMessage)errMsg).SetLogicalCallContext((LogicalCallContext)msg.Properties[Message.CallContextKey]);
  506.                 }
  507.             }
  508.             return errMsg;
  509.         }
  510.        
  511.         /// <internalonly/>
  512.         public override string ToString()
  513.         {
  514.             return "ContextID: " + _ctxID;
  515.         }
  516.        
  517.         //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  518.         //~~~~~~~~~~~~~~~~~~~ Transition Support ~~~~~~~~~~~~~~~~~~~~~~~~
  519.         //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  520.        
  521.         // This is the simple cross-context call back function invoke on
  522.         // the context to do a call-back in.
  523.         /// <internalonly/>
  524.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  525.         public void DoCallBack(CrossContextDelegate deleg)
  526.         {
  527.             /*DBG Console.WriteLine("public DoCallBack: targetCtx: "
  528.             + Int32.Format(this.InternalContextID,"x")); DBG*/           
  529.            
  530. if (deleg == null) {
  531.                 throw new ArgumentNullException("deleg");
  532.             }
  533.            
  534.             if ((_ctxFlags & CTX_FROZEN) == 0) {
  535.                 throw new RemotingException(Environment.GetResourceString("Remoting_Contexts_ContextNotFrozenForCallBack"));
  536.             }
  537.            
  538.             Context currCtx = Thread.CurrentContext;
  539.             if (currCtx == this) {
  540.                 // We are already in the target context, just execute deleg
  541.                 // NOTE: If in the future we decide to leave the context
  542.                 // and reenter it for this case we will need to change
  543.                 // Context::RequestCallBack method in VM also!
  544.                 deleg();
  545.             }
  546.             else {
  547.                 // We pass 0 for target domain ID for x-context case.
  548.                 currCtx.DoCallBackGeneric(this.InternalContextID, deleg);
  549.                 GC.KeepAlive(this);
  550.             }
  551.         }
  552.        
  553.         // This is called when EE needs to do a transition and execute some
  554.         // code. Before calling, EE determines if this is a x-domain case.
  555.         // targetDomainID will be 0 if it is a simple x-context call.
  556.         static internal void DoCallBackFromEE(IntPtr targetCtxID, IntPtr privateData, int targetDomainID)
  557.         {
  558.             BCLDebug.Assert(targetCtxID != IntPtr.Zero, "Bad transition context");
  559.            
  560.             /*DBG Console.WriteLine("private DoCallBackFromEE: targetCtx: "
  561.             + Int32.Format(targetCtxID,"x")
  562.             + " PvtData: " + Int32.Format(privateData,"x"));DBG*/           
  563.            
  564. if (targetDomainID == 0) {
  565.                     /*fromEE*/                CallBackHelper cb = new CallBackHelper(privateData, true, targetDomainID);
  566.                 CrossContextDelegate ctxDel = new CrossContextDelegate(cb.Func);
  567.                 Thread.CurrentContext.DoCallBackGeneric(targetCtxID, ctxDel);
  568.             }
  569.             else {
  570.                 // for x-appdomain calls, we can't pass a delegate since that
  571.                 // would require us to deserialize it on the other side which
  572.                 // is not allowed for non-public methods.
  573.                 TransitionCall msgCall = new TransitionCall(targetCtxID, privateData, targetDomainID);
  574.                
  575.                 Message.PropagateCallContextFromThreadToMessage(msgCall);
  576.                 //DBG Console.WriteLine("CallBackGeneric starting!");
  577.                 IMessage retMsg = Thread.CurrentContext.GetClientContextChain().SyncProcessMessage(msgCall);
  578.                 Message.PropagateCallContextFromMessageToThread(retMsg);
  579.                
  580.                 IMethodReturnMessage msg = retMsg as IMethodReturnMessage;
  581.                 if (null != msg) {
  582.                     if (msg.Exception != null)
  583.                         throw msg.Exception;
  584.                 }
  585.             }
  586.         }
  587.         // DoCallBackFromEE
  588.         // This is called by both the call back functions above.
  589.         internal void DoCallBackGeneric(IntPtr targetCtxID, CrossContextDelegate deleg)
  590.         {
  591.             TransitionCall msgCall = new TransitionCall(targetCtxID, deleg);
  592.            
  593.             Message.PropagateCallContextFromThreadToMessage(msgCall);
  594.             //DBG Console.WriteLine("CallBackGeneric starting!");
  595.             IMessage retMsg = this.GetClientContextChain().SyncProcessMessage(msgCall);
  596.             if (null != retMsg) {
  597.                 Message.PropagateCallContextFromMessageToThread(retMsg);
  598.             }
  599.            
  600.             IMethodReturnMessage msg = retMsg as IMethodReturnMessage;
  601.             if (null != msg) {
  602.                 if (msg.Exception != null)
  603.                     throw msg.Exception;
  604.             }
  605.             //DBG Console.WriteLine("CallBackGeneric finished!");
  606.         }
  607.        
  608.         // This is the E-Call that we route the EE-CallBack request to
  609.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  610.         static internal extern void ExecuteCallBackInEE(IntPtr privateData);
  611.        
  612.         //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  613.         //~~~~~~~~~~~~~~~~~~~~ Context Local Store ~~~~~~~~~~~~~~~~~~~~
  614.         //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  615.        
  616.         private LocalDataStore MyLocalStore {
  617.             get {
  618.                 if (_localDataStore == null) {
  619.                     // It's OK to lock the manager here because it is going to lock
  620.                     // itself anyway.
  621.                     lock (_localDataStoreMgr) {
  622.                         if (_localDataStore == null) {
  623.                             // The local store has not yet been created for this thread.
  624.                             _localDataStore = _localDataStoreMgr.CreateLocalDataStore();
  625.                         }
  626.                     }
  627.                 }
  628.                 return _localDataStore;
  629.             }
  630.         }
  631.        
  632.         // All of these are exact shadows of corresponding ThreadLocalStore
  633.         // APIs.
  634.         /// <internalonly/>
  635.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  636.         public static LocalDataStoreSlot AllocateDataSlot()
  637.         {
  638.             return _localDataStoreMgr.AllocateDataSlot();
  639.         }
  640.         /// <internalonly/>
  641.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  642.         public static LocalDataStoreSlot AllocateNamedDataSlot(string name)
  643.         {
  644.             return _localDataStoreMgr.AllocateNamedDataSlot(name);
  645.         }
  646.         /// <internalonly/>
  647.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  648.         public static LocalDataStoreSlot GetNamedDataSlot(string name)
  649.         {
  650.             return _localDataStoreMgr.GetNamedDataSlot(name);
  651.         }
  652.         /// <internalonly/>
  653.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  654.         public static void FreeNamedDataSlot(string name)
  655.         {
  656.             _localDataStoreMgr.FreeNamedDataSlot(name);
  657.         }
  658.        
  659.         /// <internalonly/>
  660.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  661.         public static void SetData(LocalDataStoreSlot slot, object data)
  662.         {
  663.             Thread.CurrentContext.MyLocalStore.SetData(slot, data);
  664.         }
  665.        
  666.         /// <internalonly/>
  667.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  668.         public static object GetData(LocalDataStoreSlot slot)
  669.         {
  670.             return Thread.CurrentContext.MyLocalStore.GetData(slot);
  671.         }
  672.        
  673.         //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  674.         //~~~~~~~~~~~~~~~~~~~~ Context Statics ~~~~~~~~~~~~~~~~~~~~~~~~~~
  675.         //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  676.         private int ReserveSlot()
  677.         {
  678.             // This will be called with the context crst held so we
  679.             // don't take a lock here)
  680.             if (_ctxStatics == null) {
  681.                 // allocate the first bucket
  682.                 _ctxStatics = new object[STATICS_BUCKET_SIZE];
  683.                 // set next bucket field to null
  684.                 _ctxStatics[0] = null;
  685.                 _ctxStaticsFreeIndex = 1;
  686.                 _ctxStaticsCurrentBucket = 0;
  687.             }
  688.            
  689.             // See if we have to allocate a new bucket
  690.             if (_ctxStaticsFreeIndex == STATICS_BUCKET_SIZE) {
  691.                 object[] newBucket = new object[STATICS_BUCKET_SIZE];
  692.                
  693.                 // walk the chain to locate the last bucket
  694.                 object[] bucket = _ctxStatics;
  695.                 while (bucket[0] != null) {
  696.                     bucket = (object[])bucket[0];
  697.                 }
  698.                 // chain in the new bucket
  699.                 bucket[0] = newBucket;
  700.                 _ctxStaticsFreeIndex = 1;
  701.                 _ctxStaticsCurrentBucket++;
  702.             }
  703.            
  704.             // bucket# in highWord, index in lowWord
  705.             return _ctxStaticsFreeIndex++ | _ctxStaticsCurrentBucket << 16;
  706.         }
  707.         //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  708.         //~~~~~~~~~~~~~~~~~~~~ End Context Statics ~~~~~~~~~~~~~~~~~~~~~~
  709.         //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  710.        
  711.         //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  712.         //~~~~~~~~~~~~~~~~~~~~ Dynamic Sink Support ~~~~~~~~~~~~~~~~~~~~
  713.         //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  714.         // This allows people to register a property implementing IContributeDynamicSink
  715.         // with the remoting service. Based on the obj and ctx parameters, the property
  716.         // is asked to contribute a sink that is placed at some location in the path of
  717.         // remoting calls.
  718.         // The property may be unregistered, which implies that the sink will be dropped
  719.         // for subsequent remoting calls.
  720.         // If multiple properties are registered, their sinks may be called in an
  721.         // arbitrary order which may change between calls.
  722.         //
  723.         // If obj is non null then:
  724.         // - if it is a proxy, all calls made on the proxy are intercepted
  725.         // - if it is a real object, all calls on the object are intercepted
  726.         // - the ctx argument must be null
  727.         // If ctx is non-null then:
  728.         // - the obj argument must be null
  729.         // - all calls entering and leaving the context are intercepted
  730.         // If both ctx and obj are null then:
  731.         // - all calls entering and leaving all contexts are intercepted
  732.         //
  733.         /// <internalonly/>
  734.         [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.Infrastructure)]
  735.         public static bool RegisterDynamicProperty(IDynamicProperty prop, ContextBoundObject obj, Context ctx)
  736.         {
  737.             bool fRegistered = false;
  738.            
  739.             if (prop == null || prop.Name == null || !(prop is IContributeDynamicSink)) {
  740.                 throw new ArgumentNullException("prop");
  741.             }
  742.             if (obj != null && ctx != null) {
  743.                 // Exactly one of these is allowed to be non-null.
  744.                 throw new ArgumentException(Environment.GetResourceString("Argument_NonNullObjAndCtx"));
  745.             }
  746.             if (obj != null) {
  747.                 // ctx is ignored and must be null.
  748.                 fRegistered = IdentityHolder.AddDynamicProperty(obj, prop);
  749.             }
  750.             else {
  751.                 // ctx may or may not be null
  752.                 fRegistered = Context.AddDynamicProperty(ctx, prop);
  753.             }
  754.            
  755.             return fRegistered;
  756.         }
  757.        
  758.         /// <internalonly/>
  759.         [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.Infrastructure)]
  760.         public static bool UnregisterDynamicProperty(string name, ContextBoundObject obj, Context ctx)
  761.         {
  762.             bool fUnregister = false;
  763.            
  764.             // name, obj, ctx arguments should be exactly the same as a previous
  765.             // RegisterDynamicProperty call
  766.             if (name == null) {
  767.                 throw new ArgumentNullException("name");
  768.             }
  769.             if (obj != null && ctx != null) {
  770.                 throw new ArgumentException(Environment.GetResourceString("Argument_NonNullObjAndCtx"));
  771.             }
  772.             if (obj != null) {
  773.                 // ctx is ignored and must be null.
  774.                 fUnregister = IdentityHolder.RemoveDynamicProperty(obj, name);
  775.             }
  776.             else {
  777.                 // ctx may or may not be null
  778.                 fUnregister = Context.RemoveDynamicProperty(ctx, name);
  779.             }
  780.            
  781.             return fUnregister;
  782.         }
  783.        
  784. /*
  785.         *  Support for dynamic sinks at context level
  786.         *
  787.         */       
  788.         static internal bool AddDynamicProperty(Context ctx, IDynamicProperty prop)
  789.         {
  790.             // Check if we have a property by this name
  791.             if (ctx != null) {
  792.                 return ctx.AddPerContextDynamicProperty(prop);
  793.             }
  794.             else {
  795.                 // We have to add a sink that should fire for all contexts
  796.                 return AddGlobalDynamicProperty(prop);
  797.             }
  798.         }
  799.        
  800.         private bool AddPerContextDynamicProperty(IDynamicProperty prop)
  801.         {
  802.             if (_dphCtx == null) {
  803.                 DynamicPropertyHolder dph = new DynamicPropertyHolder();
  804.                 lock (this) {
  805.                     if (_dphCtx == null) {
  806.                         _dphCtx = dph;
  807.                     }
  808.                 }
  809.             }
  810.             return _dphCtx.AddDynamicProperty(prop);
  811.         }
  812.        
  813.         private static bool AddGlobalDynamicProperty(IDynamicProperty prop)
  814.         {
  815.             return _dphGlobal.AddDynamicProperty(prop);
  816.         }
  817.        
  818.         static internal bool RemoveDynamicProperty(Context ctx, string name)
  819.         {
  820.             if (ctx != null) {
  821.                 return ctx.RemovePerContextDynamicProperty(name);
  822.             }
  823.             else {
  824.                 // We have to remove a global property
  825.                 return RemoveGlobalDynamicProperty(name);
  826.             }
  827.         }
  828.        
  829.         private bool RemovePerContextDynamicProperty(string name)
  830.         {
  831.             // We have to remove a property for this context
  832.             if (_dphCtx == null) {
  833.                 throw new RemotingException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_Contexts_NoProperty"), name));
  834.             }
  835.             return _dphCtx.RemoveDynamicProperty(name);
  836.         }
  837.        
  838.         private static bool RemoveGlobalDynamicProperty(string name)
  839.         {
  840.             return _dphGlobal.RemoveDynamicProperty(name);
  841.         }
  842.        
  843. /*
  844.         *  Returns an array of context specific dynamic properties
  845.         *  registered for this context. The number of such properties
  846.         *  is designated by length of the returned array.
  847.         */       
  848.         internal virtual IDynamicProperty[] PerContextDynamicProperties {
  849.             get {
  850.                 if (_dphCtx == null) {
  851.                     return null;
  852.                 }
  853.                 else {
  854.                     return _dphCtx.DynamicProperties;
  855.                 }
  856.             }
  857.         }
  858.        
  859. /*
  860.         *  Returns an array of global dynamic properties
  861.         *  registered (for all contexts). The number of such properties
  862.         *  is designated by length of the returned array.
  863.         */       
  864.         static internal ArrayWithSize GlobalDynamicSinks {
  865.             get { return _dphGlobal.DynamicSinks; }
  866.         }
  867.        
  868.         internal virtual ArrayWithSize DynamicSinks {
  869.             get {
  870.                 if (_dphCtx == null) {
  871.                     return null;
  872.                 }
  873.                 else {
  874.                     return _dphCtx.DynamicSinks;
  875.                 }
  876.             }
  877.         }
  878.        
  879.         internal virtual bool NotifyDynamicSinks(IMessage msg, bool bCliSide, bool bStart, bool bAsync, bool bNotifyGlobals)
  880.         {
  881.             bool bHasDynamicSinks = false;
  882.            
  883.             if (bNotifyGlobals && (_dphGlobal.DynamicProperties != null)) {
  884.                 ArrayWithSize globalSinks = GlobalDynamicSinks;
  885.                 if (globalSinks != null) {
  886.                     DynamicPropertyHolder.NotifyDynamicSinks(msg, globalSinks, bCliSide, bStart, bAsync);
  887.                     bHasDynamicSinks = true;
  888.                 }
  889.             }
  890.            
  891.             ArrayWithSize perCtxSinks = DynamicSinks;
  892.             if (perCtxSinks != null) {
  893.                 DynamicPropertyHolder.NotifyDynamicSinks(msg, perCtxSinks, bCliSide, bStart, bAsync);
  894.                 bHasDynamicSinks = true;
  895.             }
  896.            
  897.             return bHasDynamicSinks;
  898.         }
  899.         // NotifyDynamicSinks
  900.         //******************** END: Dynamic Sink Support ********************
  901.     }
  902.    
  903.     //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  904.     //~~~~~~~~~~~~~~~~~~~ More Transition Support ~~~~~~~~~~~~~~~~~~~
  905.     //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  906.     // This class is used as the backing object that implements a delegate
  907.     // function to be used for internal call-backs. The delegate type must
  908.     // be CrossContextDelegate (void Func(void) below) since we are using
  909.     // the DoCallBackGeneric also as the underlying mechanism for the
  910.     // exposed cross-context callbacks.
  911.     [Serializable()]
  912.     internal class CallBackHelper
  913.     {
  914.         // Some flag definitions
  915.         internal const int RequestedFromEE = 1;
  916.         // callBack from EE
  917.         internal const int XDomainTransition = 256;
  918.         // going x-domain
  919.         internal bool IsEERequested {
  920.             get { return (_flags & RequestedFromEE) == RequestedFromEE; }
  921.             set {
  922.                 if (value) {
  923.                     _flags |= RequestedFromEE;
  924.                 }
  925.             }
  926.         }
  927.        
  928.         internal bool IsCrossDomain {
  929.             set {
  930.                 if (value) {
  931.                     _flags |= XDomainTransition;
  932.                 }
  933.             }
  934.         }
  935.        
  936.         int _flags;
  937.         IntPtr _privateData;
  938.        
  939.         internal CallBackHelper(IntPtr privateData, bool bFromEE, int targetDomainID)
  940.         {
  941.             this.IsEERequested = bFromEE;
  942.             this.IsCrossDomain = (targetDomainID != 0);
  943.             _privateData = privateData;
  944.         }
  945.        
  946.         internal void Func()
  947.         {
  948.             /*DBG Console.WriteLine("DelegHelper::Func CTX:"
  949.             + Int32.Format(Thread.CurrentContext.InternalContextID,"x")
  950.             +Environment.NewLine + "DMN: " + Int32.Format(Thread.GetDomainID(),"x")); DBG*/           
  951. if (IsEERequested) {
  952.                 //DBG Console.WriteLine("Executing EE callback ");
  953.                
  954.                 // EE requested this call back, call EE with its private data
  955.                 Context.ExecuteCallBackInEE(_privateData);
  956.                
  957.                 //DBG Console.WriteLine("Execute CallBackInEE returned: " + Int32.Format(_retVal,"x"));
  958.             }
  959.             else {
  960.                 //DBG Console.WriteLine("Executing non-EE internal callback");
  961.             }
  962.         }
  963.     }
  964.     // class CallBackHelper
  965. }
  966. //nameSpace Remoting

Developer Fusion