AppDomainManager.cs 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSim Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. *
  27. */
  28. using System;
  29. using System.Collections;
  30. using System.Collections.Generic;
  31. using System.Reflection;
  32. using OpenSim.Grid.ScriptEngine.DotNetEngine.Compiler.LSL;
  33. namespace OpenSim.Grid.ScriptEngine.DotNetEngine
  34. {
  35. public class AppDomainManager
  36. {
  37. private int maxScriptsPerAppDomain = 1;
  38. /// <summary>
  39. /// Internal list of all AppDomains
  40. /// </summary>
  41. private List<AppDomainStructure> appDomains = new List<AppDomainStructure>();
  42. /// <summary>
  43. /// Structure to keep track of data around AppDomain
  44. /// </summary>
  45. private class AppDomainStructure
  46. {
  47. /// <summary>
  48. /// The AppDomain itself
  49. /// </summary>
  50. public AppDomain CurrentAppDomain;
  51. /// <summary>
  52. /// Number of scripts loaded into AppDomain
  53. /// </summary>
  54. public int ScriptsLoaded;
  55. /// <summary>
  56. /// Number of dead scripts
  57. /// </summary>
  58. public int ScriptsWaitingUnload;
  59. }
  60. /// <summary>
  61. /// Current AppDomain
  62. /// </summary>
  63. private AppDomainStructure currentAD;
  64. private object getLock = new object(); // Mutex
  65. private object freeLock = new object(); // Mutex
  66. //private ScriptEngine m_scriptEngine;
  67. //public AppDomainManager(ScriptEngine scriptEngine)
  68. public AppDomainManager()
  69. {
  70. //m_scriptEngine = scriptEngine;
  71. }
  72. /// <summary>
  73. /// Find a free AppDomain, creating one if necessary
  74. /// </summary>
  75. /// <returns>Free AppDomain</returns>
  76. private AppDomainStructure GetFreeAppDomain()
  77. {
  78. Console.WriteLine("Finding free AppDomain");
  79. lock (getLock)
  80. {
  81. // Current full?
  82. if (currentAD != null && currentAD.ScriptsLoaded >= maxScriptsPerAppDomain)
  83. {
  84. // Add it to AppDomains list and empty current
  85. appDomains.Add(currentAD);
  86. currentAD = null;
  87. }
  88. // No current
  89. if (currentAD == null)
  90. {
  91. // Create a new current AppDomain
  92. currentAD = new AppDomainStructure();
  93. currentAD.CurrentAppDomain = PrepareNewAppDomain();
  94. }
  95. Console.WriteLine("Scripts loaded in this Appdomain: " + currentAD.ScriptsLoaded);
  96. return currentAD;
  97. } // lock
  98. }
  99. private int AppDomainNameCount;
  100. /// <summary>
  101. /// Create and prepare a new AppDomain for scripts
  102. /// </summary>
  103. /// <returns>The new AppDomain</returns>
  104. private AppDomain PrepareNewAppDomain()
  105. {
  106. // Create and prepare a new AppDomain
  107. AppDomainNameCount++;
  108. // TODO: Currently security match current appdomain
  109. // Construct and initialize settings for a second AppDomain.
  110. AppDomainSetup ads = new AppDomainSetup();
  111. ads.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
  112. ads.DisallowBindingRedirects = false;
  113. ads.DisallowCodeDownload = true;
  114. ads.LoaderOptimization = LoaderOptimization.MultiDomain; // Sounds good ;)
  115. ads.ShadowCopyFiles = "true"; // Enabled shadowing
  116. ads.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
  117. AppDomain AD = AppDomain.CreateDomain("ScriptAppDomain_" + AppDomainNameCount, null, ads);
  118. Console.WriteLine("Loading: " +
  119. AssemblyName.GetAssemblyName("OpenSim.Region.ScriptEngine.Common.dll").ToString());
  120. AD.Load(AssemblyName.GetAssemblyName("OpenSim.Region.ScriptEngine.Common.dll"));
  121. // Return the new AppDomain
  122. return AD;
  123. }
  124. /// <summary>
  125. /// Unload appdomains that are full and have only dead scripts
  126. /// </summary>
  127. private void UnloadAppDomains()
  128. {
  129. lock (freeLock)
  130. {
  131. // Go through all
  132. foreach (AppDomainStructure ads in new ArrayList(appDomains))
  133. {
  134. // Don't process current AppDomain
  135. if (ads.CurrentAppDomain != currentAD.CurrentAppDomain)
  136. {
  137. // Not current AppDomain
  138. // Is number of unloaded bigger or equal to number of loaded?
  139. if (ads.ScriptsLoaded <= ads.ScriptsWaitingUnload)
  140. {
  141. Console.WriteLine("Found empty AppDomain, unloading");
  142. // Remove from internal list
  143. appDomains.Remove(ads);
  144. #if DEBUG
  145. long m = GC.GetTotalMemory(true);
  146. #endif
  147. // Unload
  148. AppDomain.Unload(ads.CurrentAppDomain);
  149. #if DEBUG
  150. Console.WriteLine("AppDomain unload freed " + (m - GC.GetTotalMemory(true)) +
  151. " bytes of memory");
  152. #endif
  153. }
  154. }
  155. } // foreach
  156. } // lock
  157. }
  158. public LSL_BaseClass LoadScript(string FileName)
  159. {
  160. // Find next available AppDomain to put it in
  161. AppDomainStructure FreeAppDomain = GetFreeAppDomain();
  162. Console.WriteLine("Loading into AppDomain: " + FileName);
  163. LSL_BaseClass mbrt =
  164. (LSL_BaseClass)
  165. FreeAppDomain.CurrentAppDomain.CreateInstanceFromAndUnwrap(FileName, "SecondLife.Script");
  166. //Console.WriteLine("ScriptEngine AppDomainManager: is proxy={0}", RemotingServices.IsTransparentProxy(mbrt));
  167. FreeAppDomain.ScriptsLoaded++;
  168. return mbrt;
  169. }
  170. /// <summary>
  171. /// Increase "dead script" counter for an AppDomain
  172. /// </summary>
  173. /// <param name="ad"></param>
  174. //[Obsolete("Needs fixing, needs a real purpose in life!!!")]
  175. public void StopScript(AppDomain ad)
  176. {
  177. lock (freeLock)
  178. {
  179. Console.WriteLine("Stopping script in AppDomain");
  180. // Check if it is current AppDomain
  181. if (currentAD.CurrentAppDomain == ad)
  182. {
  183. // Yes - increase
  184. currentAD.ScriptsWaitingUnload++;
  185. return;
  186. }
  187. // Lopp through all AppDomains
  188. foreach (AppDomainStructure ads in new ArrayList(appDomains))
  189. {
  190. if (ads.CurrentAppDomain == ad)
  191. {
  192. // Found it
  193. ads.ScriptsWaitingUnload++;
  194. break;
  195. }
  196. } // foreach
  197. } // lock
  198. UnloadAppDomains(); // Outsite lock, has its own GetLock
  199. }
  200. }
  201. }