remoting 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. Runtime support for Remoting
  2. ============================
  3. The runtime supports a special objects called "TransparentProxy". You can
  4. create objects of this type by calling GetTransparentProxy() on a "RealProxy"
  5. object.
  6. LDFLD/STFLD for transparent proxies
  7. ===================================
  8. Access to fields must be redirected to the remote object. System.Object has
  9. some special methods for that:
  10. void FieldGetter (string typeName, string fieldName, ref object val);
  11. void FieldSetter (string typeName, string fieldName, object val);
  12. This methods are never called on actual object. The are only used to pack
  13. LDFLD/STFLD operations into method call messages, which are then passed to the
  14. RealProxy::Invoke() method.
  15. There are two helper methods which can be used by the JIT and the interpreter
  16. to convert LDFLD/STFLD operations into messages and then call
  17. RealProxy::Invoke(): mono_store_remote_field() and mono_load_remote_field().
  18. Cross app domain optimizations
  19. ==============================
  20. The new implementation of the cross app domain channel makes a minimal use of
  21. the remoting infrastructure. The idea is to create remoting wrappers specific
  22. for cross app domain calls, which take the input paramers, switch the domain
  23. and dispatch the call in the new domain.
  24. When an vtable for a proxy needs to be created, the runtime checks if the proxy
  25. is referencing an object that belongs to another domain in the same process.
  26. In such case, the fast xdomain wrapper is returned instead of the regular one.
  27. The xdomain wrapper will have a different structure depending on the signature
  28. of the method it wraps, since different types have different marshalling needs.
  29. There are four types of marshalling, the first one is the fastest, the last one
  30. is the slowest:
  31. 1) No marshalling at all: this is for primitive types.
  32. 2) Internal copy of the object in the new domain: some system types can
  33. be copied from one domain to the other by the runtime. This currently
  34. applies to arrays of primitive types (or arrays of values that can be
  35. internally copied), String and StringBuilder. We can add more types in
  36. the future.
  37. 3) Internal copy for Out parameters. It is a specific case of the previous
  38. type, when an input parameter has the [Out] attribute, which means that the
  39. content of the object that is marshalled into the new domain, needs to be
  40. copied over the instance of the original object. This applies to arrays
  41. of primitive types and StringBuilder. This is used, for example, to be able
  42. to call methods such as Stream.Read ([Out]buffer, pos, lengh) across domains.
  43. 4) Serialization. The value is serialized in one domain and deserialized in the
  44. other one.
  45. The xdomain wrapper will be generated according to the marshalling needs of
  46. each parameter.
  47. The cross domain wrapper is divided in two methods. The first method (the
  48. wrapper itself) takes the input parameters and serializes those that need to
  49. be serialized. After that, sets the new domain and calls to a second method
  50. in the new domain, which deserializes the parameters, makes a local copy of
  51. those that don't need serialization, and dispatches the call to the real
  52. object. Then, the inverse sequence is followed: return values are serialized,
  53. flow returns to the first method, which changes the domain again and
  54. deserializes the values.
  55. Sample wrapper
  56. --------------
  57. This are examples of cross domain wrappers in pseudo-C# code.
  58. The first example is for a method with the following signature:
  59. ArrayList Test (int a, string b, ArrayList c, ref ArrayList d, ref string e, ref int f)
  60. Of course, the wrapper has the same signature:
  61. ArrayList Test_xdomain_invoke (int a, string b, ArrayList c, ref ArrayList d, ref string e, ref int f)
  62. {
  63. int loc_new_domainid, loc_old_domainid;
  64. ArrayList loc_return;
  65. byte[] loc_serialized_array;
  66. // Save thread domain data
  67. Context loc_context = Thread.CurrentContext;
  68. if (loc_context.IsDefaultContext) {
  69. return Test_remoting_invoke (a, b, c, ref d, ref e, ref f);
  70. }
  71. object loc_datastore = Thread.ResetDataStoreStatus ();
  72. // Create the array that will hold the parameters to be serialized
  73. object[] loc_array = new object [3]; // +1 to store the return value
  74. loc_array [0] = c;
  75. loc_array [1] = d;
  76. // Serialize parameters
  77. loc_serialized_array = RemotingServices.SerializeCallData (loc_Array);
  78. // Get the target domain id and change the domain
  79. RealProxy loc_real_proxy = ((TransparentProxy)this).rp;
  80. loc_new_domainid = loc_real_proxy->target_domain_id;
  81. loc_old_domainid = mono_remoting_set_domain_by_id (loc_new_domainid);
  82. string e_copy = e;
  83. /* The following is an indirect call made into the target domain */
  84. Test_xdomain_dispatch (rp, ref loc_serialized_array, out loc_serialized_exc, a, b, ref e_copy, ref f);
  85. // Switch context
  86. mono_remoting_set_domain_by_id (loc_old_domainid);
  87. // Restore thread domain data
  88. mono_context_set (loc_context);
  89. Thread.RestoreDataStoreStatus (loc_datastore);
  90. if (loc_serialized_exc != null) {
  91. Exception ex = (Exception) RemotingServices.DeserializeCallData (loc_serialized_exc);
  92. ex.FixRemotingException ();
  93. throw ex;
  94. }
  95. // copy back non-serialized output parametars
  96. e = mono_marshal_xdomain_copy_value (e_copy);
  97. // Deserialize out parameters
  98. loc_serialized_array = mono_marshal_xdomain_copy_value (loc_serialized_array);
  99. loc_array = RemotingServices.DeserializeObject (loc_serialized_array);
  100. d = loc_array [1];
  101. mono_thread_force_interruption_checkpoint ();
  102. return loc_array [2];
  103. }
  104. 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)
  105. {
  106. // Deserialize parameters
  107. try {
  108. // Clean the call context
  109. CallContext.SetCurrentCallContext (null);
  110. // Deserialize call data
  111. if (loc_call_data != null) {
  112. loc_call_data = mono_marshal_xdomain_copy_value (loc_call_data);
  113. loc_array = RemotingServices.DeserializeCallData (loc_call_data);
  114. }
  115. // Get the target object
  116. object target = rp.GetAppDomainTarget ();
  117. // Load the arguments
  118. b = mono_marshal_xdomain_copy_value (b);
  119. // Make the call to the real object
  120. mono_thread_force_interruption_checkpoint ();
  121. loc_return = target.Test (a, b, loc_array[0], ref loc_array[1], ref e, ref f);
  122. // Serialize the return values
  123. // Reset parameters in the array that don't need to be serialized back
  124. loc_array [0] = null;
  125. // Add the return value to the array
  126. loc_array [2] = loc_return;
  127. // Serialize
  128. loc_call_data = RemotingServices.SerializeCallData (loc_array);
  129. loc_exc_data = null;
  130. }
  131. catch (Exception ex) {
  132. loc_exc_data = RemotingServices.SerializeExceptionData (ex);
  133. }
  134. }
  135. Another example
  136. ---------------
  137. This is another example of a method with more simple parameters:
  138. int SimpleTest_xdomain_invoke (int a)
  139. {
  140. int loc_new_domainid, loc_old_domainid;
  141. int loc_return;
  142. byte[] loc_serialized_array;
  143. // Save thread domain data
  144. Context loc_context = Thread.CurrentContext;
  145. if (loc_context.IsDefaultContext) {
  146. return SimpleTest_remoting_invoke (a, b, c, ref d, ref e, ref f);
  147. }
  148. object loc_datastore = Thread.ResetDataStoreStatus ();
  149. // Serialize parameters. This will only serialize LogicalContext data if needed.
  150. loc_serialized_array = RemotingServices.SerializeCallData (null);
  151. // Get the target domain id and change the domain
  152. RealProxy loc_real_proxy = ((TransparentProxy)this).rp;
  153. loc_new_domainid = loc_real_proxy->target_domain_id;
  154. loc_old_domainid = mono_remoting_set_domain_by_id (loc_new_domainid);
  155. /* The following is an indirect call made into the target domain */
  156. loc_return = SimpleTest_xdomain_dispatch (rp, ref loc_serialized_array, out loc_serialized_exc, a);
  157. // Switch domain
  158. mono_remoting_set_domain_by_id (loc_old_domainid);
  159. // Restore thread domain data
  160. mono_context_set (loc_context);
  161. Thread.RestoreDataStoreStatus (loc_datastore);
  162. if (loc_serialized_exc != null) {
  163. Exception ex = (Exception) RemotingServices.DeserializeCallData (loc_serialized_exc);
  164. ex.FixRemotingException ();
  165. throw ex;
  166. }
  167. RemotingServices.DeserializeCallData (loc_serialized_array);
  168. return loc_return [2];
  169. }
  170. int SimpleTest_xdomain_dispatch (RealProxy rp, ref byte[] loc_call_data, out byte[] loc_exc_data, int a)
  171. {
  172. int loc_return;
  173. // Deserialize parameters
  174. try {
  175. // Clean the call context
  176. CallContext.SetCurrentCallContext (null);
  177. // Deserialize call data
  178. if (loc_call_data != null) {
  179. loc_call_data = mono_marshal_xdomain_copy_value (loc_call_data);
  180. RemotingServices.DeserializeCallData (loc_call_data);
  181. }
  182. // Get the target object
  183. object target = rp.GetAppDomainTarget ();
  184. // Make the call to the real object
  185. loc_return = target.Test (a);
  186. loc_call_data = RemotingServices.SerializeCallData (loc_Array);
  187. loc_exc_data = null;
  188. }
  189. catch (Exception ex) {
  190. loc_exc_data = RemotingServices.SerializeExceptionData (ex);
  191. }
  192. return loc_return;
  193. }