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
- HwndKeyboardInputProvider.cs
- MethodInfo.cs
- ExpressionBuilderContext.cs
- CompiledELinqQueryState.cs
- ZipIOZip64EndOfCentralDirectoryBlock.cs
- BitmapEffectDrawing.cs
- ThreadExceptionDialog.cs
- ChannelCacheSettings.cs
- FormViewInsertedEventArgs.cs
- TextOptions.cs
- Lookup.cs
- PipeStream.cs
- PeerName.cs
- RefreshInfo.cs
- PropertyReference.cs
- ConfigXmlText.cs
- SystemDiagnosticsSection.cs
- DbConnectionStringCommon.cs
- HighlightVisual.cs
- XmlSchemaSequence.cs
- ManagementScope.cs
- OleDbPropertySetGuid.cs
- ValueExpressions.cs
- DependsOnAttribute.cs
- CompareValidator.cs
- XmlBinaryReaderSession.cs
- EditorPartCollection.cs
- EventManager.cs
- CodeNamespaceImportCollection.cs
- FilterQuery.cs
- FixedElement.cs
- VisualTreeHelper.cs
- EntityContainerEmitter.cs
- RelationshipConstraintValidator.cs
- TextBlockAutomationPeer.cs
- DllNotFoundException.cs
- PeerNameRegistration.cs
- HttpConfigurationContext.cs
- UserControlDocumentDesigner.cs
- ViewgenGatekeeper.cs
- HttpWriter.cs
- ThreadStateException.cs
- DateTimeFormat.cs
- AcceleratedTokenProvider.cs
- CroppedBitmap.cs
- DataGridAddNewRow.cs
- XmlDownloadManager.cs
- DataSourceSerializationException.cs
- CrossSiteScriptingValidation.cs
- CryptoHelper.cs
- Soap.cs
- CompilerHelpers.cs
- SmtpNetworkElement.cs
- GenericPrincipal.cs
- ColumnResizeUndoUnit.cs
- ToolboxComponentsCreatingEventArgs.cs
- AjaxFrameworkAssemblyAttribute.cs
- NamedObject.cs
- mansign.cs
- DynamicVirtualDiscoSearcher.cs
- DictionaryEditChange.cs
- AuthenticationService.cs
- ResourceDescriptionAttribute.cs
- PixelShader.cs
- WebBrowsableAttribute.cs
- ProfessionalColorTable.cs
- DataGridDesigner.cs
- SimpleMailWebEventProvider.cs
- TreeNodeBindingCollection.cs
- DateTimePicker.cs
- MembershipUser.cs
- RegexBoyerMoore.cs
- SqlGatherConsumedAliases.cs
- SQLDateTimeStorage.cs
- SequentialOutput.cs
- RowCache.cs
- xmlsaver.cs
- EvidenceTypeDescriptor.cs
- MobileRedirect.cs
- LineInfo.cs
- WindowsFormsSectionHandler.cs
- EtwTrackingBehaviorElement.cs
- WorkflowInstanceExtensionProvider.cs
- Metafile.cs
- DesignerValidatorAdapter.cs
- RepeatInfo.cs
- XmlDataSourceNodeDescriptor.cs
- DataGridViewRowHeightInfoNeededEventArgs.cs
- TouchEventArgs.cs
- TextAdaptor.cs
- MetadataArtifactLoaderXmlReaderWrapper.cs
- HotCommands.cs
- HttpCookiesSection.cs
- COM2FontConverter.cs
- ObfuscateAssemblyAttribute.cs
- CompilationSection.cs
- WebSysDefaultValueAttribute.cs
- EDesignUtil.cs
- SynchronizationLockException.cs
- WithStatement.cs