XEngine.cs 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007
  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. using System;
  28. using System.IO;
  29. using System.Threading;
  30. using System.Collections;
  31. using System.Collections.Generic;
  32. using System.Security;
  33. using System.Security.Policy;
  34. using System.Reflection;
  35. using System.Globalization;
  36. using System.Xml;
  37. using OpenMetaverse;
  38. using OpenMetaverse.StructuredData;
  39. using log4net;
  40. using Nini.Config;
  41. using Amib.Threading;
  42. using OpenSim.Framework;
  43. using OpenSim.Region.Interfaces;
  44. using OpenSim.Region.Environment;
  45. using OpenSim.Region.Environment.Scenes;
  46. using OpenSim.Region.Environment.Interfaces;
  47. using OpenSim.Region.ScriptEngine.Shared;
  48. using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
  49. using OpenSim.Region.ScriptEngine.Shared.CodeTools;
  50. using OpenSim.Region.ScriptEngine.Shared.Instance;
  51. using OpenSim.Region.ScriptEngine.Interfaces;
  52. namespace OpenSim.Region.ScriptEngine.XEngine
  53. {
  54. public class XEngine : IRegionModule, IScriptModule, IScriptEngine
  55. {
  56. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  57. private SmartThreadPool m_ThreadPool;
  58. private int m_MaxScriptQueue;
  59. private Scene m_Scene;
  60. private IConfig m_ScriptConfig;
  61. private ICompiler m_Compiler;
  62. private int m_MinThreads;
  63. private int m_MaxThreads;
  64. private int m_IdleTimeout;
  65. private int m_StackSize;
  66. private int m_SleepTime;
  67. private int m_SaveTime;
  68. private ThreadPriority m_Prio;
  69. private bool m_Enabled = false;
  70. private bool m_InitialStartup = true;
  71. // disable warning: need to keep a reference to XEngine.EventManager
  72. // alive to avoid it being garbage collected
  73. #pragma warning disable 414
  74. private EventManager m_EventManager;
  75. #pragma warning restore 414
  76. private int m_EventLimit;
  77. private bool m_KillTimedOutScripts;
  78. private static List<XEngine> m_ScriptEngines =
  79. new List<XEngine>();
  80. // Maps the local id to the script inventory items in it
  81. private Dictionary<uint, List<UUID>> m_PrimObjects =
  82. new Dictionary<uint, List<UUID>>();
  83. // Maps the UUID above to the script instance
  84. private Dictionary<UUID, IScriptInstance> m_Scripts =
  85. new Dictionary<UUID, IScriptInstance>();
  86. // Maps the asset ID to the assembly
  87. private Dictionary<UUID, string> m_Assemblies =
  88. new Dictionary<UUID, string>();
  89. // This will list AppDomains by script asset
  90. private Dictionary<UUID, AppDomain> m_AppDomains =
  91. new Dictionary<UUID, AppDomain>();
  92. // List the scripts running in each appdomain
  93. private Dictionary<UUID, List<UUID>> m_DomainScripts =
  94. new Dictionary<UUID, List<UUID>>();
  95. private Queue m_CompileQueue = new Queue(100);
  96. IWorkItemResult m_CurrentCompile = null;
  97. public string ScriptEngineName
  98. {
  99. get { return "XEngine"; }
  100. }
  101. public Scene World
  102. {
  103. get { return m_Scene; }
  104. }
  105. public ILog Log
  106. {
  107. get { return m_log; }
  108. }
  109. public static List<XEngine> ScriptEngines
  110. {
  111. get { return m_ScriptEngines; }
  112. }
  113. // private struct RezScriptParms
  114. // {
  115. // uint LocalID;
  116. // UUID ItemID;
  117. // string Script;
  118. // }
  119. public IConfig Config
  120. {
  121. get { return m_ScriptConfig; }
  122. }
  123. //
  124. // IRegionModule functions
  125. //
  126. public void Initialise(Scene scene, IConfigSource configSource)
  127. {
  128. m_ScriptConfig = configSource.Configs["XEngine"];
  129. if (m_ScriptConfig == null)
  130. {
  131. // m_log.ErrorFormat("[XEngine] No script configuration found. Scripts disabled");
  132. return;
  133. }
  134. m_Enabled = m_ScriptConfig.GetBoolean("Enabled", true);
  135. if (!m_Enabled)
  136. return;
  137. AppDomain.CurrentDomain.AssemblyResolve +=
  138. OnAssemblyResolve;
  139. m_log.InfoFormat("[XEngine] Initializing scripts in region {0}",
  140. scene.RegionInfo.RegionName);
  141. m_Scene = scene;
  142. m_MinThreads = m_ScriptConfig.GetInt("MinThreads", 2);
  143. m_MaxThreads = m_ScriptConfig.GetInt("MaxThreads", 100);
  144. m_IdleTimeout = m_ScriptConfig.GetInt("IdleTimeout", 60);
  145. string priority = m_ScriptConfig.GetString("Priority", "BelowNormal");
  146. m_MaxScriptQueue = m_ScriptConfig.GetInt("MaxScriptEventQueue", 300);
  147. m_StackSize = m_ScriptConfig.GetInt("ThreadStackSize", 262144);
  148. m_SleepTime = m_ScriptConfig.GetInt("MaintenanceInterval", 10) * 1000;
  149. m_EventLimit = m_ScriptConfig.GetInt("EventLimit", 30);
  150. m_KillTimedOutScripts = m_ScriptConfig.GetBoolean("KillTimedOutScripts", false);
  151. m_SaveTime = m_ScriptConfig.GetInt("SaveInterval", 120) * 1000;
  152. m_Prio = ThreadPriority.BelowNormal;
  153. switch (priority)
  154. {
  155. case "Lowest":
  156. m_Prio = ThreadPriority.Lowest;
  157. break;
  158. case "BelowNormal":
  159. m_Prio = ThreadPriority.BelowNormal;
  160. break;
  161. case "Normal":
  162. m_Prio = ThreadPriority.Normal;
  163. break;
  164. case "AboveNormal":
  165. m_Prio = ThreadPriority.AboveNormal;
  166. break;
  167. case "Highest":
  168. m_Prio = ThreadPriority.Highest;
  169. break;
  170. default:
  171. m_log.ErrorFormat("[XEngine] Invalid thread priority: '{0}'. Assuming BelowNormal", priority);
  172. break;
  173. }
  174. lock (m_ScriptEngines)
  175. {
  176. m_ScriptEngines.Add(this);
  177. }
  178. // Needs to be here so we can queue the scripts that need starting
  179. //
  180. m_Scene.EventManager.OnRezScript += OnRezScript;
  181. // Complete basic setup of the thread pool
  182. //
  183. SetupEngine(m_MinThreads, m_MaxThreads, m_IdleTimeout, m_Prio,
  184. m_MaxScriptQueue, m_StackSize);
  185. m_Scene.StackModuleInterface<IScriptModule>(this);
  186. }
  187. public void PostInitialise()
  188. {
  189. if (!m_Enabled)
  190. return;
  191. m_EventManager = new EventManager(this);
  192. m_Compiler = new Compiler(this);
  193. m_Scene.EventManager.OnRemoveScript += OnRemoveScript;
  194. m_Scene.EventManager.OnScriptReset += OnScriptReset;
  195. m_Scene.EventManager.OnStartScript += OnStartScript;
  196. m_Scene.EventManager.OnStopScript += OnStopScript;
  197. m_Scene.EventManager.OnGetScriptRunning += OnGetScriptRunning;
  198. m_Scene.EventManager.OnShutdown += OnShutdown;
  199. if (m_SleepTime > 0)
  200. {
  201. m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoMaintenance),
  202. new Object[] { m_SleepTime });
  203. }
  204. if (m_SaveTime > 0)
  205. {
  206. m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoBackup),
  207. new Object[] { m_SaveTime });
  208. }
  209. m_ThreadPool.Start();
  210. }
  211. public void Close()
  212. {
  213. lock (m_ScriptEngines)
  214. {
  215. if (m_ScriptEngines.Contains(this))
  216. m_ScriptEngines.Remove(this);
  217. }
  218. }
  219. public object DoBackup(object o)
  220. {
  221. Object[] p = (Object[])o;
  222. int saveTime = (int)p[0];
  223. if (saveTime > 0)
  224. System.Threading.Thread.Sleep(saveTime);
  225. // m_log.Debug("[XEngine] Backing up script states");
  226. List<IScriptInstance> instances = new List<IScriptInstance>();
  227. lock (m_Scripts)
  228. {
  229. foreach (IScriptInstance instance in m_Scripts.Values)
  230. instances.Add(instance);
  231. }
  232. foreach (IScriptInstance i in instances)
  233. {
  234. string assembly = String.Empty;
  235. lock (m_Scripts)
  236. {
  237. if (!m_Assemblies.ContainsKey(i.AssetID))
  238. continue;
  239. assembly = m_Assemblies[i.AssetID];
  240. }
  241. i.SaveState(assembly);
  242. }
  243. instances.Clear();
  244. if (saveTime > 0)
  245. m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoBackup),
  246. new Object[] { saveTime });
  247. return 0;
  248. }
  249. public object DoMaintenance(object p)
  250. {
  251. object[] parms = (object[])p;
  252. int sleepTime = (int)parms[0];
  253. foreach (IScriptInstance inst in m_Scripts.Values)
  254. {
  255. if (inst.EventTime() > m_EventLimit)
  256. {
  257. inst.Stop(100);
  258. if (!m_KillTimedOutScripts)
  259. inst.Start();
  260. }
  261. }
  262. System.Threading.Thread.Sleep(sleepTime);
  263. m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoMaintenance),
  264. new Object[] { sleepTime });
  265. return 0;
  266. }
  267. public string Name
  268. {
  269. get { return "XEngine"; }
  270. }
  271. public bool IsSharedModule
  272. {
  273. get { return false; }
  274. }
  275. public void OnRezScript(uint localID, UUID itemID, string script, int startParam, bool postOnRez, string engine, int stateSource)
  276. {
  277. List<IScriptModule> engines = new List<IScriptModule>(m_Scene.RequestModuleInterfaces<IScriptModule>());
  278. List<string> names = new List<string>();
  279. foreach (IScriptModule m in engines)
  280. names.Add(m.ScriptEngineName);
  281. int lineEnd = script.IndexOf('\n');
  282. if (lineEnd > 1)
  283. {
  284. string firstline = script.Substring(0, lineEnd).Trim();
  285. int colon = firstline.IndexOf(':');
  286. if (firstline.Length > 2 && firstline.Substring(0, 2) == "//" && colon != -1)
  287. {
  288. string engineName = firstline.Substring(2, colon - 2);
  289. if (names.Contains(engineName))
  290. {
  291. engine = engineName;
  292. script = "//" + script.Substring(script.IndexOf(':') + 1);
  293. }
  294. else
  295. {
  296. if (engine == ScriptEngineName)
  297. {
  298. SceneObjectPart part =
  299. m_Scene.GetSceneObjectPart(
  300. localID);
  301. TaskInventoryItem item =
  302. part.Inventory.GetInventoryItem(itemID);
  303. ScenePresence presence =
  304. m_Scene.GetScenePresence(
  305. item.OwnerID);
  306. if (presence != null)
  307. {
  308. presence.ControllingClient.SendAgentAlertMessage(
  309. "Selected engine unavailable. " +
  310. "Running script on " +
  311. ScriptEngineName,
  312. false);
  313. }
  314. }
  315. }
  316. }
  317. }
  318. if (engine != ScriptEngineName)
  319. return;
  320. Object[] parms = new Object[] { localID, itemID, script, startParam, postOnRez, (StateSource)stateSource };
  321. if (stateSource == (int)StateSource.ScriptedRez)
  322. {
  323. DoOnRezScript(parms);
  324. }
  325. else
  326. {
  327. lock (m_CompileQueue)
  328. {
  329. m_CompileQueue.Enqueue(parms);
  330. if (m_CurrentCompile == null)
  331. {
  332. m_CurrentCompile = m_ThreadPool.QueueWorkItem(
  333. new WorkItemCallback(this.DoOnRezScriptQueue),
  334. new Object[0]);
  335. }
  336. }
  337. }
  338. }
  339. public Object DoOnRezScriptQueue(Object dummy)
  340. {
  341. if (m_InitialStartup)
  342. {
  343. m_InitialStartup = false;
  344. System.Threading.Thread.Sleep(15000);
  345. }
  346. Object o;
  347. lock (m_CompileQueue)
  348. {
  349. o = m_CompileQueue.Dequeue();
  350. if (o == null)
  351. {
  352. m_CurrentCompile = null;
  353. return null;
  354. }
  355. }
  356. DoOnRezScript(o);
  357. lock (m_CompileQueue)
  358. {
  359. if (m_CompileQueue.Count > 0)
  360. {
  361. m_CurrentCompile = m_ThreadPool.QueueWorkItem(
  362. new WorkItemCallback(this.DoOnRezScriptQueue),
  363. new Object[0]);
  364. }
  365. else
  366. {
  367. m_CurrentCompile = null;
  368. }
  369. }
  370. return null;
  371. }
  372. private bool DoOnRezScript(object parm)
  373. {
  374. Object[] p = (Object[])parm;
  375. uint localID = (uint)p[0];
  376. UUID itemID = (UUID)p[1];
  377. string script = (string)p[2];
  378. int startParam = (int)p[3];
  379. bool postOnRez = (bool)p[4];
  380. StateSource stateSource = (StateSource)p[5];
  381. // Get the asset ID of the script, so we can check if we
  382. // already have it.
  383. // We must look for the part outside the m_Scripts lock because GetSceneObjectPart later triggers the
  384. // m_parts lock on SOG. At the same time, a scene object that is being deleted will take the m_parts lock
  385. // and then later on try to take the m_scripts lock in this class when it calls OnRemoveScript()
  386. SceneObjectPart part = m_Scene.GetSceneObjectPart(localID);
  387. if (part == null)
  388. {
  389. Log.Error("[Script] SceneObjectPart unavailable. Script NOT started.");
  390. return false;
  391. }
  392. TaskInventoryItem item = part.Inventory.GetInventoryItem(itemID);
  393. if (item == null)
  394. return false;
  395. UUID assetID = item.AssetID;
  396. // m_log.DebugFormat("[XEngine] Compiling script {0} ({1})",
  397. // item.Name, itemID.ToString());
  398. ScenePresence presence = m_Scene.GetScenePresence(item.OwnerID);
  399. string assembly = "";
  400. CultureInfo USCulture = new CultureInfo("en-US");
  401. Thread.CurrentThread.CurrentCulture = USCulture;
  402. try
  403. {
  404. assembly = m_Compiler.PerformScriptCompile(script,
  405. assetID.ToString());
  406. }
  407. catch (Exception e)
  408. {
  409. if (presence != null && (!postOnRez))
  410. presence.ControllingClient.SendAgentAlertMessage("Script saved with errors, check debug window!", false);
  411. try
  412. {
  413. // DISPLAY ERROR INWORLD
  414. string text = "Error compiling script:\n" + e.Message.ToString();
  415. if (text.Length > 1000)
  416. text = text.Substring(0, 1000);
  417. World.SimChat(Utils.StringToBytes(text),
  418. ChatTypeEnum.DebugChannel, 2147483647,
  419. part.AbsolutePosition,
  420. part.Name, part.UUID, false);
  421. }
  422. catch (Exception e2) // LEGIT: User Scripting
  423. {
  424. m_log.Error("[XEngine]: " +
  425. "Error displaying error in-world: " +
  426. e2.ToString());
  427. m_log.Error("[XEngine]: " +
  428. "Errormessage: Error compiling script:\r\n" +
  429. e.Message.ToString());
  430. }
  431. return false;
  432. }
  433. lock (m_Scripts)
  434. {
  435. // Create the object record
  436. if ((!m_Scripts.ContainsKey(itemID)) ||
  437. (m_Scripts[itemID].AssetID != assetID))
  438. {
  439. UUID appDomain = assetID;
  440. if (part.ParentGroup.IsAttachment)
  441. appDomain = part.ParentGroup.RootPart.UUID;
  442. if (!m_AppDomains.ContainsKey(appDomain))
  443. {
  444. try
  445. {
  446. AppDomainSetup appSetup = new AppDomainSetup();
  447. // appSetup.ApplicationBase = Path.Combine(
  448. // "ScriptEngines",
  449. // m_Scene.RegionInfo.RegionID.ToString());
  450. Evidence baseEvidence = AppDomain.CurrentDomain.Evidence;
  451. Evidence evidence = new Evidence(baseEvidence);
  452. m_AppDomains[appDomain] =
  453. AppDomain.CreateDomain(
  454. m_Scene.RegionInfo.RegionID.ToString(),
  455. evidence, appSetup);
  456. m_AppDomains[appDomain].AssemblyResolve +=
  457. new ResolveEventHandler(
  458. AssemblyResolver.OnAssemblyResolve);
  459. m_DomainScripts[appDomain] = new List<UUID>();
  460. }
  461. catch (Exception e)
  462. {
  463. m_log.ErrorFormat("[XEngine] Exception creating app domain:\n {0}", e.ToString());
  464. return false;
  465. }
  466. }
  467. m_DomainScripts[appDomain].Add(itemID);
  468. ScriptInstance instance =
  469. new ScriptInstance(this, part,
  470. itemID, assetID, assembly,
  471. m_AppDomains[appDomain],
  472. part.ParentGroup.RootPart.Name,
  473. item.Name, startParam, postOnRez,
  474. stateSource, m_MaxScriptQueue);
  475. m_log.DebugFormat("[XEngine] Loaded script {0}.{1}",
  476. part.ParentGroup.RootPart.Name, item.Name);
  477. instance.AppDomain = appDomain;
  478. instance.LineMap = m_Compiler.LineMap();
  479. m_Scripts[itemID] = instance;
  480. }
  481. lock (m_PrimObjects)
  482. {
  483. if (!m_PrimObjects.ContainsKey(localID))
  484. m_PrimObjects[localID] = new List<UUID>();
  485. if (!m_PrimObjects[localID].Contains(itemID))
  486. m_PrimObjects[localID].Add(itemID);
  487. }
  488. if (!m_Assemblies.ContainsKey(assetID))
  489. m_Assemblies[assetID] = assembly;
  490. }
  491. return true;
  492. }
  493. public void OnRemoveScript(uint localID, UUID itemID)
  494. {
  495. lock (m_Scripts)
  496. {
  497. // Do we even have it?
  498. if (!m_Scripts.ContainsKey(itemID))
  499. return;
  500. IScriptInstance instance = m_Scripts[itemID];
  501. m_Scripts.Remove(itemID);
  502. instance.ClearQueue();
  503. instance.Stop(0);
  504. SceneObjectPart part =
  505. m_Scene.GetSceneObjectPart(localID);
  506. if (part != null)
  507. part.RemoveScriptEvents(itemID);
  508. lock (m_PrimObjects)
  509. {
  510. // Remove the script from it's prim
  511. if (m_PrimObjects.ContainsKey(localID))
  512. {
  513. // Remove inventory item record
  514. if (m_PrimObjects[localID].Contains(itemID))
  515. m_PrimObjects[localID].Remove(itemID);
  516. // If there are no more scripts, remove prim
  517. if (m_PrimObjects[localID].Count == 0)
  518. {
  519. m_PrimObjects.Remove(localID);
  520. }
  521. }
  522. }
  523. m_DomainScripts[instance.AppDomain].Remove(instance.ItemID);
  524. if (m_DomainScripts[instance.AppDomain].Count == 0)
  525. {
  526. m_DomainScripts.Remove(instance.AppDomain);
  527. UnloadAppDomain(instance.AppDomain);
  528. }
  529. instance.RemoveState();
  530. instance.DestroyScriptInstance();
  531. instance = null;
  532. CleanAssemblies();
  533. }
  534. }
  535. public void OnScriptReset(uint localID, UUID itemID)
  536. {
  537. ResetScript(itemID);
  538. }
  539. public void OnStartScript(uint localID, UUID itemID)
  540. {
  541. StartScript(itemID);
  542. }
  543. public void OnStopScript(uint localID, UUID itemID)
  544. {
  545. StopScript(itemID);
  546. }
  547. private void CleanAssemblies()
  548. {
  549. List<UUID> assetIDList = new List<UUID>(m_Assemblies.Keys);
  550. foreach (IScriptInstance i in m_Scripts.Values)
  551. {
  552. if (assetIDList.Contains(i.AssetID))
  553. assetIDList.Remove(i.AssetID);
  554. }
  555. foreach (UUID assetID in assetIDList)
  556. {
  557. // m_log.DebugFormat("[XEngine] Removing unreferenced assembly {0}", m_Assemblies[assetID]);
  558. try
  559. {
  560. if (File.Exists(m_Assemblies[assetID]))
  561. File.Delete(m_Assemblies[assetID]);
  562. if (File.Exists(m_Assemblies[assetID] + ".state"))
  563. File.Delete(m_Assemblies[assetID] + ".state");
  564. if (File.Exists(m_Assemblies[assetID] + ".mdb"))
  565. File.Delete(m_Assemblies[assetID] + ".mdb");
  566. }
  567. catch (Exception)
  568. {
  569. }
  570. m_Assemblies.Remove(assetID);
  571. }
  572. }
  573. private void UnloadAppDomain(UUID id)
  574. {
  575. if (m_AppDomains.ContainsKey(id))
  576. {
  577. AppDomain domain = m_AppDomains[id];
  578. m_AppDomains.Remove(id);
  579. AppDomain.Unload(domain);
  580. domain = null;
  581. // m_log.DebugFormat("[XEngine] Unloaded app domain {0}", id.ToString());
  582. }
  583. }
  584. //
  585. // Start processing
  586. //
  587. private void SetupEngine(int minThreads, int maxThreads,
  588. int idleTimeout, ThreadPriority threadPriority,
  589. int maxScriptQueue, int stackSize)
  590. {
  591. m_MaxScriptQueue = maxScriptQueue;
  592. STPStartInfo startInfo = new STPStartInfo();
  593. startInfo.IdleTimeout = idleTimeout;
  594. startInfo.MaxWorkerThreads = maxThreads;
  595. startInfo.MinWorkerThreads = minThreads;
  596. startInfo.ThreadPriority = threadPriority;
  597. startInfo.StackSize = stackSize;
  598. startInfo.StartSuspended = true;
  599. m_ThreadPool = new SmartThreadPool(startInfo);
  600. }
  601. //
  602. // Used by script instances to queue event handler jobs
  603. //
  604. public IScriptWorkItem QueueEventHandler(object parms)
  605. {
  606. return new XWorkItem(m_ThreadPool.QueueWorkItem(
  607. new WorkItemCallback(this.ProcessEventHandler),
  608. parms));
  609. }
  610. /// <summary>
  611. /// Process a previously posted script event.
  612. /// </summary>
  613. /// <param name="parms"></param>
  614. /// <returns></returns>
  615. private object ProcessEventHandler(object parms)
  616. {
  617. CultureInfo USCulture = new CultureInfo("en-US");
  618. Thread.CurrentThread.CurrentCulture = USCulture;
  619. IScriptInstance instance = (ScriptInstance)parms;
  620. //m_log.DebugFormat("[XENGINE]: Processing event for {0}", instance);
  621. return instance.EventProcessor();
  622. }
  623. /// <summary>
  624. /// Post event to an entire prim
  625. /// </summary>
  626. /// <param name="localID"></param>
  627. /// <param name="p"></param>
  628. /// <returns></returns>
  629. public bool PostObjectEvent(uint localID, EventParams p)
  630. {
  631. bool result = false;
  632. lock (m_PrimObjects)
  633. {
  634. if (!m_PrimObjects.ContainsKey(localID))
  635. return false;
  636. foreach (UUID itemID in m_PrimObjects[localID])
  637. {
  638. if (m_Scripts.ContainsKey(itemID))
  639. {
  640. IScriptInstance instance = m_Scripts[itemID];
  641. if (instance != null)
  642. {
  643. instance.PostEvent(p);
  644. result = true;
  645. }
  646. }
  647. }
  648. }
  649. return result;
  650. }
  651. /// <summary>
  652. /// Post an event to a single script
  653. /// </summary>
  654. /// <param name="itemID"></param>
  655. /// <param name="p"></param>
  656. /// <returns></returns>
  657. public bool PostScriptEvent(UUID itemID, EventParams p)
  658. {
  659. if (m_Scripts.ContainsKey(itemID))
  660. {
  661. IScriptInstance instance = m_Scripts[itemID];
  662. if (instance != null)
  663. instance.PostEvent(p);
  664. return true;
  665. }
  666. return false;
  667. }
  668. public Assembly OnAssemblyResolve(object sender,
  669. ResolveEventArgs args)
  670. {
  671. if (!(sender is System.AppDomain))
  672. return null;
  673. string[] pathList = new string[] {"bin", "ScriptEngines",
  674. Path.Combine("ScriptEngines",
  675. m_Scene.RegionInfo.RegionID.ToString())};
  676. string assemblyName = args.Name;
  677. if (assemblyName.IndexOf(",") != -1)
  678. assemblyName = args.Name.Substring(0, args.Name.IndexOf(","));
  679. foreach (string s in pathList)
  680. {
  681. string path = Path.Combine(Directory.GetCurrentDirectory(),
  682. Path.Combine(s, assemblyName)) + ".dll";
  683. if (File.Exists(path))
  684. return Assembly.LoadFrom(path);
  685. }
  686. return null;
  687. }
  688. private IScriptInstance GetInstance(UUID itemID)
  689. {
  690. IScriptInstance instance;
  691. lock (m_Scripts)
  692. {
  693. if (!m_Scripts.ContainsKey(itemID))
  694. return null;
  695. instance = m_Scripts[itemID];
  696. }
  697. return instance;
  698. }
  699. public void SetScriptState(UUID itemID, bool running)
  700. {
  701. IScriptInstance instance = GetInstance(itemID);
  702. if (instance != null)
  703. {
  704. if (running)
  705. instance.Start();
  706. else
  707. instance.Stop(100);
  708. }
  709. }
  710. public bool GetScriptState(UUID itemID)
  711. {
  712. IScriptInstance instance = GetInstance(itemID);
  713. if (instance != null)
  714. return instance.Running;
  715. return false;
  716. }
  717. public void ApiResetScript(UUID itemID)
  718. {
  719. IScriptInstance instance = GetInstance(itemID);
  720. if (instance != null)
  721. instance.ApiResetScript();
  722. }
  723. public void ResetScript(UUID itemID)
  724. {
  725. IScriptInstance instance = GetInstance(itemID);
  726. if (instance != null)
  727. instance.ResetScript();
  728. }
  729. public void StartScript(UUID itemID)
  730. {
  731. IScriptInstance instance = GetInstance(itemID);
  732. if (instance != null)
  733. instance.Start();
  734. }
  735. public void StopScript(UUID itemID)
  736. {
  737. IScriptInstance instance = GetInstance(itemID);
  738. if (instance != null)
  739. instance.Stop(0);
  740. }
  741. public DetectParams GetDetectParams(UUID itemID, int idx)
  742. {
  743. IScriptInstance instance = GetInstance(itemID);
  744. if (instance != null)
  745. return instance.GetDetectParams(idx);
  746. return null;
  747. }
  748. public void SetMinEventDelay(UUID itemID, double delay)
  749. {
  750. IScriptInstance instance = GetInstance(itemID);
  751. if (instance != null)
  752. instance.MinEventDelay = delay;
  753. }
  754. public UUID GetDetectID(UUID itemID, int idx)
  755. {
  756. IScriptInstance instance = GetInstance(itemID);
  757. if (instance != null)
  758. return instance.GetDetectID(idx);
  759. return UUID.Zero;
  760. }
  761. public void SetState(UUID itemID, string newState)
  762. {
  763. IScriptInstance instance = GetInstance(itemID);
  764. if (instance == null)
  765. return;
  766. instance.SetState(newState);
  767. }
  768. public string GetState(UUID itemID)
  769. {
  770. IScriptInstance instance = GetInstance(itemID);
  771. if (instance == null)
  772. return "default";
  773. return instance.State;
  774. }
  775. public int GetStartParameter(UUID itemID)
  776. {
  777. IScriptInstance instance = GetInstance(itemID);
  778. if (instance == null)
  779. return 0;
  780. return instance.StartParam;
  781. }
  782. public void OnShutdown()
  783. {
  784. List<IScriptInstance> instances = new List<IScriptInstance>();
  785. lock (m_Scripts)
  786. {
  787. foreach (IScriptInstance instance in m_Scripts.Values)
  788. instances.Add(instance);
  789. }
  790. foreach (IScriptInstance i in instances)
  791. {
  792. // Stop the script, even forcibly if needed. Then flag
  793. // it as shutting down and restore the previous run state
  794. // for serialization, so the scripts don't come back
  795. // dead after region restart
  796. //
  797. bool prevRunning = i.Running;
  798. i.Stop(50);
  799. i.ShuttingDown = true;
  800. i.Running = prevRunning;
  801. }
  802. DoBackup(new Object[] { 0 });
  803. }
  804. public IScriptApi GetApi(UUID itemID, string name)
  805. {
  806. IScriptInstance instance = GetInstance(itemID);
  807. if (instance == null)
  808. return null;
  809. return instance.GetApi(name);
  810. }
  811. public void OnGetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID)
  812. {
  813. IScriptInstance instance = GetInstance(itemID);
  814. if (instance == null)
  815. return;
  816. IEventQueue eq = World.RequestModuleInterface<IEventQueue>();
  817. if (eq == null)
  818. {
  819. controllingClient.SendScriptRunningReply(objectID, itemID,
  820. GetScriptState(itemID));
  821. }
  822. else
  823. {
  824. eq.Enqueue(EventQueueHelper.ScriptRunningReplyEvent(objectID, itemID, GetScriptState(itemID), true),
  825. controllingClient.AgentId);
  826. }
  827. }
  828. public string GetAssemblyName(UUID itemID)
  829. {
  830. IScriptInstance instance = GetInstance(itemID);
  831. if (instance == null)
  832. return "";
  833. return instance.GetAssemblyName();
  834. }
  835. public string GetXMLState(UUID itemID)
  836. {
  837. IScriptInstance instance = GetInstance(itemID);
  838. if (instance == null)
  839. return "";
  840. return instance.GetXMLState();
  841. }
  842. }
  843. }