Code:
/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / clr / src / BCL / System / Runtime / Remoting / CrossContextChannel.cs / 1 / CrossContextChannel.cs
// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== // // Remoting Infrastructure Sink for making calls across context // boundaries. // namespace System.Runtime.Remoting.Channels { using System; using System.Collections; using System.Threading; using System.Runtime.Remoting; using System.Runtime.Remoting.Contexts; using System.Runtime.Remoting.Messaging; using System.Runtime.Serialization; /* package scope */ // deliberately not [serializable] internal class CrossContextChannel : InternalSink, IMessageSink { private const String _channelName = "XCTX"; private const int _channelCapability = 0; private const String _channelURI = "XCTX_URI"; private static CrossContextChannel messageSink { get { return Thread.GetDomain().RemotingData.ChannelServicesData.xctxmessageSink; } set { Thread.GetDomain().RemotingData.ChannelServicesData.xctxmessageSink = value; } } private static Object staticSyncObject = new Object(); private static InternalCrossContextDelegate s_xctxDel = new InternalCrossContextDelegate(SyncProcessMessageCallback); internal static IMessageSink MessageSink { get { if (messageSink == null) { CrossContextChannel tmpSink = new CrossContextChannel(); lock (staticSyncObject) { if (messageSink == null) { messageSink = tmpSink; } } //Interlocked.CompareExchange(out messageSink, tmpSink, null); } return messageSink; } } internal static Object SyncProcessMessageCallback(Object[] args) { IMessage reqMsg = args[0] as IMessage; Context srvCtx = args[1] as Context; IMessage replyMsg = null; // If profiling of remoting is active, must tell the profiler that we have received // a message. if (RemotingServices.CORProfilerTrackRemoting()) { Guid g = Guid.Empty; if (RemotingServices.CORProfilerTrackRemotingCookie()) { Object obj = reqMsg.Properties["CORProfilerCookie"]; if (obj != null) { g = (Guid) obj; } } RemotingServices.CORProfilerRemotingServerReceivingMessage(g, false); } Message.DebugOut("::::::::::::::::::::::::: CrossContext Channel: passing to ServerContextChain"); // Server side notifications for dynamic sinks are done // in the x-context channel ... this is to maintain // symmetry of the point of notification between // the client and server context srvCtx.NotifyDynamicSinks( reqMsg, false, // bCliSide true, // bStart false, // bAsync true); // bNotifyGlobals replyMsg = srvCtx.GetServerContextChain().SyncProcessMessage(reqMsg); srvCtx.NotifyDynamicSinks( replyMsg, false, // bCliSide false, // bStart false, // bAsync true); // bNotifyGlobals Message.DebugOut("::::::::::::::::::::::::: CrossContext Channel: back from ServerContextChain"); // If profiling of remoting is active, must tell the profiler that we are sending a // reply message. if (RemotingServices.CORProfilerTrackRemoting()) { Guid g; RemotingServices.CORProfilerRemotingServerSendingReply(out g, false); if (RemotingServices.CORProfilerTrackRemotingCookie()) { replyMsg.Properties["CORProfilerCookie"] = g; } } return replyMsg; } public virtual IMessage SyncProcessMessage(IMessage reqMsg) { Object[] args = new Object[] { null, null }; IMessage replyMsg = null; try { Message.DebugOut("\n::::::::::::::::::::::::: CrossContext Channel: Sync call starting"); IMessage errMsg = ValidateMessage(reqMsg); if (errMsg != null) { return errMsg; } ServerIdentity srvID = GetServerIdentity(reqMsg); Message.DebugOut("Got Server identity \n"); BCLDebug.Assert(null != srvID,"null != srvID"); BCLDebug.Assert(null != srvID.ServerContext, "null != srvID.ServerContext"); args[0] = reqMsg; args[1] = srvID.ServerContext; replyMsg = (IMessage) Thread.CurrentThread.InternalCrossContextCallback(srvID.ServerContext, s_xctxDel, args); } catch(Exception e) { Message.DebugOut("Arrgh.. XCTXSink::throwing exception " + e + "\n"); replyMsg = new ReturnMessage(e, (IMethodCallMessage)reqMsg); if (reqMsg!=null) { ((ReturnMessage)replyMsg).SetLogicalCallContext( (LogicalCallContext) reqMsg.Properties[Message.CallContextKey]); } } Message.DebugOut("::::::::::::::::::::::::::: CrossContext Channel: Sync call returning!!\n"); return replyMsg; } internal static Object AsyncProcessMessageCallback(Object[] args) { AsyncWorkItem workItem = null; IMessage reqMsg = (IMessage) args[0]; IMessageSink replySink = (IMessageSink) args[1]; Context oldCtx = (Context) args[2]; Context srvCtx = (Context) args[3]; IMessageCtrl msgCtrl = null; // we use the work item just as our replySink in this case if (replySink != null) { workItem = new AsyncWorkItem(replySink, oldCtx); } Message.DebugOut("::::::::::::::::::::::::: CrossContext Channel: passing to ServerContextChain"); srvCtx.NotifyDynamicSinks( reqMsg, false, // bCliSide true, // bStart true, // bAsync true); // bNotifyGlobals // call the server context chain msgCtrl = srvCtx.GetServerContextChain().AsyncProcessMessage( reqMsg, (IMessageSink)workItem); // Note: for async calls, we will do the return notification // for dynamic properties only when the async call // completes (i.e. when the replySink gets called) Message.DebugOut("::::::::::::::::::::::::: CrossContext Channel: back from ServerContextChain"); return msgCtrl; } public virtual IMessageCtrl AsyncProcessMessage(IMessage reqMsg, IMessageSink replySink) { Message.DebugOut("::::::::::::::::::::::::::: CrossContext Channel: Async call starting!!\n"); // One way Async notifications may potentially pass a null reply sink. IMessage errMsg = ValidateMessage(reqMsg); Object[] args = new Object[] { null, null, null, null }; IMessageCtrl msgCtrl = null; if (errMsg != null) { if (replySink!=null) { replySink.SyncProcessMessage(errMsg); } } else { ServerIdentity srvID = GetServerIdentity(reqMsg); // If active, notify the profiler that an asynchronous remoting message was received. if (RemotingServices.CORProfilerTrackRemotingAsync()) { Guid g = Guid.Empty; if (RemotingServices.CORProfilerTrackRemotingCookie()) { Object obj = reqMsg.Properties["CORProfilerCookie"]; if (obj != null) { g = (Guid) obj; } } RemotingServices.CORProfilerRemotingServerReceivingMessage(g, true); // Only wrap the replySink if the call wants a reply if (replySink != null) { // Now wrap the reply sink in our own so that we can notify the profiler of // when the reply is sent. Upon invocation, it will notify the profiler // then pass control on to the replySink passed in above. IMessageSink profSink = new ServerAsyncReplyTerminatorSink(replySink); // Replace the reply sink with our own replySink = profSink; } } Context srvCtx = srvID.ServerContext; if (srvCtx.IsThreadPoolAware) { // this is the case when we do not queue the work item since the // server context claims to be doing its own threading. args[0] = reqMsg; args[1] = replySink; args[2] = Thread.CurrentContext; args[3] = srvCtx; InternalCrossContextDelegate xctxDel = new InternalCrossContextDelegate(AsyncProcessMessageCallback); msgCtrl = (IMessageCtrl) Thread.CurrentThread.InternalCrossContextCallback(srvCtx, xctxDel, args); } else { AsyncWorkItem workItem = null; // This is the case where we take care of returning the calling // thread asap by using the ThreadPool for completing the call. // we use a more elaborate WorkItem and delegate the work to the thread pool workItem = new AsyncWorkItem(reqMsg, replySink, Thread.CurrentContext, srvID); WaitCallback threadFunc = new WaitCallback(workItem.FinishAsyncWork); // Note: Dynamic sinks are notified in the threadFunc ThreadPool.QueueUserWorkItem(threadFunc); } } Message.DebugOut("::::::::::::::::::::::::::: CrossContext Channel: Async call returning!!\n"); return msgCtrl; } // AsyncProcessMessage internal static Object DoAsyncDispatchCallback(Object[] args) { AsyncWorkItem workItem = null; IMessage reqMsg = (IMessage) args[0]; IMessageSink replySink = (IMessageSink) args[1]; Context oldCtx = (Context) args[2]; Context srvCtx = (Context) args[3]; IMessageCtrl msgCtrl = null; // we use the work item just as our replySink in this case if (replySink != null) { workItem = new AsyncWorkItem(replySink, oldCtx); } Message.DebugOut("::::::::::::::::::::::::: CrossContext Channel: passing to ServerContextChain"); // call the server context chain msgCtrl = srvCtx.GetServerContextChain().AsyncProcessMessage(reqMsg, (IMessageSink)workItem); Message.DebugOut("::::::::::::::::::::::::: CrossContext Channel: back from ServerContextChain"); return msgCtrl; } internal static IMessageCtrl DoAsyncDispatch(IMessage reqMsg, IMessageSink replySink) { Object[] args = new Object[] { null, null, null, null }; ServerIdentity srvID = GetServerIdentity(reqMsg); // If active, notify the profiler that an asynchronous remoting message was received. if (RemotingServices.CORProfilerTrackRemotingAsync()) { Guid g = Guid.Empty; if (RemotingServices.CORProfilerTrackRemotingCookie()) { Object obj = reqMsg.Properties["CORProfilerCookie"]; if (obj != null) g = (Guid) obj; } RemotingServices.CORProfilerRemotingServerReceivingMessage(g, true); // Only wrap the replySink if the call wants a reply if (replySink != null) { // Now wrap the reply sink in our own so that we can notify the profiler of // when the reply is sent. Upon invocation, it will notify the profiler // then pass control on to the replySink passed in above. IMessageSink profSink = new ServerAsyncReplyTerminatorSink(replySink); // Replace the reply sink with our own replySink = profSink; } } IMessageCtrl msgCtrl = null; Context srvCtx = srvID.ServerContext; //if (srvCtx.IsThreadPoolAware) //{ // this is the case when we do not queue the work item since the // server context claims to be doing its own threading. args[0] = reqMsg; args[1] = replySink; args[2] = Thread.CurrentContext; args[3] = srvCtx; InternalCrossContextDelegate xctxDel = new InternalCrossContextDelegate(DoAsyncDispatchCallback); msgCtrl = (IMessageCtrl) Thread.CurrentThread.InternalCrossContextCallback(srvCtx, xctxDel, args); //} return msgCtrl; } // DoDispatch public IMessageSink NextSink { get { // We are a terminating sink for this chain. return null; } } } /* package */ internal class AsyncWorkItem : IMessageSink { // the replySink passed in to us in AsyncProcessMsg private IMessageSink _replySink; // the server identity we are calling private ServerIdentity _srvID; // the original context of the thread calling AsyncProcessMsg private Context _oldCtx; private LogicalCallContext _callCtx; // the request msg passed in private IMessage _reqMsg; internal AsyncWorkItem(IMessageSink replySink, Context oldCtx) : this(null, replySink, oldCtx, null) { } internal AsyncWorkItem(IMessage reqMsg, IMessageSink replySink, Context oldCtx, ServerIdentity srvID) { _reqMsg = reqMsg; _replySink = replySink; _oldCtx = oldCtx; _callCtx = CallContext.GetLogicalCallContext(); _srvID = srvID; } internal static Object SyncProcessMessageCallback(Object[] args) { IMessageSink replySink = (IMessageSink) args[0]; IMessage msg = (IMessage) args[1]; return replySink.SyncProcessMessage(msg); } public virtual IMessage SyncProcessMessage(IMessage msg) { // This gets called when the called object finishes the AsyncWork... // This is called irrespective of whether we delegated the initial // work to a thread pool thread or not. Quite likely it will be // called on a user thread (i.e. a thread different from the // forward call thread) // we just switch back to the old context before calling // the next replySink IMessage retMsg = null; if (_replySink != null) { // This assert covers the common case (ThreadPool) // and checks that the reply thread for the async call // indeed emerges from the server context. BCLDebug.Assert( (_srvID == null) || (_srvID.ServerContext == Thread.CurrentContext), "Thread expected to be in the server context!"); // Call the dynamic sinks to notify that the async call // has completed Thread.CurrentContext.NotifyDynamicSinks( msg, // this is the async reply false, // bCliSide false, // bStart true, // bAsync true); // bNotifyGlobals Object[] args = new Object[] { _replySink, msg }; InternalCrossContextDelegate xctxDel = new InternalCrossContextDelegate(SyncProcessMessageCallback); retMsg = (IMessage) Thread.CurrentThread.InternalCrossContextCallback(_oldCtx, xctxDel, args); } return retMsg; } public virtual IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink) { // Can't call the reply sink asynchronously! throw new NotSupportedException( Environment.GetResourceString("NotSupported_Method")); } public IMessageSink NextSink { get { return _replySink; } } internal static Object FinishAsyncWorkCallback(Object[] args) { AsyncWorkItem This = (AsyncWorkItem) args[0]; Context srvCtx = This._srvID.ServerContext; LogicalCallContext threadPoolCallCtx = CallContext.SetLogicalCallContext(This._callCtx); // Call the server context chain Async. We provide workItem as our // replySink ... this will cause the replySink.ProcessMessage // to switch back to the context of the original caller thread. // Call the dynamic sinks to notify that the async call // is starting srvCtx.NotifyDynamicSinks( This._reqMsg, false, // bCliSide true, // bStart true, // bAsync true); // bNotifyGlobals // < IMessageCtrl ctrl = srvCtx.GetServerContextChain().AsyncProcessMessage( This._reqMsg, (IMessageSink)This); // change back to the old context CallContext.SetLogicalCallContext(threadPoolCallCtx); return null; } /* package */ internal virtual void FinishAsyncWork(Object stateIgnored) { InternalCrossContextDelegate xctxDel = new InternalCrossContextDelegate(FinishAsyncWorkCallback); Object[] args = new Object[] { this }; Thread.CurrentThread.InternalCrossContextCallback(_srvID.ServerContext, xctxDel, args); } } }
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- TemplateInstanceAttribute.cs
- CustomErrorsSection.cs
- InstanceDescriptor.cs
- EventDescriptor.cs
- WorkflowElementDialog.cs
- Point4DConverter.cs
- Subtree.cs
- BuildProviderAppliesToAttribute.cs
- XamlToRtfWriter.cs
- ReadOnlyDataSource.cs
- DbProviderManifest.cs
- TemplateBindingExtension.cs
- Parser.cs
- TextureBrush.cs
- SafeFileMappingHandle.cs
- XamlWriter.cs
- TextElement.cs
- ClientReliableChannelBinder.cs
- BuildResult.cs
- DesignerActionMethodItem.cs
- ComponentResourceKeyConverter.cs
- Panel.cs
- ControlCollection.cs
- RC2.cs
- BookmarkTable.cs
- Duration.cs
- BooleanFunctions.cs
- QuadraticBezierSegment.cs
- xmlsaver.cs
- SqlComparer.cs
- EntitySetBaseCollection.cs
- InfocardClientCredentials.cs
- DurableInstanceProvider.cs
- ComplexObject.cs
- Pair.cs
- ProjectionPathBuilder.cs
- DecoderFallbackWithFailureFlag.cs
- Model3DGroup.cs
- ImpersonationContext.cs
- NumericUpDown.cs
- HybridDictionary.cs
- LocalizableAttribute.cs
- ScrollBarAutomationPeer.cs
- DESCryptoServiceProvider.cs
- DataRowChangeEvent.cs
- TransformGroup.cs
- ChildTable.cs
- SoapExtensionImporter.cs
- LineBreak.cs
- PrinterUnitConvert.cs
- Group.cs
- SharedPerformanceCounter.cs
- WhitespaceRuleReader.cs
- Version.cs
- TempFiles.cs
- PrtTicket_Public_Simple.cs
- LayoutTableCell.cs
- OdbcConnection.cs
- PreviousTrackingServiceAttribute.cs
- ActivityExecutorSurrogate.cs
- XmlAttributeCollection.cs
- PartitionResolver.cs
- StringPropertyBuilder.cs
- WhitespaceRule.cs
- StringKeyFrameCollection.cs
- TreeNodeCollection.cs
- GuidelineSet.cs
- ClientSettingsStore.cs
- ConnectionOrientedTransportBindingElement.cs
- DataGridViewAutoSizeModeEventArgs.cs
- DataGridViewRowStateChangedEventArgs.cs
- CustomError.cs
- ExceptionHandler.cs
- XmlDataCollection.cs
- XmlDataContract.cs
- _FtpControlStream.cs
- SiteMapProvider.cs
- Parallel.cs
- Stylus.cs
- FrameAutomationPeer.cs
- FullTextBreakpoint.cs
- PlanCompiler.cs
- SocketElement.cs
- HashSetEqualityComparer.cs
- CookielessHelper.cs
- WebPartZoneBase.cs
- Int32.cs
- CopyNodeSetAction.cs
- ConsoleKeyInfo.cs
- AbstractDataSvcMapFileLoader.cs
- MediaTimeline.cs
- MethodBuilderInstantiation.cs
- ConfigurationSettings.cs
- CriticalFinalizerObject.cs
- DefaultPropertyAttribute.cs
- RoleService.cs
- Multiply.cs
- FontUnit.cs
- MSHTMLHost.cs
- DataProviderNameConverter.cs