Added information about the cross-app domain optimizations in the remoting doc.
authorLluis Sanchez <lluis@novell.com>
Wed, 10 Nov 2004 12:02:50 +0000 (12:02 -0000)
committerLluis Sanchez <lluis@novell.com>
Wed, 10 Nov 2004 12:02:50 +0000 (12:02 -0000)
svn path=/trunk/mono/; revision=35968

docs/remoting

index 806e40152868b6292b05cfc9c72f0210fef5e862..65f92323bfb191ebf5c53894c8a57aa100c4002b 100644 (file)
@@ -23,4 +23,231 @@ There are two helper methods which can be used by the JIT and the interpreter
 to convert LDFLD/STFLD operations into messages and then call
 RealProxy::Invoke(): mono_store_remote_field() and mono_load_remote_field().
 
+Cross app domain optimizations
+==============================
+
+The new implementation of the cross app domain channel makes a minimal use of
+the remoting infrastructure. The idea is to create remoting wrappers specific
+for cross app domain calls, which take the input paramers, switch the domain
+and dispatch the call in the new domain.
+
+When an vtable for a proxy needs to be created, the runtime checks if the proxy
+is referencing an object that belongs to another domain in the same process.
+In such case, the fast xdomain wrapper is returned instead of the regular one.
+
+The xdomain wrapper will have a different structure depending on the signature
+of the method it wraps, since different types have different marshalling needs.
+There are four types of marshalling, the first one is the fastest, the last one
+is the slowest:
+
+1) No marshalling at all: this is for primitive types.
+
+2) Internal copy of the object in the new domain: some system types can
+   be copied from one domain to the other by the runtime. This currently
+   applies to arrays of primitive types (or arrays of values that can be
+   internally copied), String and StringBuilder. We can add more types in
+   the future.
+   
+3) Internal copy for Out parameters. It is a specific case of the previous
+   type, when an input parameter has the [Out] attribute, which means that the
+   content of the object that is marshalled into the new domain, needs to be
+   copied over the instance of the original object. This applies to arrays
+   of primitive types and StringBuilder. This is used, for example, to be able
+   to call methods such as Stream.Read ([Out]buffer, pos, lengh) across domains.
+   
+4) Serialization. The value is serialized in one domain and deserialized in the
+   other one.
+   
+The xdomain wrapper will be generated according to the marshalling needs of
+each parameter.
+
+The cross domain wrapper is divided in two methods. The first method (the
+wrapper itself) takes the input parameters and serializes those that need to
+be serialized. After that, sets the new domain and calls to a second method
+in the new domain, which deserializes the parameters, makes a local copy of
+those that don't need serialization, and dispatches the call to the real
+object. Then, the inverse sequence is followed: return values are serialized,
+flow returns to the first method, which changes the domain again and
+deserializes the values.
+
+Sample wrapper
+--------------
+
+This are examples of cross domain wrappers in pseudo-C# code.
+The first example is for a method with the following signature:
+
+       ArrayList Test (int a, string b, ArrayList c, ref ArrayList d, ref string e, ref int f)
+
+Of course, the wrapper has the same signature:
+
+       ArrayList Test_xdomain_invoke (int a, string b, ArrayList c, ref ArrayList d, ref string e, ref int f)
+       {
+               int loc_new_domainid, loc_old_domainid;
+               ArrayList loc_return;
+               byte[] loc_serialized_array;
+               
+               // Save thread domain data
+               Context loc_context = Thread.CurrentContext;
+               if (loc_context.IsDefaultContext) {
+                       return Test_remoting_invoke (a, b, c, ref d, ref e, ref f);
+               }
+               object loc_datastore = Thread.ResetDataStoreStatus ();
+               
+               // Create the array that will hold the parameters to be serialized
+               object[] loc_array = new object [3];    // +1 to store the return value
+               loc_array [0] = c;
+               loc_array [1] = d;
+       
+               // Serialize parameters
+               loc_serialized_array = RemotingServices.SerializeCallData (loc_Array);
+       
+               // Get the target domain id and change the domain
+               RealProxy loc_real_proxy = ((TransparentProxy)this).rp;
+               loc_new_domainid = loc_real_proxy->target_domain_id;
+               
+               loc_old_domainid = mono_remoting_set_domain_by_id (loc_new_domainid);
+       
+               string e_copy = e;
+               /* The following is an indirect call made into the target domain */
+               Test_xdomain_dispatch (rp, ref loc_serialized_array, out loc_serialized_exc, a, b, ref e_copy, ref f);
+               
+               // Switch context
+               mono_remoting_set_domain_by_id (loc_old_domainid);
+               
+               // Restore thread domain data
+               mono_context_set (loc_context);
+               Thread.RestoreDataStoreStatus (loc_datastore);
+               
+               if (loc_serialized_exc != null) {
+                       Exception ex = (Exception) RemotingServices.DeserializeCallData (loc_serialized_exc);
+                       ex.FixRemotingException ();
+                       throw ex;
+               }
+               
+               // copy back non-serialized output parametars
+               e = mono_marshal_xdomain_copy_value (e_copy);
+               
+               // Deserialize out parameters
+               loc_serialized_array = mono_marshal_xdomain_copy_value (loc_serialized_array);
+               loc_array = RemotingServices.DeserializeObject (loc_serialized_array);
+               d = loc_array [1];
+               mono_thread_force_interruption_checkpoint ();
+               return loc_array [2];
+       }
+       
+       void Test_xdomain_dispatch (RealProxy rp, ref byte[] loc_call_data, out byte[] loc_exc_data, int a, string b, ref string e, ref int f)
+       {
+               // Deserialize parameters
+               try {
+                       // Clean the call context
+                       CallContext.SetCurrentCallContext (null);
+                       
+                       // Deserialize call data
+                       if (loc_call_data != null) {
+                               loc_call_data = mono_marshal_xdomain_copy_value (loc_call_data);
+                               loc_array = RemotingServices.DeserializeCallData (loc_call_data);
+                       }
+                       
+                       // Get the target object
+                       object target = rp.GetAppDomainTarget ();
+               
+                       // Load the arguments
+                       b = mono_marshal_xdomain_copy_value (b);
+               
+                       // Make the call to the real object
+                       mono_thread_force_interruption_checkpoint ();
+                       loc_return = target.Test (a, b, loc_array[0], ref loc_array[1], ref e, ref f);
+                       
+                       // Serialize the return values
+                       // Reset parameters in the array that don't need to be serialized back
+                       loc_array [0] = null;
+                       // Add the return value to the array
+                       loc_array [2] = loc_return;
+                       // Serialize
+                       loc_call_data = RemotingServices.SerializeCallData (loc_array);
+                       loc_exc_data = null;
+               }
+               catch (Exception ex) {
+                       loc_exc_data = RemotingServices.SerializeExceptionData (ex);
+               }
+       }
+
+
+Another example
+---------------
+
+This is another example of a method with more simple parameters:
+
+       int SimpleTest_xdomain_invoke (int a)
+       {
+               int loc_new_domainid, loc_old_domainid;
+               int loc_return;
+               byte[] loc_serialized_array;
+               
+               // Save thread domain data
+               Context loc_context = Thread.CurrentContext;
+               if (loc_context.IsDefaultContext) {
+                       return SimpleTest_remoting_invoke (a, b, c, ref d, ref e, ref f);
+               }
+               object loc_datastore = Thread.ResetDataStoreStatus ();
+               
+               // Serialize parameters. This will only serialize LogicalContext data if needed.
+               loc_serialized_array = RemotingServices.SerializeCallData (null);
+       
+               // Get the target domain id and change the domain
+               RealProxy loc_real_proxy = ((TransparentProxy)this).rp;
+               loc_new_domainid = loc_real_proxy->target_domain_id;
+               
+               loc_old_domainid = mono_remoting_set_domain_by_id (loc_new_domainid);
+       
+               /* The following is an indirect call made into the target domain */
+               loc_return = SimpleTest_xdomain_dispatch (rp, ref loc_serialized_array, out loc_serialized_exc, a);
+               
+               // Switch domain
+               mono_remoting_set_domain_by_id (loc_old_domainid);
+               
+               // Restore thread domain data
+               mono_context_set (loc_context);
+               Thread.RestoreDataStoreStatus (loc_datastore);
+               
+               if (loc_serialized_exc != null) {
+                       Exception ex = (Exception) RemotingServices.DeserializeCallData (loc_serialized_exc);
+                       ex.FixRemotingException ();
+                       throw ex;
+               }
+               
+               RemotingServices.DeserializeCallData (loc_serialized_array);
+               return loc_return [2];
+       }
+       
+
+       int SimpleTest_xdomain_dispatch (RealProxy rp, ref byte[] loc_call_data, out byte[] loc_exc_data, int a)
+       {
+               int loc_return;
+               
+               // Deserialize parameters
+               try {
+                       // Clean the call context
+                       CallContext.SetCurrentCallContext (null);
+                       
+                       // Deserialize call data
+                       if (loc_call_data != null) {
+                               loc_call_data = mono_marshal_xdomain_copy_value (loc_call_data);
+                               RemotingServices.DeserializeCallData (loc_call_data);
+                       }
+                       
+                       // Get the target object
+                       object target = rp.GetAppDomainTarget ();
+               
+                       // Make the call to the real object
+                       loc_return = target.Test (a);
+                       
+                       loc_call_data = RemotingServices.SerializeCallData (loc_Array);
+                       loc_exc_data = null;
+               }
+               catch (Exception ex) {
+                       loc_exc_data = RemotingServices.SerializeExceptionData (ex);
+               }
+               return loc_return;
+       }