/* * Execute is called to complete a work item (sync or async). * Execute assumes that the context is set correctly and the lock * is taken (i.e. it makes no policy decisions) * * It is called from the following 3 points: * 1. thread pool thread executing the callback for an async item * 2. calling thread executing the callback for a queued sync item * 3. calling thread directly calling Execute for a non-queued sync item */ internal virtual void Execute() { // Execute should be called with the domain policy enforced // i.e. a Synchronization domain should be locked etc ... BCLDebug.Assert(IsSignaled(), "IsSignaled()"); ContextTransitionFrame frame = new ContextTransitionFrame(); Thread.CurrentThread.EnterContext(_ctx, ref frame); LogicalCallContext oldCallCtx = CallContext.SetLogicalCallContext(_callCtx); if (IsAsync()) { //DBGConsole.WriteLine(Thread.CurrentThread.GetHashCode()+"] AsyncWork.Execute"); _nextSink.AsyncProcessMessage(_reqMsg, _replySink); } else if (_nextSink != null) { //DBGConsole.WriteLine(Thread.CurrentThread.GetHashCode()+"] SyncWork.Execute"); _replyMsg = _nextSink.SyncProcessMessage(_reqMsg); } CallContext.SetLogicalCallContext(oldCallCtx); Thread.CurrentThread.ReturnToContext(ref frame); }
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 ContextTransitionFrame frame = new ContextTransitionFrame(); Thread.CurrentThread.EnterContext(_oldCtx, ref frame); retMsg = _replySink.SyncProcessMessage(msg); Thread.CurrentThread.ReturnToContext(ref frame); } return retMsg; }
} // AsyncProcessMessage internal static IMessageCtrl DoAsyncDispatch(IMessage reqMsg, IMessageSink replySink) { ServerIdentity srvID = GetServerIdentity(reqMsg); AsyncWorkItem workItem = null; // 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. Context oldCtx = Thread.CurrentContext; // change to server object context ContextTransitionFrame frame = new ContextTransitionFrame(); Thread.CurrentThread.EnterContext(srvID.ServerContext, ref frame); // 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 IMessageCtrl msgCtrl = srvID.ServerContext.GetServerContextChain().AsyncProcessMessage(reqMsg, (IMessageSink)workItem); Message.DebugOut("::::::::::::::::::::::::: CrossContext Channel: back from ServerContextChain"); // chain back to the dispatch thread context Thread.CurrentThread.ReturnToContext(ref frame); //} return msgCtrl; } // DoDispatch
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); IMessageCtrl msgCtrl=null; if (errMsg != null) { if (replySink!=null) { replySink.SyncProcessMessage(errMsg); } } else { ServerIdentity srvID = GetServerIdentity(reqMsg); AsyncWorkItem workItem = null; // 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. Context oldCtx = Thread.CurrentContext; // change to server object context ContextTransitionFrame frame = new ContextTransitionFrame(); srvCtx = srvID.ServerContext; Thread.CurrentThread.EnterContext(srvCtx, ref frame); // 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"); // chain back to the dispatch thread context Thread.CurrentThread.ReturnToContext(ref frame); } else { // 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); msgCtrl = null; } } Message.DebugOut("::::::::::::::::::::::::::: CrossContext Channel: Async call returning!!\n"); return msgCtrl; } // AsyncProcessMessage
public virtual IMessage SyncProcessMessage(IMessage reqMsg) { 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"); bool fEnteredContext = false; ContextTransitionFrame frame = new ContextTransitionFrame(); try { Context srvCtx = srvID.ServerContext; Thread.CurrentThread.EnterContext(srvCtx, ref frame); fEnteredContext = true; // 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; } } } finally { if(fEnteredContext) { Thread.CurrentThread.ReturnToContext(ref frame); } } } 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; }
public virtual IMessage SyncProcessMessage(IMessage reqMsg) { // we just switch back to the old context before calling // the next replySink IMessage retMsg = null; if (_replySink != null) { ContextTransitionFrame frame = new ContextTransitionFrame(); Thread.CurrentThread.EnterContext(_cliCtx, ref frame); // Call the dynamic sinks to notify that the async call // has completed Thread.CurrentContext.NotifyDynamicSinks( reqMsg, // this is the async reply true, // bCliSide false, // bStart true, // bAsync true); // bNotifyGlobals // call the original reply sink now that we have moved // to the correct client context retMsg = _replySink.SyncProcessMessage(reqMsg); // return the thread to its earlier context Thread.CurrentThread.ReturnToContext(ref frame); } return retMsg; }
public virtual IMessageCtrl AsyncProcessMessage(IMessage reqMsg, IMessageSink replySink) { Message.DebugOut("+++++++++++++++++++++++++ CliCtxTerminator: AsyncProcessMsg"); IMessage errMsg = ValidateMessage(reqMsg); IMessageCtrl msgCtrl=null; if (errMsg == null) { errMsg = DisallowAsyncActivation(reqMsg); } if (errMsg != null) { if (replySink != null) { replySink.SyncProcessMessage(errMsg); } } else { // If active, notify the profiler that an asynchronous remoting call is being made. if (RemotingServices.CORProfilerTrackRemotingAsync()) { Guid g; RemotingServices.CORProfilerRemotingClientSendingMessage(out g, true); if (RemotingServices.CORProfilerTrackRemotingCookie()) reqMsg.Properties["CORProfilerCookie"] = g; // 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 received. Upon invocation, it will notify the profiler // then pass control on to the replySink passed in above. IMessageSink profSink = new ClientAsyncReplyTerminatorSink(replySink); // Replace the reply sink with our own replySink = profSink; } } Context cliCtx = Thread.CurrentContext; // Notify dynamic sinks that an Async call started cliCtx.NotifyDynamicSinks( reqMsg, true, // bCliSide true, // bStart true, // bAsync true); // bNotifyGlobals // Intercept the async reply to force the thread back // into the client-context before it executes further // and to notify dynamic sinks if (replySink != null) { replySink = new AsyncReplySink(replySink, cliCtx); } // Forward call to the channel. IMessageSink channelSink = GetChannelSink(reqMsg); // Move to default context unless we are going through // the cross-context channel ContextTransitionFrame frame = new ContextTransitionFrame(); if (channelSink != CrossContextChannel.MessageSink) { Thread.CurrentThread.EnterContext( Context.DefaultContext, ref frame); } msgCtrl = channelSink.AsyncProcessMessage(reqMsg, replySink); if (channelSink != CrossContextChannel.MessageSink) { Thread.CurrentThread.ReturnToContext(ref frame); } } return msgCtrl; }
} // CreateProxyForDomain internal static ObjRef CreateDataForDomain(int appDomainId, IntPtr defCtxID) { // This is a subroutine of CreateProxyForDomain // so we can segregate the object references // from different app domains into different frames. This is // important for the app domain leak checking code. Message.DebugOut("Creating proxy for domain " + appDomainId + "\n"); bool bNeedToReset = false; ObjRef objRef = null; ContextTransitionFrame frame = new ContextTransitionFrame(); try { RegisterWellKnownChannels(); // Set the current context to the given default Context // (of the new AppDomain). Thread.CurrentThread.EnterContextInternal(null, defCtxID, appDomainId, ref frame); bNeedToReset = true; // Ensure that the well known channels are registered in this domain too RegisterWellKnownChannels(); // Marshal the app domain object objRef = MarshalInternal( Thread.CurrentContext.AppDomain, null, null); // Set the current context to the old context Thread.CurrentThread.ReturnToContext(ref frame); bNeedToReset = false; } finally { // Restore the old app domain if (bNeedToReset) { Thread.CurrentThread.ReturnToContext(ref frame); } } return objRef; } // CreateDataForDomain
// This function is called by ActivationServices in case // the activation needs to be within the same appdomain. These // are only for ContextBound types. // It is also called to do satisfy remote incoming requests from // the activation services. These could be for both ContextBound // and MarshalByRef types. internal static IConstructionReturnMessage DoCrossContextActivation( IConstructionCallMessage reqMsg) { bool bCtxBound = reqMsg.ActivationType.IsContextful; ContextTransitionFrame frame = new ContextTransitionFrame(); if (bCtxBound) { // If the type is context bound, we need to create // the appropriate context and activate the object inside // it. // Create a new Context Context serverContext = new Context(); ArrayList list = (ArrayList) reqMsg.ContextProperties; Assembly asm = null; for (int i=0; i<list.Count; i++) { IContextProperty prop = list[i] as IContextProperty; if (null == prop) { throw new RemotingException( Environment.GetResourceString( "Remoting_Activation_BadAttribute")); } asm = prop.GetType().Assembly; // Make a security check to ensure that the context property // is from a trusted assembly! CheckForInfrastructurePermission(asm); // This ensures that we don't try to add duplicate // attributes (eg. type attributes common on both client // and server end) if (serverContext.GetProperty(prop.Name) == null) { serverContext.SetProperty(prop); } } // No more property changes to the server context from here. serverContext.Freeze(); // (This seems like an overkill but that is how it is spec-ed) // Ask each of the properties in the context we formed from // if it is happy with the current context. for (int i=0; i<list.Count;i++) { if (!((IContextProperty)list[i]).IsNewContextOK( serverContext)) { throw new RemotingException( Environment.GetResourceString( "Remoting_Activation_PropertyUnhappy")); } } // Change to server context Thread.CurrentThread.EnterContext(serverContext, ref frame); } // call the first sink in the server context chain IMethodReturnMessage retMsg = (IMethodReturnMessage) Thread.CurrentContext.GetServerContextChain().SyncProcessMessage(reqMsg); // The return message may not be of type // IConstructionReturnMessage if an exception happens // in the sink chains. Exception e = null; IConstructionReturnMessage replyMsg = retMsg as IConstructionReturnMessage; if (null == replyMsg) { if (retMsg != null) { e = retMsg.Exception; } else { e = new RemotingException( Environment.GetResourceString( "Remoting_Activation_Failed")); } replyMsg = new ConstructorReturnMessage(e,null); // We have created our own message ... transfer the callcontext // from the request message. ((ConstructorReturnMessage)replyMsg).SetLogicalCallContext( (LogicalCallContext) reqMsg.Properties[Message.CallContextKey]); } if (bCtxBound) { Thread.CurrentThread.ReturnToContext(ref frame); } return replyMsg; }
internal extern bool EnterContextInternal(Context ctx, IntPtr id, Int32 appDomainID, ref ContextTransitionFrame frame);
internal extern bool ReturnToContext(ref ContextTransitionFrame frame);
internal void EnterContext(Context newContext, ref ContextTransitionFrame frame) { EnterContextInternal(newContext, newContext.InternalContextID, 0, ref frame); // The newContext parameter is passed in just to keep GC from // collecting a new context when we are trying to enter it. // By the time this returns, the m_Context field in the managed // thread is already set to the newContext ... so from there on // the newContext is rooted. // EnterContextInternal is directly called by the X-AppDomain // channel since it only has the target context-id and not the // context object itself (since the latter is in another domain) // It is also called directly when we are bootstrapping a new // AppDomain w.r.t. remoting (in CreateProxyForDomain). In both // these cases, the newContext is null. }
} // DoDispatch internal byte[] DoTransitionDispatch( byte[] reqStmBuff, SmuggledMethodCallMessage smuggledMcm, out SmuggledMethodReturnMessage smuggledMrm) { // Note: To be safe w.r.t. the app domain leak code, this frame // should have no non-agile references in it. ContextTransitionFrame frame = new ContextTransitionFrame(); // change to server domain Thread.CurrentThread.EnterContextInternal( null, _srvContextID, _srvDomainID, ref frame); byte[] retBuff = null; smuggledMrm = null; try { Message.DebugOut("#### : changed to Server Domain :: "+ (Thread.CurrentContext.InternalContextID).ToString("X") ); retBuff = DoDispatch(reqStmBuff, smuggledMcm, out smuggledMrm); } catch (Exception e) { // This will catch exceptions thrown by the infrastructure, // Serialization/Deserialization etc // Those thrown by the server are already taken care of // and encoded in the retMsg .. so we don't come here for // that case. // We are in another appDomain, so we can't simply throw // the exception object across. The following marshals it // into a serialized return message. IMessage retMsg = new ReturnMessage(e, new ErrorMessage()); //*********************** SERIALIZE RET-MSG ****************** retBuff = CrossAppDomainSerializer.SerializeMessage(retMsg).GetBuffer(); retMsg = null; } finally { RemotingServices.LogRemotingStage(RemotingServices.SERVER_RET_SEND); Thread.CurrentThread.ReturnToContext(ref frame); Message.DebugOut("#### : changed back to Client Domain " + (Thread.CurrentContext.InternalContextID).ToString("X")); } // System.Diagnostics.Debugger.Break(); return retBuff; } // DoTransitionDispatch
/* package */ internal virtual void FinishAsyncWork(Object stateIgnored) { // set to the server context ContextTransitionFrame frame = new ContextTransitionFrame(); Context srvCtx = _srvID.ServerContext; Thread.CurrentThread.EnterContext(srvCtx, ref frame); LogicalCallContext threadPoolCallCtx = CallContext.SetLogicalCallContext(_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( _reqMsg, false, // bCliSide true, // bStart true, // bAsync true); // bNotifyGlobals IMessageCtrl ctrl = srvCtx.GetServerContextChain().AsyncProcessMessage( _reqMsg, (IMessageSink)this); // change back to the old context CallContext.SetLogicalCallContext(threadPoolCallCtx); Thread.CurrentThread.ReturnToContext(ref frame); }
public virtual IMessage SyncProcessMessage(IMessage reqMsg) { Message.DebugOut("+++++++++++++++++++++++++ CliCtxTerminator: SyncProcessMsg"); IMessage errMsg = ValidateMessage(reqMsg); if (errMsg != null) { return errMsg; } Context ctx = Thread.CurrentContext; bool bHasDynamicSinks = ctx.NotifyDynamicSinks(reqMsg, true, // bCliSide true, // bStart false, // bAsync true); // bNotifyGlobals IMessage replyMsg; if (reqMsg is IConstructionCallMessage) { errMsg = ctx.NotifyActivatorProperties( reqMsg, false /*bServerSide*/); if (errMsg != null) { return errMsg; } replyMsg = ((IConstructionCallMessage)reqMsg).Activator.Activate( (IConstructionCallMessage)reqMsg); BCLDebug.Assert(replyMsg is IConstructionReturnMessage,"bad ctorRetMsg"); errMsg = ctx.NotifyActivatorProperties( replyMsg, false /*bServerSide*/); if (errMsg != null) { return errMsg; } } else { ChannelServices.NotifyProfiler(reqMsg, RemotingProfilerEvent.ClientSend); // Forward call to the channel. IMessageSink channelSink = GetChannelSink(reqMsg); // Move to default context unless we are going through // the cross-context channel ContextTransitionFrame frame = new ContextTransitionFrame(); if (channelSink != CrossContextChannel.MessageSink) { Thread.CurrentThread.EnterContext( Context.DefaultContext, ref frame); } replyMsg = channelSink.SyncProcessMessage(reqMsg); if (channelSink != CrossContextChannel.MessageSink) { Thread.CurrentThread.ReturnToContext(ref frame); } ChannelServices.NotifyProfiler(replyMsg, RemotingProfilerEvent.ClientReceive); } if (bHasDynamicSinks) { ctx.NotifyDynamicSinks(reqMsg, true, // bCliSide false, // bStart false, // bAsync true); // bNotifyGlobals } return replyMsg; }
/* * Execute is called to complete a work item (sync or async). * Execute assumes that the context is set correctly and the lock * is taken (i.e. it makes no policy decisions) * * It is called from the following 3 points: * 1. thread pool thread executing the callback for an async item * 2. calling thread executing the callback for a queued sync item * 3. calling thread directly calling Execute for a non-queued sync item */ internal virtual void Execute() { // Execute should be called with the domain policy enforced // i.e. a Synchronization domain should be locked etc ... BCLDebug.Assert(IsSignaled(),"IsSignaled()"); ContextTransitionFrame frame = new ContextTransitionFrame(); Thread.CurrentThread.EnterContext(_ctx, ref frame); LogicalCallContext oldCallCtx = CallContext.SetLogicalCallContext(_callCtx); if (IsAsync()) { //DBGConsole.WriteLine(Thread.CurrentThread.GetHashCode()+"] AsyncWork.Execute"); _nextSink.AsyncProcessMessage(_reqMsg, _replySink); } else if (_nextSink != null) { //DBGConsole.WriteLine(Thread.CurrentThread.GetHashCode()+"] SyncWork.Execute"); _replyMsg = _nextSink.SyncProcessMessage(_reqMsg); } CallContext.SetLogicalCallContext(oldCallCtx); Thread.CurrentThread.ReturnToContext(ref frame); }
private static void InternalRemotelySetupRemoteDomain(IntPtr contextId, int domainId, String friendlyName, AppDomainSetup setup, IntPtr parentSecurityDescriptor, char[] serProvidedEvidence, char[] serCreatorEvidence, byte[] serializedEvidence) { bool bNeedToReset = false; ContextTransitionFrame frame = new ContextTransitionFrame(); try { // Set the current context to the given default Context // (of the new AppDomain). Thread.CurrentThread.EnterContextInternal(null, contextId, domainId, ref frame); bNeedToReset = true; InternalRemotelySetupRemoteDomainHelper(friendlyName, setup, parentSecurityDescriptor, serProvidedEvidence, serCreatorEvidence, serializedEvidence); // Set the current context to the old context Thread.CurrentThread.ReturnToContext(ref frame); bNeedToReset = false; } finally { // Restore the old app domain if (bNeedToReset) Thread.CurrentThread.ReturnToContext(ref frame); } } // InternalSetupRemoteDomain