XEngine.cs 34 KB

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