You've already forked linux-packaging-mono
							
							
		
			
				
	
	
		
			254 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			254 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| Runtime support for Remoting
 | |
| ============================
 | |
| 
 | |
| The runtime supports a special objects called "TransparentProxy". You can
 | |
| create objects of this type by calling GetTransparentProxy() on a "RealProxy"
 | |
| object. 
 | |
| 
 | |
| LDFLD/STFLD for transparent proxies
 | |
| ===================================
 | |
| 
 | |
| Access to fields must be redirected to the remote object. System.Object has
 | |
| some special methods for that:
 | |
| 
 | |
| void FieldGetter (string typeName, string fieldName, ref object val);
 | |
| 		
 | |
| void FieldSetter (string typeName, string fieldName, object val);
 | |
| 
 | |
| This methods are never called on actual object. The are only used to pack
 | |
| LDFLD/STFLD operations into method call messages, which are then passed to the
 | |
| RealProxy::Invoke() method. 
 | |
| 
 | |
| 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;
 | |
| 	}
 | |
| 
 |