Code:
/ FXUpdate3074 / FXUpdate3074 / 1.1 / untmp / whidbey / QFE / 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: passign 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: passign 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: passign 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 assertt 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); } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- EndpointDiscoveryBehavior.cs
- BuildProviderUtils.cs
- SimpleWebHandlerParser.cs
- TypeDescriptionProviderAttribute.cs
- SoapBinding.cs
- OneWayChannelFactory.cs
- MetafileHeader.cs
- DbQueryCommandTree.cs
- ThrowHelper.cs
- RowType.cs
- DataListItemCollection.cs
- EventLogPermission.cs
- EmptyEnumerator.cs
- EmbeddedMailObject.cs
- ContainerUIElement3D.cs
- CalendarDay.cs
- CommandTreeTypeHelper.cs
- CaseInsensitiveHashCodeProvider.cs
- MetadataItem_Static.cs
- LogAppendAsyncResult.cs
- SponsorHelper.cs
- HostVisual.cs
- UIElementParaClient.cs
- TransformProviderWrapper.cs
- WebEventTraceProvider.cs
- Matrix.cs
- DocumentCollection.cs
- ClientConvert.cs
- PropertyPath.cs
- ContentFilePart.cs
- loginstatus.cs
- ToolBarPanel.cs
- DrawingVisual.cs
- PageBuildProvider.cs
- FileInfo.cs
- ChildTable.cs
- EdmScalarPropertyAttribute.cs
- DictionarySectionHandler.cs
- ResolveNameEventArgs.cs
- HtmlShimManager.cs
- OciHandle.cs
- Range.cs
- MenuItem.cs
- LoginStatusDesigner.cs
- DelegateTypeInfo.cs
- HelpKeywordAttribute.cs
- ScriptMethodAttribute.cs
- WindowsFormsDesignerOptionService.cs
- TheQuery.cs
- BitmapPalettes.cs
- RichTextBoxAutomationPeer.cs
- TextEvent.cs
- QueryPageSettingsEventArgs.cs
- TypeExtension.cs
- HostSecurityManager.cs
- IImplicitResourceProvider.cs
- AssemblyFilter.cs
- DynamicPropertyHolder.cs
- ResXFileRef.cs
- Condition.cs
- ICspAsymmetricAlgorithm.cs
- DesignerVerbCollection.cs
- SerialReceived.cs
- GlyphElement.cs
- SerializationEventsCache.cs
- DispatchWrapper.cs
- RuleInfoComparer.cs
- HyperLinkStyle.cs
- WindowsIdentity.cs
- SafeReversePInvokeHandle.cs
- FieldToken.cs
- PartialTrustVisibleAssemblyCollection.cs
- LineSegment.cs
- WindowsListViewItemCheckBox.cs
- uribuilder.cs
- SqlMetaData.cs
- TableLayoutSettingsTypeConverter.cs
- CodeNamespace.cs
- OutOfMemoryException.cs
- IisTraceWebEventProvider.cs
- IList.cs
- XPathException.cs
- KeyGesture.cs
- OracleCommandBuilder.cs
- StringArrayConverter.cs
- DataGridLinkButton.cs
- ComponentTray.cs
- CodeDomSerializer.cs
- DataReceivedEventArgs.cs
- ActionFrame.cs
- BrushConverter.cs
- RecipientInfo.cs
- ImportCatalogPart.cs
- SecurityRequiresReviewAttribute.cs
- relpropertyhelper.cs
- GridPattern.cs
- HttpCookieCollection.cs
- WebPartsPersonalizationAuthorization.cs
- Knowncolors.cs
- SqlPersistenceProviderFactory.cs