X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=docs%2Fremoting;h=65f92323bfb191ebf5c53894c8a57aa100c4002b;hb=83569e1ef07325ec30b00d3e2b955718f210e608;hp=806e40152868b6292b05cfc9c72f0210fef5e862;hpb=b7c17c47e6b3c02192e64175cb5ee0ce7f7dda1b;p=mono.git diff --git a/docs/remoting b/docs/remoting index 806e4015286..65f92323bfb 100644 --- a/docs/remoting +++ b/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; + }