Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added information about the cross-app domain optimizations in the rem…

…oting doc.

svn path=/trunk/mono/; revision=35968
  • Loading branch information...
commit d3b7ce10a8ebde22097bfc1ec0c96b9289d5b2fa 1 parent 596ebfe
@slluis slluis authored
Showing with 227 additions and 0 deletions.
  1. +227 −0 docs/remoting
View
227 docs/remoting
@@ -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;
+ }
Please sign in to comment.
Something went wrong with that request. Please try again.